Merge "Support to launch app pair from overview with recorded split ratio." into sc-v2-dev
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index e82c900..f9a0bb1 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -161,8 +161,7 @@
}
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = info.container > 0
- ? (FolderInfo) itemsIdMap.get(info.container) : null;
+ FolderInfo parent = getContainer(info, itemsIdMap);
StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
}
additionalSnapshotEvents(instanceId);
@@ -199,8 +198,7 @@
}
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = info.container > 0
- ? (FolderInfo) itemsIdMap.get(info.container) : null;
+ FolderInfo parent = getContainer(info, itemsIdMap);
LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
Log.d(TAG, itemInfo.toString());
StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
@@ -222,6 +220,22 @@
}
}
+ private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
+ if (info.container > 0) {
+ ItemInfo containerInfo = itemsIdMap.get(info.container);
+
+ if (!(containerInfo instanceof FolderInfo)) {
+ Log.e(TAG, String.format(
+ "Item info: %s found with invalid container: %s",
+ info,
+ containerInfo));
+ } else {
+ return (FolderInfo) containerInfo;
+ }
+ }
+ return null;
+ }
+
@Override
public void validateData() {
super.validateData();
diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
index 24a88a4..90c035f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java
@@ -46,16 +46,13 @@
}
};
- // Initialized in init.
- TaskbarControllers mControllers;
-
public FallbackTaskbarUIController(RecentsActivity recentsActivity) {
mRecentsActivity = recentsActivity;
}
@Override
protected void init(TaskbarControllers taskbarControllers) {
- mControllers = taskbarControllers;
+ super.init(taskbarControllers);
mRecentsActivity.setTaskbarUIController(this);
mRecentsActivity.getStateManager().addStateListener(mStateListener);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 1c0c773..7d23439 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -25,7 +25,6 @@
import android.util.Log;
import android.view.MotionEvent;
import android.view.TaskTransitionSpec;
-import android.view.View;
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
@@ -62,7 +61,6 @@
this::onStashedInAppChanged;
// Initialized in init.
- private TaskbarControllers mControllers;
private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
private TaskbarKeyguardController mKeyguardController;
private final TaskbarLauncherStateController
@@ -83,7 +81,7 @@
@Override
protected void init(TaskbarControllers taskbarControllers) {
- mControllers = taskbarControllers;
+ super.init(taskbarControllers);
mTaskbarLauncherStateController.init(mControllers, mLauncher);
mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
@@ -168,10 +166,6 @@
return mControllers.taskbarDragController.isDragging();
}
- public View getRootView() {
- return mControllers.taskbarActivityContext.getDragLayer();
- }
-
@Override
protected void onStashedInAppChanged() {
onStashedInAppChanged(mLauncher.getDeviceProfile());
@@ -251,4 +245,12 @@
mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
instanceId);
}
+
+ @Override
+ public void setSystemGestureInProgress(boolean inProgress) {
+ super.setSystemGestureInProgress(inProgress);
+ // Launcher's ScrimView will draw the background throughout the gesture. But once the
+ // gesture ends, start drawing taskbar's background again since launcher might stop drawing.
+ forceHideBackground(inProgress);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 0565f7e..f6e0426 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_HOME;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_IME_SWITCH;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_RECENTS;
-import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_IME;
import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
@@ -140,11 +139,6 @@
mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
mNavButtonTranslationYMultiplier.value = 1;
- mPropertyHolders.add(new StatePropertyHolder(
- mControllers.taskbarViewController.getTaskbarIconAlpha()
- .getProperty(ALPHA_INDEX_IME),
- flags -> (flags & FLAG_IME_VISIBLE) == 0, MultiValueAlpha.VALUE, 1, 0));
-
boolean isThreeButtonNav = mContext.isThreeButtonNav();
// IME switcher
View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
@@ -196,7 +190,7 @@
}
// Animate taskbar background when any of these flags are enabled
- int flagsToShowBg = FLAG_IME_VISIBLE | FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE
+ int flagsToShowBg = FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE
| FLAG_NOTIFICATION_SHADE_EXPANDED;
mPropertyHolders.add(new StatePropertyHolder(
mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 2c80f06..22ca63f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -16,6 +16,8 @@
package com.android.launcher3.taskbar;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Outline;
@@ -23,8 +25,6 @@
import android.view.View;
import android.view.ViewOutlineProvider;
-import androidx.annotation.Nullable;
-
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.RevealOutlineAnimation;
@@ -66,7 +66,10 @@
private final Rect mStashedHandleBounds = new Rect();
private float mStashedHandleRadius;
- private boolean mIsAtStashedRevealBounds = true;
+ // When the reveal animation is cancelled, we can assume it's about to create a new animation,
+ // which should start off at the same point the cancelled one left off.
+ private float mStartProgressForNextRevealAnim;
+ private boolean mWasLastRevealAnimReversed;
public StashedHandleViewController(TaskbarActivityContext activity,
StashedHandleView stashedHandleView) {
@@ -148,15 +151,27 @@
* shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape
* morphs into the size of where the taskbar icons will be.
*/
- public @Nullable Animator createRevealAnimToIsStashed(boolean isStashed) {
- if (mIsAtStashedRevealBounds == isStashed) {
- return null;
- }
- mIsAtStashedRevealBounds = isStashed;
+ public Animator createRevealAnimToIsStashed(boolean isStashed) {
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
mStashedHandleRadius, mStashedHandleRadius,
mControllers.taskbarViewController.getIconLayoutBounds(), mStashedHandleBounds);
- return handleRevealProvider.createRevealAnimator(mStashedHandleView, !isStashed);
+
+ boolean isReversed = !isStashed;
+ boolean changingDirection = mWasLastRevealAnimReversed != isReversed;
+ mWasLastRevealAnimReversed = isReversed;
+ if (changingDirection) {
+ mStartProgressForNextRevealAnim = 1f - mStartProgressForNextRevealAnim;
+ }
+
+ ValueAnimator revealAnim = handleRevealProvider.createRevealAnimator(mStashedHandleView,
+ isReversed, mStartProgressForNextRevealAnim);
+ revealAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStartProgressForNextRevealAnim = ((ValueAnimator) animation).getAnimatedFraction();
+ }
+ });
+ return revealAnim;
}
public void onIsStashed(boolean isStashed) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 56730db..2d4942d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -19,6 +19,9 @@
import com.android.systemui.shared.rotation.RotationButtonController;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Hosts various taskbar controllers to facilitate passing between one another.
*/
@@ -43,6 +46,9 @@
/** Do not store this controller, as it may change at runtime. */
@NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
+ private boolean mAreAllControllersInitialized;
+ private final List<Runnable> mPostInitCallbacks = new ArrayList<>();
+
public TaskbarControllers(TaskbarActivityContext taskbarActivityContext,
TaskbarDragController taskbarDragController,
TaskbarNavButtonController navButtonController,
@@ -81,6 +87,8 @@
* in constructors for now, as some controllers may still be waiting for init().
*/
public void init(TaskbarSharedState sharedState) {
+ mAreAllControllersInitialized = false;
+
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
rotationButtonController.init();
@@ -92,6 +100,12 @@
stashedHandleViewController.init(this);
taskbarStashController.init(this, sharedState);
taskbarEduController.init(this);
+
+ mAreAllControllersInitialized = true;
+ for (Runnable postInitCallback : mPostInitCallbacks) {
+ postInitCallback.run();
+ }
+ mPostInitCallbacks.clear();
}
/**
@@ -108,4 +122,17 @@
stashedHandleViewController.onDestroy();
taskbarAutohideSuspendController.onDestroy();
}
+
+ /**
+ * If all controllers are already initialized, runs the given callback immediately. Otherwise,
+ * queues it to run after calling init() on all controllers. This should likely be used in any
+ * case where one controller is telling another controller to do something inside init().
+ */
+ public void runAfterInit(Runnable callback) {
+ if (mAreAllControllersInitialized) {
+ callback.run();
+ } else {
+ mPostInitCallbacks.add(callback);
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 248c40d..806b390 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -44,6 +44,7 @@
private final AnimatedFloat mKeyguardBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat(
this::updateBackgroundAlpha);
+ private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
// Used to hide our background color when someone else (e.g. ScrimView) is handling it.
private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
@@ -74,6 +75,7 @@
mBgTaskbar.value = 1;
mKeyguardBgTaskbar.value = 1;
mNotificationShadeBgTaskbar.value = 1;
+ mImeBgTaskbar.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
}
@@ -108,6 +110,10 @@
return mNotificationShadeBgTaskbar;
}
+ public AnimatedFloat getImeBgTaskbar() {
+ return mImeBgTaskbar;
+ }
+
public AnimatedFloat getOverrideBackgroundAlpha() {
return mBgOverride;
}
@@ -119,7 +125,7 @@
private void updateBackgroundAlpha() {
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
- * mNotificationShadeBgTaskbar.value;
+ * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value;
mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
mTaskbarDragLayer.setTaskbarBackgroundAlpha(mLastSetBackgroundAlpha);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 6dcfe56..37a9b5e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -184,9 +184,12 @@
}
mContainer.updateHotseatItems(hotseatItemInfos);
- mControllers.taskbarStashController.updateStateForFlag(
- TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, isHotseatEmpty);
- mControllers.taskbarStashController.applyState();
+ final boolean finalIsHotseatEmpty = isHotseatEmpty;
+ mControllers.runAfterInit(() -> {
+ mControllers.taskbarStashController.updateStateForFlag(
+ TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, finalIsHotseatEmpty);
+ mControllers.taskbarStashController.applyState();
+ });
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 60842c8..8965dc4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import android.animation.Animator;
@@ -48,11 +49,13 @@
public static final int FLAG_STASHED_IN_APP_PINNED = 1 << 2; // app pinning
public static final int FLAG_STASHED_IN_APP_EMPTY = 1 << 3; // no hotseat icons
public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 4; // setup wizard and AllSetActivity
- public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 5;
+ public static final int FLAG_STASHED_IN_APP_IME = 1 << 5; // IME is visible
+ public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 6;
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
public static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_MANUAL
- | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP;
+ | FLAG_STASHED_IN_APP_PINNED | FLAG_STASHED_IN_APP_EMPTY | FLAG_STASHED_IN_APP_SETUP
+ | FLAG_STASHED_IN_APP_IME;
/**
* How long to stash/unstash when manually invoked via long press.
@@ -60,6 +63,11 @@
public static final long TASKBAR_STASH_DURATION = 300;
/**
+ * How long to stash/unstash when keyboard is appearing/disappearing.
+ */
+ private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
+
+ /**
* The scale TaskbarView animates to when being stashed.
*/
private static final float STASHED_TASKBAR_SCALE = 0.5f;
@@ -100,6 +108,7 @@
private TaskbarControllers mControllers;
// Taskbar background properties.
private AnimatedFloat mTaskbarBackgroundOffset;
+ private AnimatedFloat mTaskbarImeBgAlpha;
// TaskbarView icon properties.
private AlphaProperty mIconAlphaForStash;
private AnimatedFloat mIconScaleForStash;
@@ -113,6 +122,8 @@
private int mState;
private @Nullable AnimatorSet mAnimator;
+ private boolean mIsSystemGestureInProgress;
+ private boolean mIsImeShowing;
// Evaluate whether the handle should be stashed
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
@@ -137,6 +148,7 @@
TaskbarDragLayerController dragLayerController = controllers.taskbarDragLayerController;
mTaskbarBackgroundOffset = dragLayerController.getTaskbarBackgroundOffset();
+ mTaskbarImeBgAlpha = dragLayerController.getImeBgTaskbar();
TaskbarViewController taskbarViewController = controllers.taskbarViewController;
mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().getProperty(
@@ -271,17 +283,21 @@
* Create a stash animation and save to {@link #mAnimator}.
* @param isStashed whether it's a stash animation or an unstash animation
* @param duration duration of the animation
+ * @param startDelay how many milliseconds to delay the animation after starting it.
*/
- private void createAnimToIsStashed(boolean isStashed, long duration) {
+ private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay) {
if (mAnimator != null) {
mAnimator.cancel();
}
mAnimator = new AnimatorSet();
if (!supportsVisualStashing()) {
- // Just hide/show the icons instead of stashing into a handle.
+ // Just hide/show the icons and background instead of stashing into a handle.
mAnimator.play(mIconAlphaForStash.animateToValue(isStashed ? 0 : 1)
.setDuration(duration));
+ mAnimator.play(mTaskbarImeBgAlpha.animateToValue(
+ hasAnyFlag(FLAG_STASHED_IN_APP_IME) ? 0 : 1).setDuration(duration));
+ mAnimator.setStartDelay(startDelay);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -332,11 +348,8 @@
);
}
- Animator stashedHandleRevealAnim = mControllers.stashedHandleViewController
- .createRevealAnimToIsStashed(isStashed);
- if (stashedHandleRevealAnim != null) {
- fullLengthAnimatorSet.play(stashedHandleRevealAnim);
- }
+ fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
+ .createRevealAnimToIsStashed(isStashed));
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
fullLengthAnimatorSet.play(mTaskbarStashedHandleHintScale.animateToValue(1f));
@@ -348,6 +361,7 @@
mAnimator.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
secondHalfAnimatorSet);
+ mAnimator.setStartDelay(startDelay);
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -406,6 +420,10 @@
mStatePropertyHolder.setState(mState, duration, true);
}
+ public void applyState(long duration, long startDelay) {
+ mStatePropertyHolder.setState(mState, duration, startDelay, true);
+ }
+
public Animator applyStateWithoutStart() {
return applyStateWithoutStart(TASKBAR_STASH_DURATION);
}
@@ -414,11 +432,50 @@
return mStatePropertyHolder.setState(mState, duration, false);
}
+ /**
+ * Should be called when a system gesture starts and settles, so we can defer updating
+ * FLAG_STASHED_IN_APP_IME until after the gesture transition completes.
+ */
+ public void setSystemGestureInProgress(boolean inProgress) {
+ mIsSystemGestureInProgress = inProgress;
+ // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
+ if (!mIsSystemGestureInProgress) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
+ applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
+ }
+ }
+
+ /**
+ * When hiding the IME, delay the unstash animation to align with the end of the transition.
+ */
+ private long getTaskbarStashStartDelayForIme() {
+ if (mIsImeShowing) {
+ // Only delay when IME is exiting, not entering.
+ return 0;
+ }
+ // This duration is based on input_method_extract_exit.xml.
+ long imeExitDuration = mControllers.taskbarActivityContext.getResources()
+ .getInteger(android.R.integer.config_shortAnimTime);
+ return imeExitDuration - TASKBAR_STASH_DURATION_FOR_IME;
+ }
+
/** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
+ long animDuration = TASKBAR_STASH_DURATION;
+ long startDelay = 0;
+
updateStateForFlag(FLAG_STASHED_IN_APP_PINNED,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING));
- applyState(skipAnim ? 0 : TASKBAR_STASH_DURATION);
+
+ // Only update FLAG_STASHED_IN_APP_IME when system gesture is not in progress.
+ mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
+ if (!mIsSystemGestureInProgress) {
+ updateStateForFlag(FLAG_STASHED_IN_APP_IME, mIsImeShowing);
+ animDuration = TASKBAR_STASH_DURATION_FOR_IME;
+ startDelay = getTaskbarStashStartDelayForIme();
+ }
+
+ applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay);
}
/**
@@ -474,16 +531,34 @@
mStashCondition = stashCondition;
}
+ /**
+ * @see #setState(int, long, long, boolean) with a default startDelay = 0.
+ */
public Animator setState(int flags, long duration, boolean start) {
+ return setState(flags, duration, 0 /* startDelay */, start);
+ }
+
+ /**
+ * Applies the latest state, potentially calling onStateChangeApplied() and creating a new
+ * animation (stored in mAnimator) which is started if {@param start} is true.
+ * @param flags The latest flags to apply (see the top of this file).
+ * @param duration The length of the animation.
+ * @param startDelay How long to delay the animation after calling start().
+ * @param start Whether to start mAnimator immediately.
+ * @return mAnimator if mIsStashed changed, else null.
+ */
+ public Animator setState(int flags, long duration, long startDelay, boolean start) {
+ int changedFlags = mPrevFlags ^ flags;
if (mPrevFlags != flags) {
- int changedFlags = mPrevFlags ^ flags;
onStateChangeApplied(changedFlags);
mPrevFlags = flags;
}
boolean isStashed = mStashCondition.test(flags);
if (mIsStashed != isStashed) {
mIsStashed = isStashed;
- createAnimToIsStashed(mIsStashed, duration);
+
+ // This sets mAnimator.
+ createAnimToIsStashed(mIsStashed, duration, startDelay);
if (start) {
mAnimator.start();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index d8360e0..f713dca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import android.graphics.Rect;
+import android.view.View;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -29,7 +30,12 @@
public static final TaskbarUIController DEFAULT = new TaskbarUIController();
- protected void init(TaskbarControllers taskbarControllers) { }
+ // Initialized in init.
+ protected TaskbarControllers mControllers;
+
+ protected void init(TaskbarControllers taskbarControllers) {
+ mControllers = taskbarControllers;
+ }
protected void onDestroy() { }
@@ -46,4 +52,16 @@
}
public void onTaskbarIconLaunched(WorkspaceItemInfo item) { }
+
+ public View getRootView() {
+ return mControllers.taskbarActivityContext.getDragLayer();
+ }
+
+ /**
+ * Called when swiping from the bottom nav region in fully gestural mode.
+ * @param inProgress True if the animation started, false if we just settled on an end target.
+ */
+ public void setSystemGestureInProgress(boolean inProgress) {
+ mControllers.taskbarStashController.setSystemGestureInProgress(inProgress);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index c47bde9..445a23b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -45,12 +45,11 @@
private static final Runnable NO_OP = () -> { };
public static final int ALPHA_INDEX_HOME = 0;
- public static final int ALPHA_INDEX_IME = 1;
- public static final int ALPHA_INDEX_KEYGUARD = 2;
- public static final int ALPHA_INDEX_STASH = 3;
- public static final int ALPHA_INDEX_RECENTS_DISABLED = 4;
- public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 5;
- private static final int NUM_ALPHA_CHANNELS = 6;
+ public static final int ALPHA_INDEX_KEYGUARD = 1;
+ public static final int ALPHA_INDEX_STASH = 2;
+ public static final int ALPHA_INDEX_RECENTS_DISABLED = 3;
+ public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
+ private static final int NUM_ALPHA_CHANNELS = 5;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 2fa8b07..d74b6c5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
@@ -73,8 +72,6 @@
getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
RECENTS_GRID_PROGRESS.set(mRecentsView,
state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
-
- applySplitScrollOffset(state);
}
@Override
@@ -120,16 +117,6 @@
boolean showAsGrid = toState.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile());
setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
showAsGrid ? INSTANT : FINAL_FRAME);
-
- applySplitScrollOffset(toState);
- }
-
- private void applySplitScrollOffset(@NonNull final LauncherState state) {
- if (state == OVERVIEW_SPLIT_SELECT) {
- mRecentsView.applySplitPrimaryScrollOffset();
- } else {
- mRecentsView.resetSplitPrimaryScrollOffset();
- }
}
abstract FloatProperty getTaskModalnessProperty();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 2f15013..b21d677 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -90,8 +90,10 @@
LauncherState currentState = mLauncher.getStateManager().getState();
if (isSplitSelectionState(toState) && !isSplitSelectionState(currentState)) {
builder.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
+ mRecentsView.applySplitPrimaryScrollOffset();
} else if (!isSplitSelectionState(toState) && isSplitSelectionState(currentState)) {
builder.add(mRecentsView.cancelSplitSelect(true).buildAnim());
+ mRecentsView.resetSplitPrimaryScrollOffset();
}
setAlphas(builder, config, toState);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index d396018..a4eff87 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -21,13 +21,11 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.SystemProperties;
-import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
import com.android.launcher3.util.Themes;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.util.LayoutUtils;
@@ -66,10 +64,7 @@
@Override
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
- Workspace workspace = launcher.getWorkspace();
- View workspacePage = workspace.getPageAt(workspace.getCurrentPage());
- float workspacePageWidth = workspacePage != null && workspacePage.getWidth() != 0
- ? workspacePage.getWidth() : launcher.getDeviceProfile().availableWidthPx;
+ float workspacePageWidth = launcher.getDeviceProfile().getWorkspaceWidth();
recentsView.getTaskSize(sTempRect);
float scale = (float) sTempRect.width() / workspacePageWidth;
float parallaxFactor = 0.5f;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 45b2081..c9cbba1 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -121,8 +121,8 @@
import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.function.Consumer;
/**
@@ -687,14 +687,17 @@
}
private void onAnimatorPlaybackControllerCreated(AnimatorControllerWithResistance anim) {
+ boolean isFirstCreation = mLauncherTransitionController == null;
mLauncherTransitionController = anim;
- mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, () -> {
- // Wait until the gesture is started (touch slop was passed) to start in sync with
- // mWindowTransitionController. This ensures we don't hide the taskbar background when
- // long pressing to stash it, for instance.
- mLauncherTransitionController.getNormalController().dispatchOnStart();
- updateLauncherTransitionProgress();
- });
+ if (isFirstCreation) {
+ mStateCallback.runOnceAtState(STATE_GESTURE_STARTED, () -> {
+ // Wait until the gesture is started (touch slop was passed) to start in sync with
+ // mWindowTransitionController. This ensures we don't hide the taskbar background
+ // when long pressing to stash it, for instance.
+ mLauncherTransitionController.getNormalController().dispatchOnStart();
+ updateLauncherTransitionProgress();
+ });
+ }
}
public Intent getLaunchIntent() {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index e15aa92..a566765 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -30,6 +30,7 @@
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
@@ -398,6 +399,11 @@
* (This is a hack to ensure Taskbar draws its background first to avoid flickering.)
*/
public @Nullable View onSettledOnEndTarget(GestureState.GestureEndTarget endTarget) {
+ TaskbarUIController taskbarUIController = getTaskbarController();
+ if (taskbarUIController != null) {
+ taskbarUIController.setSystemGestureInProgress(false);
+ return taskbarUIController.getRootView();
+ }
return null;
}
@@ -533,6 +539,16 @@
pa.addFloat(recentsView, RECENTS_SCALE_PROPERTY,
recentsView.getMaxScaleForFullScreen(), 1, LINEAR);
pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
+
+ pa.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ TaskbarUIController taskbarUIController = getTaskbarController();
+ if (taskbarUIController != null) {
+ taskbarUIController.setSystemGestureInProgress(true);
+ }
+ }
+ });
}
}
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index aa9435b..719c2ae 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -25,12 +25,10 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.Rect;
import android.view.MotionEvent;
-import android.view.View;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -132,19 +130,6 @@
pa.addFloat(getDepthController(),
new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio, LINEAR);
-
- pa.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- LauncherTaskbarUIController taskbarUIController =
- activity.getTaskbarUIController();
- if (taskbarUIController != null) {
- // Launcher's ScrimView will draw the background throughout the gesture.
- taskbarUIController.forceHideBackground(true);
- }
- }
- });
-
}
};
@@ -366,16 +351,4 @@
return NORMAL;
}
}
-
- @Override
- public View onSettledOnEndTarget(@Nullable GestureEndTarget endTarget) {
- View superRet = super.onSettledOnEndTarget(endTarget);
- LauncherTaskbarUIController taskbarUIController = getTaskbarController();
- if (taskbarUIController != null) {
- // Start drawing taskbar's background again since launcher might stop drawing.
- taskbarUIController.forceHideBackground(false);
- return taskbarUIController.getRootView();
- }
- return superRet;
- }
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 22f67d2..d2373c9 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -37,12 +37,12 @@
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -206,10 +206,6 @@
@Override
public void onStateTransitionStart(RecentsState toState) {
- if (toState == HOME) {
- // Clean-up logic that occurs when recents is no longer in use/visible.
- reset();
- }
setOverviewStateEnabled(true);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.isFullScreen());
@@ -218,6 +214,10 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
+ if (finalState == HOME) {
+ // Clean-up logic that occurs when recents is no longer in use/visible.
+ reset();
+ }
boolean isOverlayEnabled = finalState == DEFAULT || finalState == MODAL_TASK;
setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index a2e9e57..d001690 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -92,10 +92,6 @@
@Override
public void onStateTransitionStart(LauncherState toState) {
- if (toState == NORMAL || toState == SPRING_LOADED) {
- // Clean-up logic that occurs when recents is no longer in use/visible.
- reset();
- }
setOverviewStateEnabled(toState.overviewUi);
setOverviewGridEnabled(toState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
setOverviewFullscreenEnabled(toState.getOverviewFullscreenProgress() == 1);
@@ -104,6 +100,10 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
+ if (finalState == NORMAL || finalState == SPRING_LOADED) {
+ // Clean-up logic that occurs when recents is no longer in use/visible.
+ reset();
+ }
boolean isOverlayEnabled = finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK;
setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4b9b8a4..e9010d2 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3118,14 +3118,10 @@
}
} else {
// Update focus task and its size.
- if (finalIsFocusedTaskDismissed) {
- if (finalNextFocusedTaskView != null) {
- mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
- mTopRowIdSet.remove(mFocusedTaskViewId);
- finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
- } else {
- mFocusedTaskViewId = -1;
- }
+ if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
+ mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
+ mTopRowIdSet.remove(mFocusedTaskViewId);
+ finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
updateTaskSize(/*isTaskDismissal=*/ true);
updateChildTaskOrientations();
@@ -3189,6 +3185,7 @@
}
}
}
+ pageBeginTransition();
setCurrentPage(pageToSnapTo);
// Update various scroll-dependent UI.
dispatchScrollChanged();
@@ -4019,6 +4016,7 @@
// * Focused Task
updateGridProperties();
resetFromSplitSelectionState();
+ updateScrollSynchronously();
}
});
@@ -4027,7 +4025,7 @@
/** TODO(b/181707736) More gracefully handle exiting split selection state */
private void resetFromSplitSelectionState() {
- if (!showAsGrid()) {
+ if (!mActivity.getDeviceProfile().overviewShowAsGrid) {
int pageToSnapTo = mCurrentPage;
if (mSplitHiddenTaskViewIndex <= pageToSnapTo) {
pageToSnapTo += 1;
@@ -4040,7 +4038,6 @@
resetTaskVisuals();
mSplitHiddenTaskViewIndex = -1;
if (mSplitHiddenTaskView != null) {
- mSplitHiddenTaskView.setTranslationY(0);
mSplitHiddenTaskView.setVisibility(VISIBLE);
mSplitHiddenTaskView = null;
}
@@ -4501,9 +4498,8 @@
}
private int getFirstViewIndex() {
- return mShowAsGridLastOnLayout && mFocusedTaskViewId != -1
- ? indexOfChild(getFocusedTaskView())
- : 0;
+ TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
+ return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
}
private int getLastViewIndex() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index f2836ca..ff19918 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -813,15 +813,23 @@
Point padding = getTotalWorkspacePadding();
int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
- int cellLayoutTotalPadding =
- isTwoPanels ? 4 * cellLayoutPaddingLeftRightPx : 2 * cellLayoutPaddingLeftRightPx;
- int screenWidthPx = availableWidthPx - padding.x - cellLayoutTotalPadding;
+ int screenWidthPx = getWorkspaceWidth(padding);
result.x = calculateCellWidth(screenWidthPx, cellLayoutBorderSpacePx.x, numColumns);
result.y = calculateCellHeight(availableHeightPx - padding.y
- cellLayoutBottomPaddingPx, cellLayoutBorderSpacePx.y, inv.numRows);
return result;
}
+ public int getWorkspaceWidth() {
+ return getWorkspaceWidth(getTotalWorkspacePadding());
+ }
+
+ public int getWorkspaceWidth(Point workspacePadding) {
+ int cellLayoutTotalPadding =
+ isTwoPanels ? 4 * cellLayoutPaddingLeftRightPx : 2 * cellLayoutPaddingLeftRightPx;
+ return availableWidthPx - workspacePadding.x - cellLayoutTotalPadding;
+ }
+
public Point getTotalWorkspacePadding() {
updateWorkspacePadding();
return new Point(workspacePadding.left + workspacePadding.right,
diff --git a/src/com/android/launcher3/anim/RevealOutlineAnimation.java b/src/com/android/launcher3/anim/RevealOutlineAnimation.java
index f99dabc..f5a746f 100644
--- a/src/com/android/launcher3/anim/RevealOutlineAnimation.java
+++ b/src/com/android/launcher3/anim/RevealOutlineAnimation.java
@@ -26,9 +26,27 @@
/** Sets the progress, from 0 to 1, of the reveal animation. */
abstract void setProgress(float progress);
+ /**
+ * @see #createRevealAnimator(View, boolean, float) where startProgress is set to 0.
+ */
public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed) {
- ValueAnimator va =
- isReversed ? ValueAnimator.ofFloat(1f, 0f) : ValueAnimator.ofFloat(0f, 1f);
+ return createRevealAnimator(revealView, isReversed, 0f /* startProgress */);
+ }
+
+ /**
+ * Animates the given View's ViewOutline according to {@link #setProgress(float)}.
+ * @param revealView The View whose outline we are animating.
+ * @param isReversed Whether we are hiding rather than revealing the View.
+ * @param startProgress The progress at which to start the newly created animation. Useful if
+ * the previous reveal animation was cancelled and we want to create a new animation where it
+ * left off. Note that if isReversed=true, we start at 1 - startProgress (and go to 0).
+ * @return The Animator, which the caller must start.
+ */
+ public ValueAnimator createRevealAnimator(final View revealView, boolean isReversed,
+ float startProgress) {
+ ValueAnimator va = isReversed
+ ? ValueAnimator.ofFloat(1f - startProgress, 0f)
+ : ValueAnimator.ofFloat(startProgress, 1f);
final float elevation = revealView.getElevation();
va.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 13ad90e..d3351dc 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -31,6 +31,8 @@
import android.util.ArraySet;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace;
@@ -215,6 +217,19 @@
}
public synchronized void addItem(Context context, ItemInfo item, boolean newItem) {
+ addItem(context, item, newItem, null);
+ }
+
+ public synchronized void addItem(
+ Context context, ItemInfo item, boolean newItem, @Nullable LoaderMemoryLogger logger) {
+ if (logger != null) {
+ logger.addLog(
+ Log.DEBUG,
+ TAG,
+ String.format("Adding item to ID map: %s", item.toString()),
+ /* stackTrace= */ null);
+ }
+
itemsIdMap.put(item.id, item);
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 47df538..08b38e8 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -383,18 +383,23 @@
info.cellY = getInt(cellYIndex);
}
+ public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
+ checkAndAddItem(info, dataModel, null);
+ }
+
/**
* Adds the {@param info} to {@param dataModel} if it does not overlap with any other item,
* otherwise marks it for deletion.
*/
- public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
+ public void checkAndAddItem(
+ ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) {
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
// Ensure that it is a valid intent. An exception here will
// cause the item loading to get skipped
ShortcutKey.fromItemInfo(info);
}
if (checkItemPlacement(info)) {
- dataModel.addItem(mContext, info, false);
+ dataModel.addItem(mContext, info, false, logger);
} else {
markDeleted("Item position overlap");
}
diff --git a/src/com/android/launcher3/model/LoaderMemoryLogger.java b/src/com/android/launcher3/model/LoaderMemoryLogger.java
new file mode 100644
index 0000000..f48efcb
--- /dev/null
+++ b/src/com/android/launcher3/model/LoaderMemoryLogger.java
@@ -0,0 +1,91 @@
+/*
+ * 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.model;
+
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Helper logger that collects logs while {@code LoaderTask#run} executes and prints them all iff
+ * an exception is caught in {@code LoaderTask#run}.
+ */
+public class LoaderMemoryLogger {
+
+ private static final String TAG = "LoaderMemoryLogger";
+
+ private final ArrayList<LogEntry> mLogEntries = new ArrayList<>();
+
+ protected LoaderMemoryLogger() {}
+
+ protected void addLog(int logLevel, String tag, String log) {
+ addLog(logLevel, tag, log, null);
+ }
+
+ protected void addLog(
+ int logLevel, String tag, String log, Exception stackTrace) {
+ switch (logLevel) {
+ case Log.ASSERT:
+ case Log.ERROR:
+ case Log.DEBUG:
+ case Log.INFO:
+ case Log.VERBOSE:
+ case Log.WARN:
+ mLogEntries.add(new LogEntry(logLevel, tag, log, stackTrace));
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid log level provided: " + logLevel);
+
+ }
+ }
+
+ protected void clearLogs() {
+ mLogEntries.clear();
+ }
+
+ protected void printLogs() {
+ for (LogEntry logEntry : mLogEntries) {
+ String tag = String.format("%s: %s", TAG, logEntry.mLogTag);
+ String logString = logEntry.mStackStrace == null
+ ? logEntry.mLogString
+ : String.format(
+ "%s\n%s",
+ logEntry.mLogString,
+ Log.getStackTraceString(logEntry.mStackStrace));
+
+ Log.println(logEntry.mLogLevel, tag, logString);
+ }
+ clearLogs();
+ }
+
+ private static class LogEntry {
+
+ protected final int mLogLevel;
+ protected final String mLogTag;
+ protected final String mLogString;
+ @Nullable protected final Exception mStackStrace;
+
+ protected LogEntry(
+ int logLevel, String logTag, String logString, @Nullable Exception stackStrace) {
+ mLogLevel = logLevel;
+ mLogTag = logTag;
+ mLogString = logString;
+ mStackStrace = stackStrace;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index a4f6f7a..2a0f9a6 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -52,6 +52,8 @@
import android.util.LongSparseArray;
import android.util.TimingLogger;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
@@ -197,11 +199,12 @@
Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
TimingLogger logger = new TimingLogger(TAG, "run");
+ LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
Trace.beginSection("LoadWorkspace");
try {
- loadWorkspace(allShortcuts);
+ loadWorkspace(allShortcuts, memoryLogger);
} finally {
Trace.endSection();
}
@@ -311,9 +314,13 @@
mModelDelegate.modelLoadComplete();
transaction.commit();
+ memoryLogger.clearLogs();
} catch (CancellationException e) {
// Loader stopped, ignore
logASplit(logger, "Cancelled");
+ } catch (Exception e) {
+ memoryLogger.printLogs();
+ throw e;
} finally {
logger.dumpToLog();
}
@@ -325,13 +332,21 @@
this.notify();
}
- private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
+ private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger logger) {
loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI,
- null /* selection */);
+ null /* selection */, logger);
}
- protected void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, Uri contentUri,
- String selection) {
+ protected void loadWorkspace(
+ List<ShortcutInfo> allDeepShortcuts, Uri contentUri, String selection) {
+ loadWorkspace(allDeepShortcuts, contentUri, selection, null);
+ }
+
+ protected void loadWorkspace(
+ List<ShortcutInfo> allDeepShortcuts,
+ Uri contentUri,
+ String selection,
+ @Nullable LoaderMemoryLogger logger) {
final Context context = mApp.getContext();
final ContentResolver contentResolver = context.getContentResolver();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -635,7 +650,7 @@
}
}
- c.checkAndAddItem(info, mBgDataModel);
+ c.checkAndAddItem(info, mBgDataModel, logger);
} else {
throw new RuntimeException("Unexpected null WorkspaceItemInfo");
}
@@ -654,7 +669,7 @@
// no special handling required for restored folders
c.markRestored();
- c.checkAndAddItem(folderInfo, mBgDataModel);
+ c.checkAndAddItem(folderInfo, mBgDataModel, logger);
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index d5479fb..3eb8cf1 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -212,7 +212,7 @@
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to get overview actions")) {
verifyActiveContainer();
- UiObject2 overviewActions = mLauncher.waitForLauncherObject("action_buttons");
+ UiObject2 overviewActions = mLauncher.waitForOverviewObject("action_buttons");
return new OverviewActions(overviewActions, mLauncher);
}
}
@@ -224,19 +224,16 @@
return mLauncher.hasLauncherObject(mLauncher.getOverviewObjectSelector("clear_all"));
}
- /* TODO(b/197630182): Once b/188790554 is fixed, remove instanceof check. Currently, when
- swiping from app to overview in Fallback Recents, taskbar remains and no action buttons
- are visible, so we are only testing Overview for now, not BaseOverview. */
private void verifyActionsViewVisibility() {
- if (!(this instanceof Overview) || !hasTasks()) {
+ if (!hasTasks()) {
return;
}
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to assert overview actions view visibility")) {
if (mLauncher.isTablet() && !isOverviewSnappedToFocusedTaskForTablet()) {
- mLauncher.waitUntilLauncherObjectGone("action_buttons");
+ mLauncher.waitUntilOverviewObjectGone("action_buttons");
} else {
- mLauncher.waitForLauncherObject("action_buttons");
+ mLauncher.waitForOverviewObject("action_buttons");
}
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 3485dd1..91b1bc7 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1029,6 +1029,10 @@
waitUntilGoneBySelector(getLauncherObjectSelector(resId));
}
+ void waitUntilOverviewObjectGone(String resId) {
+ waitUntilGoneBySelector(getOverviewObjectSelector(resId));
+ }
+
void waitUntilLauncherObjectGone(BySelector selector) {
waitUntilGoneBySelector(makeLauncherSelector(selector));
}