Merge "Fix launch animation from bottom row and end of grid" into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index aa31261..1c0c773 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,18 +15,10 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
-import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
-import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
-import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.annotation.ColorInt;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -44,28 +36,17 @@
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.RecentsAnimationCallbacks;
-import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
-import com.android.quickstep.RecentsAnimationController;
-import com.android.quickstep.views.RecentsView;
-import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.Set;
-import java.util.function.Supplier;
import java.util.stream.Stream;
/**
@@ -77,82 +58,15 @@
private final BaseQuickstepLauncher mLauncher;
- private final AnimatedFloat mIconAlignmentForResumedState =
- new AnimatedFloat(this::onIconAlignmentRatioChanged);
- private final AnimatedFloat mIconAlignmentForGestureState =
- new AnimatedFloat(this::onIconAlignmentRatioChanged);
- private final AnimatedFloat mIconAlignmentForLauncherState =
- new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
-
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
this::onStashedInAppChanged;
- private final StateManager.StateListener<LauncherState> mStateListener =
- new StateManager.StateListener<LauncherState>() {
- private Animator mAnimator;
-
- @Override
- public void onStateTransitionStart(LauncherState toState) {
- // Stash animation from going to launcher should be already handled in
- // createAnimToLauncher.
- TaskbarStashController controller = mControllers.taskbarStashController;
- long duration = TASKBAR_STASH_DURATION;
- controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- toState.isTaskbarStashed());
- Animator stashAnimator = controller.applyStateWithoutStart(duration);
- if (stashAnimator != null) {
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- PendingAnimation pendingAnimation = new PendingAnimation(duration);
- pendingAnimation.add(stashAnimator);
- pendingAnimation.setFloat(mIconAlignmentForLauncherState,
- AnimatedFloat.VALUE, toState.isTaskbarStashed() ? 0 : 1,
- FAST_OUT_SLOW_IN);
- pendingAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverrideForStateTransition = toState;
- // Copy hotseat alpha over to taskbar icons
- mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
- mLauncher.getHotseat().setIconsAlpha(0);
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- if (toState.isTaskbarStashed()) {
- // Reset hotseat alpha to default
- mLauncher.getHotseat().setIconsAlpha(1);
- }
- mTargetStateOverrideForStateTransition = null;
- mAnimator = null;
- }
- });
- mAnimator = pendingAnimation.buildAnim();
- mAnimator.start();
- }
- }
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- TaskbarStashController controller = mControllers.taskbarStashController;
- controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- finalState.isTaskbarStashed());
- controller.applyState();
- }
- };
-
// Initialized in init.
private TaskbarControllers mControllers;
- private AnimatedFloat mTaskbarBackgroundAlpha;
private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
- private AlphaProperty mIconAlphaForHome;
- private boolean mIsAnimatingToLauncherViaResume;
- private boolean mIsAnimatingToLauncherViaGesture;
private TaskbarKeyguardController mKeyguardController;
-
- private LauncherState mTargetStateOverride = null;
- private LauncherState mTargetStateOverrideForStateTransition = null;
+ private final TaskbarLauncherStateController
+ mTaskbarLauncherStateController = new TaskbarLauncherStateController();
private final DeviceProfile.OnDeviceProfileChangeListener mProfileChangeListener =
new DeviceProfile.OnDeviceProfileChangeListener() {
@@ -171,37 +85,26 @@
protected void init(TaskbarControllers taskbarControllers) {
mControllers = taskbarControllers;
- mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
- .getTaskbarBackgroundAlpha();
+ mTaskbarLauncherStateController.init(mControllers, mLauncher);
mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
.getOverrideBackgroundAlpha();
- MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
- mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
-
mLauncher.setTaskbarUIController(this);
mKeyguardController = taskbarControllers.taskbarKeyguardController;
onLauncherResumedOrPaused(mLauncher.hasBeenResumed(), true /* fromInit */);
- mIconAlignmentForResumedState.finishAnimation();
- onIconAlignmentRatioChanged();
onStashedInAppChanged(mLauncher.getDeviceProfile());
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
- mLauncher.getStateManager().addStateListener(mStateListener);
mLauncher.addOnDeviceProfileChangeListener(mProfileChangeListener);
}
@Override
protected void onDestroy() {
onLauncherResumedOrPaused(false);
- mIconAlignmentForResumedState.finishAnimation();
- mIconAlignmentForGestureState.finishAnimation();
- mIconAlignmentForLauncherState.finishAnimation();
+ mTaskbarLauncherStateController.onDestroy();
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
- mLauncher.getStateManager().removeStateListener(mStateListener);
- mLauncher.getHotseat().setIconsAlpha(1f);
mLauncher.setTaskbarUIController(null);
mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
updateTaskTransitionSpec(true);
@@ -209,11 +112,7 @@
@Override
protected boolean isTaskbarTouchable() {
- return !isAnimatingToLauncher();
- }
-
- private boolean isAnimatingToLauncher() {
- return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
+ return !mTaskbarLauncherStateController.isAnimatingToLauncher();
}
@Override
@@ -240,24 +139,9 @@
}
}
- long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION;
- if (fromInit) {
- // Since we are creating the starting state, we don't have a state to animate from, so
- // set our state immediately.
- duration = 0;
- }
- ObjectAnimator anim = mIconAlignmentForResumedState.animateToValue(
- getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
- .setDuration(duration);
-
- anim.addListener(AnimatorListeners.forEndCallback(
- () -> mIsAnimatingToLauncherViaResume = false));
- anim.start();
- mIsAnimatingToLauncherViaResume = isResumed;
-
- TaskbarStashController stashController = mControllers.taskbarStashController;
- stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
- stashController.applyState(duration);
+ mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed);
+ mTaskbarLauncherStateController.applyState(
+ fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
}
/**
@@ -268,77 +152,7 @@
*/
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
- AnimatorSet animatorSet = new AnimatorSet();
- TaskbarStashController stashController = mControllers.taskbarStashController;
- stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- toState.isTaskbarStashed());
- if (toState.isTaskbarStashed()) {
- animatorSet.play(stashController.applyStateWithoutStart(duration));
- } else {
- animatorSet.play(mIconAlignmentForGestureState
- .animateToValue(1)
- .setDuration(duration));
- }
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animator) {
- mTargetStateOverride = null;
- animator.removeListener(this);
- }
-
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverride = toState;
- mIsAnimatingToLauncherViaGesture = true;
- stashController.updateStateForFlag(FLAG_IN_APP, false);
- stashController.applyState(duration);
- }
- });
-
- TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
- callbacks.addListener(listener);
- RecentsView recentsView = mLauncher.getOverviewPanel();
- recentsView.setTaskLaunchListener(() -> {
- listener.endGestureStateOverride(true);
- callbacks.removeListener(listener);
- });
-
- return animatorSet;
- }
-
- private float getCurrentIconAlignmentRatio() {
- return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
- }
-
- private float getCurrentIconAlignmentRatioForLauncherState() {
- return mIconAlignmentForLauncherState.value;
- }
-
- private void onIconAlignmentRatioChangedForStateTransition() {
- onIconAlignmentRatioChanged(
- mTargetStateOverrideForStateTransition != null
- ? mTargetStateOverrideForStateTransition
- : mLauncher.getStateManager().getState(),
- this::getCurrentIconAlignmentRatioForLauncherState);
- }
-
- private void onIconAlignmentRatioChanged() {
- onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
- : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
- }
-
- private void onIconAlignmentRatioChanged(LauncherState state,
- Supplier<Float> alignmentSupplier) {
- if (mControllers == null) {
- return;
- }
- float alignment = alignmentSupplier.get();
- mControllers.taskbarViewController.setLauncherIconAlignment(
- alignment, mLauncher.getDeviceProfile());
-
- mTaskbarBackgroundAlpha.updateValue(1 - alignment);
-
- setIconAlpha(state, alignment);
+ return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
}
/**
@@ -358,20 +172,6 @@
return mControllers.taskbarActivityContext.getDragLayer();
}
- private void setIconAlpha(LauncherState state, float progress) {
- if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- // If the hotseat icons are visible, then switch taskbar in last frame
- setTaskbarViewVisible(progress < 1);
- } else {
- mIconAlphaForHome.setValue(1 - progress);
- }
- }
-
- private void setTaskbarViewVisible(boolean isVisible) {
- mIconAlphaForHome.setValue(isVisible ? 1 : 0);
- mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
- }
-
@Override
protected void onStashedInAppChanged() {
onStashedInAppChanged(mLauncher.getDeviceProfile());
@@ -451,35 +251,4 @@
mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
instanceId);
}
-
- private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener {
- private final RecentsAnimationCallbacks mCallbacks;
-
- TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
- mCallbacks = callbacks;
- }
-
- @Override
- public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
- endGestureStateOverride(true);
- }
-
- @Override
- public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- endGestureStateOverride(!controller.getFinishTargetIsLauncher());
- }
-
- private void endGestureStateOverride(boolean finishedToApp) {
- mCallbacks.removeListener(this);
- mIsAnimatingToLauncherViaGesture = false;
-
- mIconAlignmentForGestureState
- .animateToValue(0)
- .start();
-
- TaskbarStashController controller = mControllers.taskbarStashController;
- controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
- controller.applyState();
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
new file mode 100644
index 0000000..152b255
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
+import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
+import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.HashMap;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
+ * the task bar accordingly.
+ */
+ public class TaskbarLauncherStateController {
+
+ public static final int FLAG_RESUMED = 1 << 0;
+ public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
+ public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2;
+ public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3;
+
+ private final AnimatedFloat mIconAlignmentForResumedState =
+ new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ private final AnimatedFloat mIconAlignmentForGestureState =
+ new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ private final AnimatedFloat mIconAlignmentForLauncherState =
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
+
+ private TaskbarControllers mControllers;
+ private AnimatedFloat mTaskbarBackgroundAlpha;
+ private MultiValueAlpha.AlphaProperty mIconAlphaForHome;
+ private BaseQuickstepLauncher mLauncher;
+
+ private int mPrevState;
+ private int mState;
+
+ private LauncherState mTargetStateOverride = null;
+ private LauncherState mTargetStateOverrideForStateTransition = null;
+
+ private boolean mIsAnimatingToLauncherViaGesture;
+ private boolean mIsAnimatingToLauncherViaResume;
+
+ private final StateManager.StateListener<LauncherState> mStateListener =
+ new StateManager.StateListener<LauncherState>() {
+
+ @Override
+ public void onStateTransitionStart(LauncherState toState) {
+ mTargetStateOverrideForStateTransition = toState;
+ updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
+ toState.isTaskbarStashed());
+ applyState();
+ }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ updateStateForFlag(FLAG_TRANSITION_STATE_COMMITTED_STASHED,
+ finalState.isTaskbarStashed());
+ applyState();
+ }
+ };
+
+ public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) {
+ mControllers = controllers;
+ mLauncher = launcher;
+
+ mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
+ .getTaskbarBackgroundAlpha();
+ MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
+ mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
+ mIconAlphaForHome.setConsumer(
+ (Consumer<Float>) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
+
+ mIconAlignmentForResumedState.finishAnimation();
+ onIconAlignmentRatioChanged();
+
+ mLauncher.getStateManager().addStateListener(mStateListener);
+ }
+
+ public void onDestroy() {
+ mIconAlignmentForResumedState.finishAnimation();
+ mIconAlignmentForGestureState.finishAnimation();
+ mIconAlignmentForLauncherState.finishAnimation();
+
+ mIconAlphaForHome.setConsumer(null);
+ mLauncher.getHotseat().setIconsAlpha(1f);
+ mLauncher.getStateManager().removeStateListener(mStateListener);
+ }
+
+ public Animator createAnimToLauncher(@NonNull LauncherState toState,
+ @NonNull RecentsAnimationCallbacks callbacks, long duration) {
+ // If going to overview, stash the task bar
+ // If going home, align the icons to hotseat
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ toState.isTaskbarStashed());
+ stashController.updateStateForFlag(FLAG_IN_APP, false);
+
+ updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
+ animatorSet.play(stashController.applyStateWithoutStart(duration));
+ animatorSet.play(applyState(duration, false));
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ mTargetStateOverride = null;
+ animator.removeListener(this);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animator) {
+ mTargetStateOverride = toState;
+ }
+ });
+
+ TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
+ callbacks.addListener(listener);
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ recentsView.setTaskLaunchListener(() -> {
+ listener.endGestureStateOverride(true);
+ callbacks.removeListener(listener);
+ });
+ return animatorSet;
+ }
+
+ public boolean isAnimatingToLauncher() {
+ return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
+ }
+
+ /**
+ * Updates the proper flag to change the state of the task bar.
+ *
+ * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
+ *
+ * @param flag The flag to update.
+ * @param enabled Whether to enable the flag
+ */
+ public void updateStateForFlag(int flag, boolean enabled) {
+ if (enabled) {
+ mState |= flag;
+ } else {
+ mState &= ~flag;
+ }
+ }
+
+ private boolean hasAnyFlag(int flagMask) {
+ return hasAnyFlag(mState, flagMask);
+ }
+
+ private boolean hasAnyFlag(int flags, int flagMask) {
+ return (flags & flagMask) != 0;
+ }
+
+ public void applyState() {
+ applyState(TASKBAR_STASH_DURATION);
+ }
+
+ public void applyState(long duration) {
+ applyState(duration, true);
+ }
+
+ public Animator applyState(boolean start) {
+ return applyState(TASKBAR_STASH_DURATION, start);
+ }
+
+ public Animator applyState(long duration, boolean start) {
+ Animator animator = null;
+ if (mPrevState != mState) {
+ int changedFlags = mPrevState ^ mState;
+ animator = onStateChangeApplied(changedFlags, duration, start);
+ mPrevState = mState;
+ }
+ return animator;
+ }
+
+ private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
+ AnimatorSet animatorSet = new AnimatorSet();
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED)) {
+ boolean isResumed = isResumed();
+ ObjectAnimator anim = mIconAlignmentForResumedState
+ .animateToValue(getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
+ .setDuration(duration);
+
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaResume = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaResume = isResumed;
+
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
+ stashController.applyState(duration);
+ }
+ });
+ animatorSet.play(anim);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)) {
+ boolean isRecentsAnimationRunning = isRecentsAnimationRunning();
+ Animator animator = mIconAlignmentForGestureState
+ .animateToValue(isRecentsAnimationRunning ? 1 : 0);
+ if (isRecentsAnimationRunning) {
+ animator.setDuration(duration);
+ }
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = isRecentsAnimationRunning();
+ }
+ });
+ animatorSet.play(animator);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) {
+ playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration,
+ false /* committed */);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_COMMITTED_STASHED)) {
+ playStateTransitionAnim(isTransitionStateCommittedStashed(), animatorSet, duration,
+ true /* committed */);
+ }
+
+ if (start) {
+ animatorSet.start();
+ }
+ return animatorSet;
+ }
+
+ private void playStateTransitionAnim(boolean isTransitionStateStashed,
+ AnimatorSet animatorSet, long duration, boolean committed) {
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ isTransitionStateStashed);
+ Animator stashAnimator = controller.applyStateWithoutStart(duration);
+ if (stashAnimator != null) {
+ stashAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (isTransitionStateStashed && committed) {
+ // Reset hotseat alpha to default
+ mLauncher.getHotseat().setIconsAlpha(1);
+ }
+ mTargetStateOverrideForStateTransition = null;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
+ }
+ });
+ animatorSet.play(stashAnimator);
+ animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
+ getCurrentIconAlignmentRatioForLauncherState(),
+ isTransitionStateStashed ? 0 : 1));
+ } else {
+ mTargetStateOverrideForStateTransition = null;
+ }
+ }
+
+ private boolean isResumed() {
+ return (mState & FLAG_RESUMED) != 0;
+ }
+
+ private boolean isRecentsAnimationRunning() {
+ return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0;
+ }
+
+ private boolean isTransitionStateStartStashed() {
+ return (mState & FLAG_TRANSITION_STATE_START_STASHED) != 0;
+ }
+
+ private boolean isTransitionStateCommittedStashed() {
+ return (mState & FLAG_TRANSITION_STATE_COMMITTED_STASHED) != 0;
+ }
+
+ private void onIconAlignmentRatioChangedForStateTransition() {
+ onIconAlignmentRatioChanged(
+ mTargetStateOverrideForStateTransition != null
+ ? mTargetStateOverrideForStateTransition
+ : mLauncher.getStateManager().getState(),
+ this::getCurrentIconAlignmentRatioForLauncherState);
+ }
+
+ private void onIconAlignmentRatioChanged() {
+ onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
+ : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
+ }
+
+ private void onIconAlignmentRatioChanged(LauncherState state,
+ Supplier<Float> alignmentSupplier) {
+ if (mControllers == null) {
+ return;
+ }
+ float alignment = alignmentSupplier.get();
+ mControllers.taskbarViewController.setLauncherIconAlignment(
+ alignment, mLauncher.getDeviceProfile());
+
+ mTaskbarBackgroundAlpha.updateValue(1 - alignment);
+
+ setIconAlpha(state, alignment);
+ }
+
+ private float getCurrentIconAlignmentRatio() {
+ return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+ }
+
+ private float getCurrentIconAlignmentRatioForLauncherState() {
+ return mIconAlignmentForLauncherState.value;
+ }
+
+ private void setIconAlpha(LauncherState state, float progress) {
+ if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ // If the hotseat icons are visible, then switch taskbar in last frame
+ setTaskbarViewVisible(progress < 1);
+ } else {
+ mIconAlphaForHome.setValue(1 - progress);
+ }
+ }
+
+ private void setTaskbarViewVisible(boolean isVisible) {
+ mIconAlphaForHome.setValue(isVisible ? 1 : 0);
+ }
+
+ private final class TaskBarRecentsAnimationListener implements
+ RecentsAnimationCallbacks.RecentsAnimationListener {
+ private final RecentsAnimationCallbacks mCallbacks;
+
+ TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ endGestureStateOverride(true);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ endGestureStateOverride(!controller.getFinishTargetIsLauncher());
+ }
+
+ private void endGestureStateOverride(boolean finishedToApp) {
+ mCallbacks.removeListener(this);
+ updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
+ applyState();
+
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
+ controller.applyState();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index eff59e2..95095fa 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.fallback;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
+import static com.android.quickstep.ViewUtils.postFrameDrawn;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
@@ -218,8 +219,14 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
- setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
+ boolean isOverlayEnabled = finalState == DEFAULT || finalState == MODAL_TASK;
+ setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
+
+ if (isOverlayEnabled) {
+ postFrameDrawn(this, () -> runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)));
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 30b55a8..df99d27 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -74,7 +74,7 @@
}
public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
- StagedSplitBounds splitBoundsConfig) {
+ @Nullable StagedSplitBounds splitBoundsConfig) {
super.bind(primary, orientedState);
mSecondaryTask = secondary;
mTaskIdContainer[1] = secondary.key.id;
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 5d6b656..3cba392 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
+import static com.android.quickstep.ViewUtils.postFrameDrawn;
import android.annotation.TargetApi;
import android.content.Context;
@@ -104,8 +105,14 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- setOverlayEnabled(finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK);
+ boolean isOverlayEnabled = finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK;
+ setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
+
+ if (isOverlayEnabled) {
+ postFrameDrawn(this, () -> runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)));
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 586693c..7b5a6b9 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -383,7 +383,9 @@
protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
+ @Nullable
protected RecentsAnimationController mRecentsAnimationController;
+ @Nullable
protected SurfaceTransactionApplier mSyncTransactionApplier;
protected int mTaskWidth;
protected int mTaskHeight;
@@ -394,12 +396,15 @@
// mTaskGridVerticalDiff and mTopBottomRowHeightDiff summed together provides the top
// position for bottom row of grid tasks.
+ @Nullable
protected RemoteTargetHandle[] mRemoteTargetHandles;
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
+ @Nullable
protected Float mLastComputedTaskStartPushOutDistance = null;
+ @Nullable
protected Float mLastComputedTaskEndPushOutDistance = null;
protected boolean mEnableDrawingLiveTile = false;
protected final Rect mTempRect = new Rect();
@@ -454,11 +459,13 @@
private final IntSet mTopRowIdSet = new IntSet();
// The GestureEndTarget that is still in progress.
+ @Nullable
protected GestureState.GestureEndTarget mCurrentGestureEndTarget;
// TODO(b/187528071): Remove these and replace with a real scrim.
private float mColorTint;
private final int mTintingColor;
+ @Nullable
private ObjectAnimator mTintingAnimator;
private int mOverScrollShift = 0;
@@ -542,6 +549,7 @@
private int mTaskViewIdCount;
private final int[] INVALID_TASK_IDS = new int[]{-1, -1};
protected boolean mRunningTaskTileHidden;
+ @Nullable
private Task[] mTmpRunningTasks;
protected int mFocusedTaskViewId = -1;
@@ -556,7 +564,9 @@
private int mDownX;
private int mDownY;
+ @Nullable
private PendingAnimation mPendingAnimation;
+ @Nullable
private LayoutTransition mLayoutTransition;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -581,7 +591,9 @@
private final Point mLastMeasureSize = new Point();
private final int mEmptyMessagePadding;
private boolean mShowEmptyMessage;
+ @Nullable
private OnEmptyMessageUpdatedListener mOnEmptyMessageUpdatedListener;
+ @Nullable
private Layout mEmptyTextLayout;
/**
@@ -596,8 +608,11 @@
* ensure this View doesn't go back into the {@link #mTaskViewPool},
* see {@link #onViewRemoved(View)}
*/
+ @Nullable
private TaskView mSplitHiddenTaskView;
+ @Nullable
private TaskView mSecondSplitHiddenTaskView;
+ @Nullable
private StagedSplitBounds mSplitBoundsConfig;
private final Toast mSplitToast = Toast.makeText(getContext(),
R.string.toast_split_select_app, Toast.LENGTH_SHORT);
@@ -613,12 +628,15 @@
* removed from recentsView
*/
private int mSplitHiddenTaskViewIndex;
+ @Nullable
private FloatingTaskView mFirstFloatingTaskView;
+ @Nullable
private FloatingTaskView mSecondFloatingTaskView;
/**
* The task to be removed and immediately re-added. Should not be added to task pool.
*/
+ @Nullable
private TaskView mMovingTaskView;
private OverviewActionsView mActionsView;
@@ -638,10 +656,12 @@
}
};
+ @Nullable
private RunnableList mSideTaskLaunchCallback;
+ @Nullable
private TaskLaunchListener mTaskLaunchListener;
- public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
+ public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseActivityInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
setEnableFreeScroll(true);
@@ -782,6 +802,7 @@
}
@Override
+ @Nullable
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
if (mHandleTaskStackChanges) {
TaskView taskView = getTaskViewByTaskId(taskId);
@@ -817,6 +838,7 @@
* Update the thumbnail of the task.
* @param refreshNow Refresh immediately if it's true.
*/
+ @Nullable
public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData, boolean refreshNow) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
@@ -1017,10 +1039,12 @@
}
}
+ @Nullable
private TaskView getLastGridTaskView() {
return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray());
}
+ @Nullable
private TaskView getLastGridTaskView(IntArray topRowIdArray, IntArray bottomRowIdArray) {
if (topRowIdArray.isEmpty() && bottomRowIdArray.isEmpty()) {
return null;
@@ -1070,6 +1094,10 @@
return getScrollForPage(taskIndex) == getPagedOrientationHandler().getPrimaryScroll(this);
}
+ /**
+ * Returns a {@link TaskView} that has taskId matching {@code taskId} or null if no match.
+ */
+ @Nullable
public TaskView getTaskViewByTaskId(int taskId) {
if (taskId == -1) {
return null;
@@ -1309,6 +1337,7 @@
return;
}
+ mLoadPlanEverApplied = true;
if (taskGroups == null || taskGroups.isEmpty()) {
removeTasksViewsAndClearAllButton();
onTaskStackUpdated();
@@ -1411,7 +1440,6 @@
resetTaskVisuals();
onTaskStackUpdated();
updateEnabledOverlays();
- mLoadPlanEverApplied = true;
}
private boolean isModal() {
@@ -1480,17 +1508,6 @@
}
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- // Since we reuse the same mLiveTileTaskViewSimulator in the RecentsView, we need
- // to reset the params after it settles in Overview from swipe up so that we don't
- // render with obsolete param values.
- runActionOnRemoteHandles(remoteTargetHandle -> {
- TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator();
- simulator.taskPrimaryTranslation.value = 0;
- simulator.taskSecondaryTranslation.value = 0;
- simulator.fullScreenProgress.value = 0;
- simulator.recentsViewScale.value = 1;
- });
-
// Similar to setRunningTaskHidden below, reapply the state before runningTaskView is
// null.
if (!mRunningTaskShowScreenshot) {
@@ -1878,7 +1895,7 @@
setEnableDrawingLiveTile(false);
runActionOnRemoteHandles(remoteTargetHandle -> {
remoteTargetHandle.getTransformParams().setTargetSet(null);
- remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true);
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
});
mSplitSelectStateController.resetState();
@@ -1920,6 +1937,7 @@
return getTaskViewFromTaskViewId(mFocusedTaskViewId);
}
+ @Nullable
private TaskView getTaskViewFromTaskViewId(int taskViewId) {
if (taskViewId == -1) {
return null;
@@ -2987,6 +3005,10 @@
@SuppressWarnings("WrongCall")
private void onEnd(boolean success) {
+ // Reset task translations as they may have updated via animations in
+ // createTaskDismissAnimation
+ resetTaskVisuals();
+
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
@@ -3003,10 +3025,6 @@
}
}
- // Reset task translations as they may have updated via animations in
- // createTaskDismissAnimation
- resetTaskVisuals();
-
int pageToSnapTo = mCurrentPage;
mCurrentPageScrollDiff = 0;
int taskViewIdToSnapTo = -1;
@@ -3088,12 +3106,17 @@
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
}
+ boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
removeViewInLayout(dismissedTaskView);
mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
- startHome();
+ if (isHomeTaskDismissed) {
+ updateEmptyMessage();
+ } else {
+ startHome();
+ }
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed) {
@@ -4355,7 +4378,6 @@
TaskViewSimulator tvs = remoteTargetHandle.getTaskViewSimulator();
tvs.setOrientationState(mOrientationState);
tvs.setDp(mActivity.getDeviceProfile());
- tvs.setDrawsBelowRecents(true);
tvs.recentsViewScale.value = 1;
}
}
@@ -4371,12 +4393,15 @@
}
}
- public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) {
+ /**
+ * Finish recents animation.
+ */
+ public void finishRecentsAnimation(boolean toRecents, @Nullable Runnable onFinishComplete) {
finishRecentsAnimation(toRecents, true /* shouldPip */, onFinishComplete);
}
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
- Runnable onFinishComplete) {
+ @Nullable Runnable onFinishComplete) {
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
cleanupRemoteTargets();
if (!toRecents && ENABLE_QUICKSTEP_LIVE_TILE.get()) {
@@ -4925,10 +4950,13 @@
private static class PinnedStackAnimationListener<T extends BaseActivity> extends
IPipAnimationListener.Stub {
+ @Nullable
private T mActivity;
+ @Nullable
private RecentsView mRecentsView;
- public void setActivityAndRecentsView(T activity, RecentsView recentsView) {
+ public void setActivityAndRecentsView(@Nullable T activity,
+ @Nullable RecentsView recentsView) {
mActivity = activity;
mRecentsView = recentsView;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index c960f88..f8368ae 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -459,15 +459,36 @@
float availableHeight = surfaceHeight
- (thumbnailClipHint.top + thumbnailClipHint.bottom);
- if (isRotated) {
- float canvasAspect = canvasWidth / (float) canvasHeight;
- float availableAspect = availableHeight / availableWidth;
+ float canvasAspect = canvasWidth / (float) canvasHeight;
+ float availableAspect = isRotated
+ ? availableHeight / availableWidth
+ : availableWidth / availableHeight;
+ boolean isAspectLargelyDifferent = Utilities.isRelativePercentDifferenceGreaterThan(
+ canvasAspect, availableAspect, 0.1f);
+ if (isRotated && isAspectLargelyDifferent) {
// Do not rotate thumbnail if it would not improve fit
- if (Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
- availableAspect, 0.1f)) {
- isRotated = false;
- isOrientationDifferent = false;
+ isRotated = false;
+ isOrientationDifferent = false;
+ }
+
+ if (isAspectLargelyDifferent) {
+ // Crop letterbox insets if insets isn't already clipped
+ if (!TaskView.clipLeft(dp)) {
+ thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
}
+ if (!TaskView.clipRight(dp)) {
+ thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
+ }
+ if (!TaskView.clipTop(dp)) {
+ thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
+ }
+ if (!TaskView.clipBottom(dp)) {
+ thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
+ }
+ availableWidth = surfaceWidth
+ - (thumbnailClipHint.left + thumbnailClipHint.right);
+ availableHeight = surfaceHeight
+ - (thumbnailClipHint.top + thumbnailClipHint.bottom);
}
final float targetW, targetH;
@@ -478,30 +499,25 @@
targetW = canvasWidth;
targetH = canvasHeight;
}
- float canvasAspect = targetW / targetH;
+ float targetAspect = targetW / targetH;
// Update the clipHint such that
// > the final clipped position has same aspect ratio as requested by canvas
- // > the clipped region is within the task insets if possible
- // > the clipped region is not scaled up when drawing. If that is not possible
- // while staying within the taskInsets, move outside the insets.
+ // > first fit the width and crop the extra height
+ // > if that will leave empty space, fit the height and crop the width instead
float croppedWidth = availableWidth;
- if (croppedWidth < targetW) {
- croppedWidth = Math.min(targetW, surfaceWidth);
- }
-
- float croppedHeight = croppedWidth / canvasAspect;
+ float croppedHeight = croppedWidth / targetAspect;
if (croppedHeight > availableHeight) {
croppedHeight = availableHeight;
if (croppedHeight < targetH) {
croppedHeight = Math.min(targetH, surfaceHeight);
}
- croppedWidth = croppedHeight * canvasAspect;
+ croppedWidth = croppedHeight * targetAspect;
// One last check in case the task aspect radio messed up something
if (croppedWidth > surfaceWidth) {
croppedWidth = surfaceWidth;
- croppedHeight = croppedWidth / canvasAspect;
+ croppedHeight = croppedWidth / targetAspect;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 3da7893..e9a3779 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -648,21 +648,7 @@
recentsView.getDepthController());
anim.addListener(new AnimatorListenerAdapter() {
@Override
- public void onAnimationStart(Animator animator) {
- recentsView.runActionOnRemoteHandles(
- (Consumer<RemoteTargetHandle>) remoteTargetHandle ->
- remoteTargetHandle
- .getTaskViewSimulator()
- .setDrawsBelowRecents(false));
- }
-
- @Override
public void onAnimationEnd(Animator animator) {
- recentsView.runActionOnRemoteHandles(
- (Consumer<RemoteTargetHandle>) remoteTargetHandle ->
- remoteTargetHandle
- .getTaskViewSimulator()
- .setDrawsBelowRecents(true));
mIsClickableAsLiveTile = true;
}
});
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 5c16b4c..e64ea90 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -251,8 +251,7 @@
// Tablet UI does not support emulated landscape.
isTablet = allowRotation && info.isTablet(windowBounds);
isPhone = !isTablet;
- isTwoPanels = isTablet && useTwoPanels
- && (isLandscape || FeatureFlags.ENABLE_TWO_PANEL_HOME_IN_PORTRAIT.get());
+ isTwoPanels = isTablet && useTwoPanels;
aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 9f3d445..68e19cb 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -383,7 +383,7 @@
case LauncherSettings.Settings.METHOD_NEW_SCREEN_ID: {
Bundle result = new Bundle();
result.putInt(LauncherSettings.Settings.EXTRA_VALUE,
- mOpenHelper.generateNewScreenId());
+ mOpenHelper.getNewScreenId());
return result;
}
case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: {
@@ -628,7 +628,6 @@
private final Context mContext;
private final boolean mForMigration;
private int mMaxItemId = -1;
- private int mMaxScreenId = -1;
private boolean mBackupTableExists;
private boolean mHotseatRestoreTableExists;
@@ -672,9 +671,6 @@
if (mMaxItemId == -1) {
mMaxItemId = initializeMaxItemId(getWritableDatabase());
}
- if (mMaxScreenId == -1) {
- mMaxScreenId = initializeMaxScreenId(getWritableDatabase());
- }
}
@Override
@@ -682,7 +678,6 @@
if (LOGD) Log.d(TAG, "creating new launcher database");
mMaxItemId = 1;
- mMaxScreenId = 0;
addFavoritesTable(db, false);
@@ -1043,36 +1038,19 @@
public void checkId(ContentValues values) {
int id = values.getAsInteger(Favorites._ID);
mMaxItemId = Math.max(id, mMaxItemId);
-
- Integer screen = values.getAsInteger(Favorites.SCREEN);
- Integer container = values.getAsInteger(Favorites.CONTAINER);
- if (screen != null && container != null
- && container.intValue() == Favorites.CONTAINER_DESKTOP) {
- mMaxScreenId = Math.max(screen, mMaxScreenId);
- }
}
private int initializeMaxItemId(SQLiteDatabase db) {
return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s", Favorites._ID, Favorites.TABLE_NAME);
}
- // Generates a new ID to use for an workspace screen in your database. This method
- // should be only called from the main UI thread. As an exception, we do call it when we
- // call the constructor from the worker thread; however, this doesn't extend until after the
- // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
- // after that point
- public int generateNewScreenId() {
- if (mMaxScreenId < 0) {
- throw new RuntimeException("Error: max screen id was not initialized");
- }
- mMaxScreenId += 1;
- return mMaxScreenId;
- }
-
- private int initializeMaxScreenId(SQLiteDatabase db) {
- return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
+ // Returns a new ID to use for an workspace screen in your database that is greater than all
+ // existing screen IDs.
+ private int getNewScreenId() {
+ return getMaxId(getWritableDatabase(),
+ "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
- Favorites.CONTAINER_DESKTOP);
+ Favorites.CONTAINER_DESKTOP) + 1;
}
@Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
@@ -1081,7 +1059,6 @@
// Ensure that the max ids are initialized
mMaxItemId = initializeMaxItemId(db);
- mMaxScreenId = initializeMaxScreenId(db);
return count;
}
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 523ac72..cefadf7 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1721,6 +1721,10 @@
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ if (mScroller.isFinished()) {
+ // This was not caused by the scroller, skip it.
+ return;
+ }
int newDestinationPage = getDestinationPage();
if (newDestinationPage >= 0 && newDestinationPage != mCurrentScrollOverPage) {
mCurrentScrollOverPage = newDestinationPage;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ce06c6e..131fbfb 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -869,13 +869,13 @@
mWorkspaceScreens.remove(emptyScreenId);
mScreenOrder.removeValue(emptyScreenId);
- int newScreenId = -1;
+ int newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
+ LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
// Launcher database isn't aware of empty pages that are already bound, so we need to
// skip those IDs manually.
- while (newScreenId == -1 || mWorkspaceScreens.containsKey(newScreenId)) {
- newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
- LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getInt(LauncherSettings.Settings.EXTRA_VALUE);
+ while (mWorkspaceScreens.containsKey(newScreenId)) {
+ newScreenId++;
}
mWorkspaceScreens.put(newScreenId, cl);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index e253505..c4d8166 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -210,10 +210,6 @@
"ENABLE_TWO_PANEL_HOME", true,
"Uses two panel on home screen. Only applicable on large screen devices.");
- public static final BooleanFlag ENABLE_TWO_PANEL_HOME_IN_PORTRAIT = getDebugFlag(
- "ENABLE_TWO_PANEL_HOME_IN_PORTRAIT", true,
- "Uses two panel on home screen in portrait if ENABLE_TWO_PANEL_HOME is enabled.");
-
public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(
"ENABLE_SCRIM_FOR_APP_LAUNCH", false,
"Enables scrim during app launch animation.");
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index fea15c4..a13fa55 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -16,7 +16,6 @@
package com.android.launcher3.model;
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.WorkspaceLayoutManager.SECOND_SCREEN_ID;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
@@ -300,11 +299,6 @@
IntSet screensToExclude = new IntSet();
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
screensToExclude.add(FIRST_SCREEN_ID);
-
- // On split display we don't want to add the new items onto the second screen.
- if (app.getInvariantDeviceProfile().isSplitDisplay) {
- screensToExclude.add(SECOND_SCREEN_ID);
- }
}
for (int screen = 0; screen < screenCount; screen++) {
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 0439e75..94e06d1 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -292,7 +292,7 @@
FileLog.d(TAG, "removing items from db " + items.stream().map(
(item) -> item.getTargetComponent() == null ? ""
: item.getTargetComponent().getPackageName()).collect(
- Collectors.joining(",")), new Exception());
+ Collectors.joining(",")));
notifyDelete(items);
enqueueDeleteRunnable(() -> {
for (ItemInfo item : items) {
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 8caf886..ba9d09c 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -451,24 +451,19 @@
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo, int desiredStagePosition) {
boolean isLandscape = dp.isLandscape;
- float verticalDividerDiff = splitInfo.visualDividerBounds.height() / 2f;
- float horizontalDividerDiff = splitInfo.visualDividerBounds.width() / 2f;
- float diff;
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
if (isLandscape) {
- diff = outRect.width() * (1f - splitInfo.leftTaskPercent) + horizontalDividerDiff;
- outRect.right -= diff;
+ outRect.right = outRect.left + (int) (outRect.width() * splitInfo.leftTaskPercent);
} else {
- diff = outRect.height() * (1f - splitInfo.topTaskPercent) + verticalDividerDiff;
- outRect.bottom -= diff;
+ outRect.bottom = outRect.top + (int) (outRect.height() * splitInfo.topTaskPercent);
}
} else {
if (isLandscape) {
- diff = outRect.width() * splitInfo.leftTaskPercent + horizontalDividerDiff;
- outRect.left += diff;
+ outRect.left += (int) (outRect.width() *
+ (splitInfo.leftTaskPercent + splitInfo.dividerWidthPercent));
} else {
- diff = outRect.height() * splitInfo.topTaskPercent + verticalDividerDiff;
- outRect.top += diff;
+ outRect.top += (int) (outRect.height() *
+ (splitInfo.topTaskPercent + splitInfo.dividerHeightPercent));
}
}
}
@@ -479,9 +474,9 @@
StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
- int dividerBar = (splitBoundsConfig.appsStackedVertically ?
- splitBoundsConfig.visualDividerBounds.height() :
- splitBoundsConfig.visualDividerBounds.width());
+ int dividerBar = splitBoundsConfig.appsStackedVertically
+ ? (int) (splitBoundsConfig.dividerHeightPercent * parentHeight)
+ : (int) (splitBoundsConfig.dividerWidthPercent * parentWidth);
int primarySnapshotHeight;
int primarySnapshotWidth;
int secondarySnapshotHeight;
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index bd39391..326141d 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -24,6 +24,7 @@
import com.android.launcher3.anim.AlphaUpdateListener;
import java.util.Arrays;
+import java.util.function.Consumer;
/**
* Utility class to handle separating a single value as a factor of multiple values
@@ -85,6 +86,8 @@
// Factor of all other alpha channels, only valid if mMyMask is present in mValidMask.
private float mOthers = 1;
+ private Consumer<Float> mConsumer;
+
AlphaProperty(int myMask) {
mMyMask = myMask;
}
@@ -109,16 +112,24 @@
mValidMask = mMyMask;
mValue = value;
- mView.setAlpha(mOthers * mValue);
+ final float alpha = mOthers * mValue;
+ mView.setAlpha(alpha);
if (mUpdateVisibility) {
AlphaUpdateListener.updateVisibility(mView);
}
+ if (mConsumer != null) {
+ mConsumer.accept(mValue);
+ }
}
public float getValue() {
return mValue;
}
+ public void setConsumer(Consumer<Float> consumer) {
+ mConsumer = consumer;
+ }
+
@Override
public String toString() {
return Float.toString(mValue);
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 6aef38f..53b1c3e 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -99,6 +99,8 @@
// This class is orientation-agnostic, so we compute both for later use
public final float topTaskPercent;
public final float leftTaskPercent;
+ public final float dividerWidthPercent;
+ public final float dividerHeightPercent;
/**
* If {@code true}, that means at the time of creation of this object, the
* split-screened apps were vertically stacked. This is useful in scenarios like
@@ -130,6 +132,8 @@
leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
topTaskPercent = this.leftTopBounds.height() / (float) rightBottomBounds.bottom;
+ dividerWidthPercent = visualDividerBounds.width() / (float) rightBottomBounds.right;
+ dividerHeightPercent = visualDividerBounds.height() / (float) rightBottomBounds.bottom;
}
}
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 16f024e..8a4590a 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -86,8 +86,6 @@
@Test
public void testFindSpaceForItem_prefers_second() throws Exception {
- mIdp.isSplitDisplay = false;
-
// First screen has only one hole of size 1
int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
@@ -109,24 +107,6 @@
}
@Test
- public void testFindSpaceForItem_prefers_third_on_split_display() throws Exception {
- mIdp.isSplitDisplay = true;
- // First screen has only one hole of size 1
- int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
-
- // Second screen has 2 holes of sizes 3x2 and 2x3
- setupWorkspaceWithHoles(nextId, 2, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
-
- int[] spaceFound = newTask().findSpaceForItem(
- mAppState, mModelHelper.getBgDataModel(), mExistingScreens, mNewScreens, 1, 1);
- // For split display, it picks the next screen, even if there is enough space
- // on previous screen
- assertEquals(2, spaceFound[0]);
- assertTrue(mScreenOccupancy.get(spaceFound[0])
- .isRegionVacant(spaceFound[1], spaceFound[2], 1, 1));
- }
-
- @Test
public void testFindSpaceForItem_adds_new_screen() throws Exception {
// First screen has 2 holes of sizes 3x2 and 2x3
setupWorkspaceWithHoles(1, 1, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 36af8f0..194ee4f 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -28,7 +28,6 @@
import com.android.launcher3.tapl.WidgetResizeFrame;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -48,7 +47,6 @@
@Test
@PortraitLandscape
- @ScreenRecord // b/204807156
public void testDragIcon() throws Throwable {
clearHomescreen();
mDevice.pressHome();
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 758c426..fa39ce0 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -45,7 +45,6 @@
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
@@ -139,7 +138,6 @@
}
@Test
- @ScreenRecord // b/204807156
public void testPendingWidget_autoRestored() {
// A non-restored widget with no config screen gets restored automatically.
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);