[automerger skipped] Merge "Merge Android 12L" am: 3a9bb04f93 -s ours am: f29e0a220b -s ours
am skip reason: Merged-In Icf0cc432ab3a97614b27efcf6fc9d18ea423a743 with SHA-1 11a0454879 is already in history
Original change: https://android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/2013193
Change-Id: If6d6bda6e649e84c6ff11fe8e43d12bd8b4be274
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 4269f2d..4ceb195 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -39,6 +39,7 @@
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.IBinder;
import android.view.View;
import android.view.WindowInsets;
import android.window.SplashScreen;
@@ -513,11 +514,26 @@
}
/**
- * Adds a new launch cookie for the activity launch of the given {@param info} if supported.
+ * Adds a new launch cookie for the activity launch if supported.
+ *
+ * @param info the item info for the launch
+ * @param opts the options to set the launchCookie on.
*/
public void addLaunchCookie(ItemInfo info, ActivityOptions opts) {
+ IBinder launchCookie = getLaunchCookie(info);
+ if (launchCookie != null) {
+ opts.setLaunchCookie(launchCookie);
+ }
+ }
+
+ /**
+ * Return a new launch cookie for the activity launch if supported.
+ *
+ * @param info the item info for the launch
+ */
+ public IBinder getLaunchCookie(ItemInfo info) {
if (info == null) {
- return;
+ return null;
}
switch (info.container) {
case LauncherSettings.Favorites.CONTAINER_DESKTOP:
@@ -531,8 +547,7 @@
break;
}
// Reset any existing launch cookies associated with the cookie
- opts.setLaunchCookie(ObjectWrapper.wrap(NO_MATCHING_ID));
- return;
+ return ObjectWrapper.wrap(NO_MATCHING_ID);
}
switch (info.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
@@ -543,10 +558,9 @@
break;
default:
// Reset any existing launch cookies associated with the cookie
- opts.setLaunchCookie(ObjectWrapper.wrap(NO_MATCHING_ID));
- return;
+ return ObjectWrapper.wrap(NO_MATCHING_ID);
}
- opts.setLaunchCookie(ObjectWrapper.wrap(new Integer(info.id)));
+ return ObjectWrapper.wrap(new Integer(info.id));
}
public void setHintUserWillBeActive() {
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 6e2fadd..49b2cc5 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -367,7 +367,7 @@
if (launcherClosing) {
// Delay animation by a frame to avoid jank.
Pair<AnimatorSet, Runnable> launcherContentAnimator =
- getLauncherContentAnimator(true /* isAppOpening */, startDelay);
+ getLauncherContentAnimator(true /* isAppOpening */, startDelay, false);
anim.play(launcherContentAnimator.first);
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -464,9 +464,10 @@
* @param isAppOpening True when this is called when an app is opening.
* False when this is called when an app is closing.
* @param startDelay Start delay duration.
+ * @param skipAllAppsScale True if we want to avoid scaling All Apps
*/
private Pair<AnimatorSet, Runnable> getLauncherContentAnimator(boolean isAppOpening,
- int startDelay) {
+ int startDelay, boolean skipAllAppsScale) {
AnimatorSet launcherAnimator = new AnimatorSet();
Runnable endListener;
@@ -484,7 +485,6 @@
final float startAlpha = appsView.getAlpha();
final float startScale = SCALE_PROPERTY.get(appsView);
appsView.setAlpha(alphas[0]);
- SCALE_PROPERTY.set(appsView, scales[0]);
ObjectAnimator alpha = ObjectAnimator.ofFloat(appsView, View.ALPHA, alphas);
alpha.setDuration(CONTENT_ALPHA_DURATION);
@@ -496,12 +496,16 @@
appsView.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
- ObjectAnimator scale = ObjectAnimator.ofFloat(appsView, SCALE_PROPERTY, scales);
- scale.setInterpolator(AGGRESSIVE_EASE);
- scale.setDuration(CONTENT_SCALE_DURATION);
+
+ if (!skipAllAppsScale) {
+ SCALE_PROPERTY.set(appsView, scales[0]);
+ ObjectAnimator scale = ObjectAnimator.ofFloat(appsView, SCALE_PROPERTY, scales);
+ scale.setInterpolator(AGGRESSIVE_EASE);
+ scale.setDuration(CONTENT_SCALE_DURATION);
+ launcherAnimator.play(scale);
+ }
launcherAnimator.play(alpha);
- launcherAnimator.play(scale);
endListener = () -> {
appsView.setAlpha(startAlpha);
@@ -1565,6 +1569,7 @@
|| mLauncher.getWorkspace().isOverlayShown();
boolean playWorkspaceReveal = true;
+ boolean skipAllAppsScale = false;
if (mFromUnlock) {
anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
} else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
@@ -1579,6 +1584,10 @@
true /* animateOverviewScrim */, launcherView).getAnimators());
// We play StaggeredWorkspaceAnim as a part of the closing window animation.
playWorkspaceReveal = false;
+ } else {
+ // Skip scaling all apps, otherwise FloatingIconView will get wrong
+ // layout bounds.
+ skipAllAppsScale = true;
}
} else {
anim.play(getFallbackClosingWindowAnimators(appTargets));
@@ -1600,7 +1609,8 @@
if (mLauncher.isInState(LauncherState.ALL_APPS)) {
Pair<AnimatorSet, Runnable> contentAnimator =
- getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY);
+ getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
+ skipAllAppsScale);
anim.play(contentAnimator.first);
anim.addListener(new AnimatorListenerAdapter() {
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5308a8f..3b6d5fb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -90,11 +90,12 @@
private static final String WINDOW_TITLE = "Taskbar";
- private final DeviceProfile mDeviceProfile;
private final LayoutInflater mLayoutInflater;
private final TaskbarDragLayer mDragLayer;
private final TaskbarControllers mControllers;
+ private DeviceProfile mDeviceProfile;
+
private final WindowManager mWindowManager;
private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
private final int mTaskbarHeightForIme;
@@ -125,10 +126,7 @@
Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
final Resources resources = getResources();
- float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size);
- mDeviceProfile.updateIconSize(1, resources);
- float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
- mDeviceProfile.updateIconSize(iconScale, resources);
+ updateIconSize(resources);
mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size);
@@ -211,6 +209,19 @@
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
}
+ /** Updates the Device profile instance to the latest representation of the screen. */
+ public void updateDeviceProfile(DeviceProfile dp) {
+ mDeviceProfile = dp;
+ updateIconSize(getResources());
+ }
+
+ private void updateIconSize(Resources resources) {
+ float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size);
+ mDeviceProfile.updateIconSize(1, resources);
+ float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
+ mDeviceProfile.updateIconSize(iconScale, resources);
+ }
+
public void onConfigurationChanged(@Config int configChanges) {
mControllers.onConfigurationChanged(configChanges);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index b3a9f8d..21d7411 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -145,7 +145,7 @@
PopupContainerWithArrow<TaskbarActivityContext> popupContainer =
mControllers.taskbarPopupController.showForIcon(btv);
if (popupContainer != null) {
- dragOptions.preDragCondition = popupContainer.createPreDragCondition();
+ dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 7a50d0b..be5ab55 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -207,59 +207,10 @@
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(isResumed && goingToUnstashedLauncherState()
- ? 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 && goingToUnstashedLauncherState()
- ? 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_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) {
- boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING);
- animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1)
- .setDuration(duration));
- }
-
+ // Add the state animation first to ensure FLAG_IN_STASHED_LAUNCHER_STATE is set and we can
+ // determine whether goingToUnstashedLauncherStateChanged.
+ boolean wasGoingToUnstashedLauncherState = goingToUnstashedLauncherState();
if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_RUNNING)) {
boolean committed = !hasAnyFlag(FLAG_TRANSITION_STATE_RUNNING);
playStateTransitionAnim(animatorSet, duration, committed);
@@ -270,6 +221,76 @@
applyState(0 /* duration */);
}
}
+ boolean goingToUnstashedLauncherStateChanged = wasGoingToUnstashedLauncherState
+ != goingToUnstashedLauncherState();
+
+ boolean launcherStateChangedDuringAnimToResumeAlignment =
+ mIconAlignmentForResumedState.isAnimating() && goingToUnstashedLauncherStateChanged;
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED)
+ || launcherStateChangedDuringAnimToResumeAlignment) {
+ boolean isResumed = isResumed();
+ float toAlignmentForResumedState = isResumed && goingToUnstashedLauncherState() ? 1 : 0;
+ // If we're already animating to the value, just leave it be instead of restarting it.
+ if (!mIconAlignmentForResumedState.isAnimatingToValue(toAlignmentForResumedState)) {
+ ObjectAnimator resumeAlignAnim = mIconAlignmentForResumedState
+ .animateToValue(toAlignmentForResumedState)
+ .setDuration(duration);
+
+ resumeAlignAnim.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(resumeAlignAnim);
+ }
+ }
+
+
+ boolean launcherStateChangedDuringAnimToGestureAlignment =
+ mIconAlignmentForGestureState.isAnimating() && goingToUnstashedLauncherStateChanged;
+ if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)
+ || launcherStateChangedDuringAnimToGestureAlignment) {
+ boolean isRecentsAnimationRunning = isRecentsAnimationRunning();
+ float toAlignmentForGestureState = isRecentsAnimationRunning
+ && goingToUnstashedLauncherState() ? 1 : 0;
+ // If we're already animating to the value, just leave it be instead of restarting it.
+ if (!mIconAlignmentForGestureState.isAnimatingToValue(toAlignmentForGestureState)) {
+ Animator gestureAlignAnim = mIconAlignmentForGestureState
+ .animateToValue(toAlignmentForGestureState);
+ if (isRecentsAnimationRunning) {
+ gestureAlignAnim.setDuration(duration);
+ }
+ gestureAlignAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = isRecentsAnimationRunning();
+ }
+ });
+ animatorSet.play(gestureAlignAnim);
+ }
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING)) {
+ boolean goingToLauncher = hasAnyFlag(FLAG_RESUMED | FLAG_RECENTS_ANIMATION_RUNNING);
+ animatorSet.play(mTaskbarBackgroundAlpha.animateToValue(goingToLauncher ? 0 : 1)
+ .setDuration(duration));
+ }
if (start) {
animatorSet.start();
@@ -310,8 +331,11 @@
animatorSet.play(stashAnimator);
}
- animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
- .setDuration(duration));
+ // If we're already animating to the value, just leave it be instead of restarting it.
+ if (!mIconAlignmentForLauncherState.isAnimatingToValue(toAlignment)) {
+ animatorSet.play(mIconAlignmentForLauncherState.animateToValue(toAlignment)
+ .setDuration(duration));
+ }
}
private boolean isResumed() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 3cdcdf7..bec717d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -110,6 +110,13 @@
} else {
// Config change might be handled without re-creating the taskbar
if (mTaskbarActivityContext != null) {
+ DeviceProfile dp = mUserUnlocked
+ ? LauncherAppState.getIDP(mContext).getDeviceProfile(mContext)
+ : null;
+
+ if (dp != null && dp.isTaskbarPresent) {
+ mTaskbarActivityContext.updateDeviceProfile(dp.copy(mContext));
+ }
mTaskbarActivityContext.onConfigurationChanged(configDiff);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 1cf50f7..ed71562 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -21,6 +21,7 @@
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.content.Intent;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
@@ -58,6 +59,12 @@
Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
.getActivityLaunchOptions(hostView);
+ Object itemInfo = hostView.getTag();
+ IBinder launchCookie = null;
+ if (itemInfo instanceof ItemInfo) {
+ launchCookie = mLauncher.getLaunchCookie((ItemInfo) itemInfo);
+ activityOptions.options.setLaunchCookie(launchCookie);
+ }
if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) {
// In the event this pending intent eventually launches an activity, i.e. a trampoline,
// use the Quickstep transition animation.
@@ -65,17 +72,14 @@
ActivityTaskManager.getService()
.registerRemoteAnimationForNextActivityStart(
pendingIntent.getCreatorPackage(),
- activityOptions.options.getRemoteAnimationAdapter());
+ activityOptions.options.getRemoteAnimationAdapter(),
+ launchCookie);
} catch (RemoteException e) {
// Do nothing.
}
}
activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_EMPTY);
- Object itemInfo = hostView.getTag();
- if (itemInfo instanceof ItemInfo) {
- mLauncher.addLaunchCookie((ItemInfo) itemInfo, activityOptions.options);
- }
options = Pair.create(options.first, activityOptions.options);
if (pendingIntent.isActivity()) {
logAppLaunch(itemInfo);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9f1e47f..2f52c9d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -249,6 +249,8 @@
private RunningWindowAnim[] mRunningWindowAnim;
// Possible second animation running at the same time as mRunningWindowAnim
private Animator mParallelRunningAnim;
+ // Current running divider animation
+ private ValueAnimator mDividerAnimator;
private boolean mIsMotionPaused;
private boolean mHasMotionEverBeenPaused;
@@ -831,8 +833,8 @@
// Notify when the animation starts
flushOnRecentsAnimationAndLauncherBound();
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- false /*shown*/, true /*animate*/);
+ // Start hiding the divider
+ setDividerShown(false, false /* immediate */);
// Only add the callback to enable the input consumer after we actually have the controller
mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
@@ -849,8 +851,7 @@
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, true /*animate*/);
+ setDividerShown(true, false /* immediate */);
}
// Defer clearing the controller and the targets until after we've updated the state
@@ -1000,8 +1001,7 @@
mStateCallback.setState(STATE_RESUME_LAST_TASK);
}
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, false /*animate*/);
+ setDividerShown(true, true /* immediate */);
}
break;
}
@@ -1653,8 +1653,7 @@
mActivityInterface.onTransitionCancelled(wasVisible, mGestureState.getEndTarget());
if (mRecentsAnimationTargets != null) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, false /*animate*/);
+ setDividerShown(true, true /* immediate */);
}
// Leave the pending invisible flag, as it may be used by wallpaper open animation.
@@ -1920,8 +1919,7 @@
@Override
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
if (!controller.getFinishTargetIsLauncher()) {
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRecentsAnimationTargets.nonApps,
- true /*shown*/, true /*animate*/);
+ setDividerShown(true, false /* immediate */);
}
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
@@ -2026,6 +2024,19 @@
return scaleProgress;
}
+ private void setDividerShown(boolean shown, boolean immediate) {
+ if (mDividerAnimator != null) {
+ mDividerAnimator.cancel();
+ }
+ mDividerAnimator = TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+ mRecentsAnimationTargets.nonApps, shown, (dividerAnimator) -> {
+ dividerAnimator.start();
+ if (immediate) {
+ dividerAnimator.end();
+ }
+ });
+ }
+
/**
* Used for winscope tracing, see launcher_trace.proto
* @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 95c8710..6a7d066 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -42,6 +42,8 @@
private final Runnable mUpdateCallback;
private ObjectAnimator mValueAnimator;
+ // Only non-null when an animation is playing to this value.
+ private Float mEndValue;
public float value;
@@ -68,9 +70,17 @@
mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end);
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animator) {
+ if (mValueAnimator == animator) {
+ mEndValue = end;
+ }
+ }
+
+ @Override
public void onAnimationEnd(Animator animator) {
if (mValueAnimator == animator) {
mValueAnimator = null;
+ mEndValue = null;
}
}
});
@@ -103,4 +113,15 @@
public ObjectAnimator getCurrentAnimation() {
return mValueAnimator;
}
+
+ public boolean isAnimating() {
+ return mValueAnimator != null;
+ }
+
+ /**
+ * Returns whether we are currently animating, and the animation's end value matches the given.
+ */
+ public boolean isAnimatingToValue(float endValue) {
+ return isAnimating() && mEndValue != null && mEndValue == endValue;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java
index 0b09323..c455dc7 100644
--- a/quickstep/src/com/android/quickstep/InputConsumer.java
+++ b/quickstep/src/com/android/quickstep/InputConsumer.java
@@ -99,6 +99,8 @@
default void onMotionEvent(MotionEvent ev) { }
+ default void onHoverEvent(MotionEvent ev) { }
+
default void onKeyEvent(KeyEvent ev) { }
default void onInputEvent(InputEvent ev) {
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 75e8dd1..17baa3a 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -38,6 +38,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
@@ -271,6 +272,14 @@
scheduleNextTask(cmd);
}
+ public void dump(PrintWriter pw) {
+ pw.println("OverviewCommandHelper:");
+ pw.println(" mPendingCommands=" + mPendingCommands.size());
+ if (!mPendingCommands.isEmpty()) {
+ pw.println(" pendingCommandType=" + mPendingCommands.get(0).type);
+ }
+ }
+
private static class CommandInfo {
public final long createTime = SystemClock.elapsedRealtime();
public final int type;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 103f350..1dc4933 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -99,6 +99,7 @@
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private static final long HOME_APPEAR_DURATION = 250;
+ private static final long RECENTS_ANIMATION_TIMEOUT = 1000;
private RecentsDragLayer mDragLayer;
private ScrimView mScrimView;
@@ -115,6 +116,11 @@
// Strong refs to runners which are cleared when the activity is destroyed
private RemoteAnimationFactory mActivityLaunchAnimationRunner;
+ // For handling degenerate cases where starting an activity doesn't actually trigger the remote
+ // animation callback
+ private final Handler mHandler = new Handler();
+ private final Runnable mAnimationStartTimeoutRunnable = this::onAnimationStartTimeout;
+
/**
* Init drag layer and overview panel views.
*/
@@ -219,6 +225,16 @@
// TODO(b/137318995) This should go home, but doing so removes freeform windows
}
+ /**
+ * Called if the remote animation callback from #getActivityLaunchOptions() hasn't called back
+ * in a reasonable time due to a conflict with the recents animation.
+ */
+ private void onAnimationStartTimeout() {
+ if (mActivityLaunchAnimationRunner != null) {
+ mActivityLaunchAnimationRunner.onAnimationCancelled();
+ }
+ }
+
@Override
public ActivityOptionsWrapper getActivityLaunchOptions(final View v, @Nullable ItemInfo item) {
if (!(v instanceof TaskView)) {
@@ -233,6 +249,7 @@
public void onCreateAnimation(int transit, RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
RemoteAnimationTargetCompat[] nonAppTargets, AnimationResult result) {
+ mHandler.removeCallbacks(mAnimationStartTimeoutRunnable);
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets, nonAppTargets);
anim.addListener(resetStateListener());
@@ -242,6 +259,7 @@
@Override
public void onAnimationCancelled() {
+ mHandler.removeCallbacks(mAnimationStartTimeoutRunnable);
onEndCallback.executeAllAndDestroy();
}
};
@@ -256,6 +274,7 @@
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat),
onEndCallback);
activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
+ mHandler.postDelayed(mAnimationStartTimeoutRunnable, RECENTS_ANIMATION_TIMEOUT);
return activityOptions;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 73d1424..99a02e1 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -554,15 +554,13 @@
/**
* @param ev An ACTION_DOWN motion event
- * @param task Info for the currently running task
* @return whether the given motion event can trigger the assistant over the current task.
*/
- public boolean canTriggerAssistantAction(MotionEvent ev, ActivityManager.RunningTaskInfo task) {
+ public boolean canTriggerAssistantAction(MotionEvent ev) {
return mAssistantAvailable
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
&& mRotationTouchHelper.touchInAssistantRegion(ev)
- && !isLockToAppActive()
- && !isGestureBlockedActivity(task);
+ && !isLockToAppActive();
}
/**
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 5d9a537..30e225a 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -85,6 +85,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -538,8 +539,16 @@
nonAppTargets, depthController, pa);
if (launcherClosing) {
// TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
- TaskViewUtils.setSplitAuxiliarySurfacesShown(nonAppTargets,
- true /*shown*/, true /*animate*/, pa);
+ TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, true /*shown*/,
+ (dividerAnimator) -> {
+ // If split apps are launching, we want to delay showing the divider bar
+ // until the very end once the apps are mostly in place. This is because we
+ // aren't moving the divider leash in the relative position with the
+ // launching apps.
+ dividerAnimator.setStartDelay(pa.getDuration()
+ - SPLIT_DIVIDER_ANIM_DURATION);
+ pa.add(dividerAnimator);
+ });
}
Animator childStateAnimation = null;
@@ -594,16 +603,17 @@
anim.addListener(windowAnimEndListener);
}
- public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
- boolean shown, boolean animate) {
- setSplitAuxiliarySurfacesShown(nonApps, shown, animate,null);
- }
-
- private static void setSplitAuxiliarySurfacesShown(
- @NonNull RemoteAnimationTargetCompat[] nonApps, boolean shown, boolean animate,
- @Nullable PendingAnimation splitLaunchAnimation) {
+ /**
+ * Creates an animation to show/hide the auxiliary surfaces (aka. divider bar), only calling
+ * {@param animatorHandler} if there are valid surfaces to animate.
+ *
+ * @return the animator animating the surfaces
+ */
+ public static ValueAnimator createSplitAuxiliarySurfacesAnimator(
+ RemoteAnimationTargetCompat[] nonApps, boolean shown,
+ Consumer<ValueAnimator> animatorHandler) {
if (nonApps == null || nonApps.length == 0) {
- return;
+ return null;
}
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -618,20 +628,7 @@
}
}
if (!hasSurfaceToAnimate) {
- return;
- }
-
- if (!animate) {
- for (SurfaceControl leash : auxiliarySurfaces) {
- t.setAlpha(leash, shown ? 1 : 0);
- if (shown) {
- t.show(leash);
- } else {
- t.hide(leash);
- }
- }
- t.apply();
- return;
+ return null;
}
ValueAnimator dockFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
@@ -668,15 +665,7 @@
}
});
dockFadeAnimator.setDuration(SPLIT_DIVIDER_ANIM_DURATION);
- if (splitLaunchAnimation != null) {
- // If split apps are launching, we want to delay showing the divider bar until the very
- // end once the apps are mostly in place. This is because we aren't moving the divider
- // leash in the relative position with the launching apps.
- dockFadeAnimator.setStartDelay(
- splitLaunchAnimation.getDuration() - SPLIT_DIVIDER_ANIM_DURATION);
- splitLaunchAnimation.add(dockFadeAnimator);
- } else {
- dockFadeAnimator.start();
- }
+ animatorHandler.accept(dockFadeAnimator);
+ return dockFadeAnimator;
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 539239d..af8fec2 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -37,7 +37,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import android.annotation.TargetApi;
-import android.app.ActivityManager;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
@@ -600,26 +599,14 @@
ActiveGestureLog.INSTANCE.addLog("setInputConsumer: " + mConsumer.getName());
mUncheckedConsumer = mConsumer;
- } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()) {
+ } else if (mDeviceState.isUserUnlocked() && mDeviceState.isFullyGesturalNavMode()
+ && mDeviceState.canTriggerAssistantAction(event)) {
mGestureState = createGestureState(mGestureState);
- ActivityManager.RunningTaskInfo runningTask = mGestureState.getRunningTask();
- if (mDeviceState.canTriggerAssistantAction(event, runningTask)) {
- // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
- // should not interrupt it. QuickSwitch assumes that interruption can only
- // happen if the next gesture is also quick switch.
- mUncheckedConsumer = new AssistantInputConsumer(
- this,
- mGestureState,
- InputConsumer.NO_OP, mInputMonitorCompat,
- mDeviceState,
- event);
- } else if (mDeviceState.canTriggerOneHandedAction(event)) {
- // Consume gesture event for triggering one handed feature.
- mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
- InputConsumer.NO_OP, mInputMonitorCompat);
- } else {
- mUncheckedConsumer = InputConsumer.NO_OP;
- }
+ // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we
+ // should not interrupt it. QuickSwitch assumes that interruption can only
+ // happen if the next gesture is also quick switch.
+ mUncheckedConsumer = tryCreateAssistantInputConsumer(
+ InputConsumer.NO_OP, mGestureState, event);
} else if (mDeviceState.canTriggerOneHandedAction(event)) {
// Consume gesture event for triggering one handed feature.
mUncheckedConsumer = new OneHandedModeInputConsumer(this, mDeviceState,
@@ -666,6 +653,14 @@
ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
}
+ private InputConsumer tryCreateAssistantInputConsumer(InputConsumer base,
+ GestureState gestureState, MotionEvent motionEvent) {
+ return mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())
+ ? base
+ : new AssistantInputConsumer(this, gestureState, base, mInputMonitorCompat,
+ mDeviceState, motionEvent);
+ }
+
public GestureState createGestureState(GestureState previousGestureState) {
GestureState gestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.generateAndSetLogId());
@@ -711,9 +706,8 @@
handleOrientationSetup(base);
}
if (mDeviceState.isFullyGesturalNavMode()) {
- if (mDeviceState.canTriggerAssistantAction(event, newGestureState.getRunningTask())) {
- base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat,
- mDeviceState, event);
+ if (mDeviceState.canTriggerAssistantAction(event)) {
+ base = tryCreateAssistantInputConsumer(base, newGestureState, event);
}
// If Taskbar is present, we listen for long press to unstash it.
@@ -967,6 +961,9 @@
if (mOverviewComponentObserver != null) {
mOverviewComponentObserver.dump(pw);
}
+ if (mOverviewCommandHelper != null) {
+ mOverviewCommandHelper.dump(pw);
+ }
if (mGestureState != null) {
mGestureState.dump(pw);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index b0df286..02ac48e 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -101,6 +101,13 @@
}
@Override
+ public void onHoverEvent(MotionEvent ev) {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ mActivity.dispatchGenericMotionEvent(ev);
+ }
+ }
+
+ @Override
public void onKeyEvent(KeyEvent ev) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
switch (ev.getKeyCode()) {
diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
index c2101a8..91b53c7 100644
--- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
@@ -71,7 +71,16 @@
private boolean onInputConsumerEvent(InputEvent ev) {
if (ev instanceof MotionEvent) {
- onInputConsumerMotionEvent((MotionEvent) ev);
+ MotionEvent event = (MotionEvent) ev;
+ int action = event.getActionMasked();
+ boolean isHoverEvent = action == MotionEvent.ACTION_HOVER_ENTER
+ || action == MotionEvent.ACTION_HOVER_MOVE
+ || action == MotionEvent.ACTION_HOVER_EXIT;
+ if (isHoverEvent) {
+ onInputConsumerHoverEvent(event);
+ } else {
+ onInputConsumerMotionEvent(event);
+ }
} else if (ev instanceof KeyEvent) {
initInputConsumerIfNeeded();
mInputConsumer.onKeyEvent((KeyEvent) ev);
@@ -113,6 +122,15 @@
return true;
}
+ private void onInputConsumerHoverEvent(MotionEvent ev) {
+ initInputConsumerIfNeeded();
+ if (mInputConsumer != null) {
+ SimpleOrientationTouchTransformer.INSTANCE.get(mContext).transform(ev,
+ mRotationSupplier.get());
+ mInputConsumer.onHoverEvent(ev);
+ }
+ }
+
public void destroy() {
if (mTouchInProgress) {
mDestroyPending = true;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 02261af..7218cd7 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -984,13 +984,17 @@
*/
public void launchSideTaskInLiveTileModeForRestartedApp(int taskId) {
int runningTaskViewId = getTaskViewIdFromTaskId(taskId);
- if (mRunningTaskViewId != -1 && mRunningTaskViewId == runningTaskViewId) {
- TransformParams params = mRemoteTargetHandles[0].getTransformParams();
- RemoteAnimationTargets targets = params.getTargetSet();
- if (targets != null && targets.findTask(taskId) != null) {
- launchSideTaskInLiveTileMode(taskId, targets.apps, targets.wallpapers,
- targets.nonApps);
- }
+ if (mRunningTaskViewId == -1 ||
+ mRunningTaskViewId != runningTaskViewId ||
+ mRemoteTargetHandles == null) {
+ return;
+ }
+
+ TransformParams params = mRemoteTargetHandles[0].getTransformParams();
+ RemoteAnimationTargets targets = params.getTargetSet();
+ if (targets != null && targets.findTask(taskId) != null) {
+ launchSideTaskInLiveTileMode(taskId, targets.apps, targets.wallpapers,
+ targets.nonApps);
}
}
@@ -4139,8 +4143,10 @@
anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex),
mOrientationHandler.getPrimaryViewTranslate(), primaryTranslation));
int runningTaskIndex = recentsView.getRunningTaskIndex();
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() && runningTaskIndex != -1
- && runningTaskIndex != taskIndex) {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()
+ && runningTaskIndex != -1
+ && runningTaskIndex != taskIndex
+ && recentsView.getRemoteTargetHandles() != null) {
for (RemoteTargetHandle remoteHandle : recentsView.getRemoteTargetHandles()) {
anim.play(ObjectAnimator.ofFloat(
remoteHandle.getTaskViewSimulator().taskPrimaryTranslation,
@@ -4235,9 +4241,12 @@
if (isSuccess) {
if (tv.getTaskIds()[1] != -1) {
// TODO(b/194414938): make this part of the animations instead.
- TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0]
- .getTransformParams().getTargetSet().nonApps,
- true /*shown*/, false /*animate*/);
+ TaskViewUtils.createSplitAuxiliarySurfacesAnimator(
+ mRemoteTargetHandles[0].getTransformParams().getTargetSet().nonApps,
+ true /*shown*/, (dividerAnimator) -> {
+ dividerAnimator.start();
+ dividerAnimator.end();
+ });
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
finishRecentsAnimation(false /* toRecents */, null);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 6a2c997e..d046fef 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -462,11 +462,15 @@
return getItemInfo(mTask);
}
- protected WorkspaceItemInfo getItemInfo(Task task) {
- ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key);
+ protected WorkspaceItemInfo getItemInfo(@Nullable Task task) {
WorkspaceItemInfo stubInfo = new WorkspaceItemInfo();
stubInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK;
stubInfo.container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER;
+ if (task == null) {
+ return stubInfo;
+ }
+
+ ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key);
stubInfo.user = componentKey.user;
stubInfo.intent = new Intent().setComponent(componentKey.componentName);
stubInfo.title = task.title;
diff --git a/res/color-night-v31/accent_ripple_color.xml b/res/color-night-v31/accent_ripple_color.xml
new file mode 100644
index 0000000..cb149d6
--- /dev/null
+++ b/res/color-night-v31/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_accent1_300"/>
+</selector>
\ No newline at end of file
diff --git a/res/color-night/accent_ripple_color.xml b/res/color-night/accent_ripple_color.xml
new file mode 100644
index 0000000..4a37b00
--- /dev/null
+++ b/res/color-night/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#53BCAC"/>
+</selector>
\ No newline at end of file
diff --git a/res/color-v31/accent_ripple_color.xml b/res/color-v31/accent_ripple_color.xml
new file mode 100644
index 0000000..a996228
--- /dev/null
+++ b/res/color-v31/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_accent2_50"/>
+</selector>
\ No newline at end of file
diff --git a/res/color/accent_ripple_color.xml b/res/color/accent_ripple_color.xml
new file mode 100644
index 0000000..697f415
--- /dev/null
+++ b/res/color/accent_ripple_color.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#CDFAF1"/>
+</selector>
\ No newline at end of file
diff --git a/res/drawable/all_apps_tabs_background.xml b/res/drawable/all_apps_tabs_background.xml
index aea2e7a..8471cd4 100644
--- a/res/drawable/all_apps_tabs_background.xml
+++ b/res/drawable/all_apps_tabs_background.xml
@@ -13,23 +13,36 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:enterFadeDuration="100">
- <item
- android:id="@+id/unselected"
- android:state_selected="false">
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/accent_ripple_color">
+
+ <item android:id="@android:id/mask">
<shape android:shape="rectangle">
<corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="@color/all_apps_tabs_background" />
+ <solid android:color="@color/accent_ripple_color" />
</shape>
</item>
- <item
- android:id="@+id/selected"
- android:state_selected="true">
- <shape android:shape="rectangle">
- <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- <solid android:color="@color/all_apps_tab_background_selected" />
- </shape>
+ <item>
+ <selector android:enterFadeDuration="100">
+ <item
+ android:id="@+id/unselected"
+ android:state_selected="false">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+ <solid android:color="@color/all_apps_tabs_background" />
+ </shape>
+ </item>
+
+ <item
+ android:id="@+id/selected"
+ android:state_selected="true">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+ <solid android:color="@color/all_apps_tab_background_selected" />
+ </shape>
+ </item>
+ </selector>
</item>
-</selector>
\ No newline at end of file
+
+</ripple>
\ No newline at end of file
diff --git a/res/drawable/personal_work_tabs_ripple.xml b/res/drawable/personal_work_tabs_ripple.xml
deleted file mode 100644
index 2e57b80..0000000
--- a/res/drawable/personal_work_tabs_ripple.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight">
- <shape android:shape="rectangle">
- <solid android:color="@android:color/transparent" />
- <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
- </shape>
-</ripple>
\ No newline at end of file
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 1f1d57a..163b442 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -35,6 +35,7 @@
import android.graphics.drawable.Drawable;
import android.icu.text.MessageFormat;
import android.text.TextPaint;
+import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Property;
@@ -785,7 +786,7 @@
invalidate();
}
}
- if (itemInfo.contentDescription != null) {
+ if (!TextUtils.isEmpty(itemInfo.contentDescription)) {
if (itemInfo.isDisabled()) {
setContentDescription(getContext().getString(R.string.disabled_app_label,
itemInfo.contentDescription));
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index d2fe483..63313f7 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -460,9 +460,10 @@
* Trims the string, removing all whitespace at the beginning and end of the string.
* Non-breaking whitespaces are also removed.
*/
+ @NonNull
public static String trim(CharSequence s) {
if (s == null) {
- return null;
+ return "";
}
// Just strip any sequence of whitespace or java space characters from the beginning and end
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 281dfea..c8dd003 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1686,7 +1686,7 @@
PopupContainerWithArrow<Launcher> popupContainer = PopupContainerWithArrow
.showForIcon((BubbleTextView) child);
if (popupContainer != null) {
- dragOptions.preDragCondition = popupContainer.createPreDragCondition();
+ dragOptions.preDragCondition = popupContainer.createPreDragCondition(true);
}
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 08b38e8..178fbdb 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -202,8 +202,7 @@
* Returns the title or empty string
*/
private String getTitle() {
- String title = getString(titleIndex);
- return TextUtils.isEmpty(title) ? "" : Utilities.trim(title);
+ return Utilities.trim(getString(titleIndex));
}
/**
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index b963950..6d2b12f 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -396,7 +396,7 @@
* Current behavior:
* - Start the drag if the touch passes a certain distance from the original touch down.
*/
- public DragOptions.PreDragCondition createPreDragCondition() {
+ public DragOptions.PreDragCondition createPreDragCondition(boolean updateIconUi) {
return new DragOptions.PreDragCondition() {
@Override
@@ -406,6 +406,9 @@
@Override
public void onPreDragStart(DropTarget.DragObject dragObject) {
+ if (!updateIconUi) {
+ return;
+ }
if (mIsAboveIcon) {
// Hide only the icon, keep the text visible.
mOriginalIcon.setIconVisible(false);
@@ -418,6 +421,9 @@
@Override
public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
+ if (!updateIconUi) {
+ return;
+ }
mOriginalIcon.setIconVisible(true);
if (dragStarted) {
// Make sure we keep the original icon hidden while it is being dragged.
@@ -480,6 +486,9 @@
@Override
protected void closeComplete() {
super.closeComplete();
+ if (mActivityContext.getDragController() != null) {
+ mActivityContext.getDragController().removeDragListener(this);
+ }
PopupContainerWithArrow openPopup = getOpen(mActivityContext);
if (openPopup == null || openPopup.mOriginalIcon != mOriginalIcon) {
mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index dc3ee43..0a800c3 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -564,6 +564,12 @@
launcher, parent);
view.recycle();
+ // Init properties before getting the drawable.
+ view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
+ view.mIsOpening = isOpening;
+ view.mOriginalIcon = originalView;
+ view.mPositionOut = positionOut;
+
// Get the drawable on the background thread
boolean shouldLoadIcon = originalView.getTag() instanceof ItemInfo && hideOriginal;
if (shouldLoadIcon) {
@@ -577,11 +583,6 @@
}
sIconLoadResult = null;
- view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
- view.mIsOpening = isOpening;
- view.mOriginalIcon = originalView;
- view.mPositionOut = positionOut;
-
// Match the position of the original view.
view.matchPositionOf(launcher, originalView, isOpening, positionOut);
@@ -639,6 +640,7 @@
mLoadIconSignal = null;
mEndRunnable = null;
mFinalDrawableBounds.setEmpty();
+ mIsOpening = false;
mPositionOut = null;
mListenerView.setListener(null);
mOriginalIcon = null;