Merge "Use aconfig flag for desktop mode" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 7c6d7a8..ace2210 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -48,3 +48,10 @@
description: "Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext."
bug: "299193589"
}
+
+flag {
+ name: "enable_home_transition_listener"
+ namespace: "launcher"
+ description: "Enables launcher to listen to all transitions that include home activity"
+ bug: "306053414"
+}
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index f8b08f8..dde69e3 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -135,7 +135,7 @@
}
}
-// Next value 52
+// Next value 53
enum Attribute {
option allow_alias = true;
@@ -188,6 +188,7 @@
ALL_APPS_SEARCH_RESULT_EDUCARD = 43;
ALL_APPS_SEARCH_RESULT_LOCATION = 50;
ALL_APPS_SEARCH_RESULT_TEXT_HEADER = 51;
+ ALL_APPS_SEARCH_RESULT_NO_FULFILLMENT = 52;
// Result sources
DATA_SOURCE_APPSEARCH_APP_PREVIEW = 45;
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index c5d0b95..e77d2c6 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1057,9 +1057,9 @@
boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW
&& BlurUtils.supportsBlursOnWindows();
- ObjectAnimator backgroundRadiusAnim =
- ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
- MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mLauncher))
+ LaunchDepthController depthController = new LaunchDepthController(mLauncher);
+ ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController.stateDepth,
+ MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mLauncher))
.setDuration(APP_LAUNCH_DURATION);
if (allowBlurringLauncher) {
@@ -1085,6 +1085,9 @@
new SurfaceControl.Transaction().remove(dimLayer).apply()));
}
+ backgroundRadiusAnim.addListener(
+ AnimatorListeners.forEndCallback(depthController::dispose));
+
return backgroundRadiusAnim;
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 957db64..882682d 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -94,6 +94,18 @@
}
}
+ /**
+ * Cleans up after this controller so it can be garbage collected without leaving traces.
+ */
+ public void dispose() {
+ removeSecondaryListeners();
+
+ if (mLauncher.getRootView() != null && mOnAttachListener != null) {
+ mLauncher.getRootView().removeOnAttachStateChangeListener(mOnAttachListener);
+ mOnAttachListener = null;
+ }
+ }
+
private void removeSecondaryListeners() {
if (mCrossWindowBlurListener != null) {
CrossWindowBlurListeners.getInstance().removeListener(mCrossWindowBlurListener);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 445a1bd..09376d7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_HOME_TRANSITION_LISTENER;
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
@@ -39,6 +38,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
@@ -101,7 +101,7 @@
mLauncher.setTaskbarUIController(this);
- if (!ENABLE_HOME_TRANSITION_LISTENER.get()) {
+ if (!FeatureFlags.enableHomeTransitionListener()) {
onLauncherVisibilityChanged(mLauncher.hasBeenResumed(), true /* fromInit */);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 6aadd65..6ee151b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -129,6 +129,7 @@
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Optional;
+import java.util.function.Consumer;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
@@ -299,38 +300,31 @@
* the icon size
*/
private void applyDeviceProfile(DeviceProfile originDeviceProfile) {
- mDeviceProfile = originDeviceProfile.toBuilder(this)
- .withDimensionsOverride(deviceProfile -> {
- // Taskbar should match the number of icons of hotseat
- deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
- // Same QSB width to have a smooth animation
- deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
+ Consumer<DeviceProfile> overrideProvider = deviceProfile -> {
+ // Taskbar should match the number of icons of hotseat
+ deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
+ // Same QSB width to have a smooth animation
+ deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
- // Update icon size
- deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
- deviceProfile.updateIconSize(1f, getResources());
- }).build();
+ // Update icon size
+ deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
+ deviceProfile.updateIconSize(1f, getResources());
+ };
+ mDeviceProfile = originDeviceProfile.toBuilder(this)
+ .withDimensionsOverride(overrideProvider).build();
if (DisplayController.isTransientTaskbar(this)) {
mTransientTaskbarDeviceProfile = mDeviceProfile;
mPersistentTaskbarDeviceProfile = mDeviceProfile
.toBuilder(this)
- .withDimensionsOverride(deviceProfile -> {
- // Update icon size
- deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
- deviceProfile.updateIconSize(1f, getResources());
- })
+ .withDimensionsOverride(overrideProvider)
.setIsTransientTaskbar(false)
.build();
} else {
mPersistentTaskbarDeviceProfile = mDeviceProfile;
mTransientTaskbarDeviceProfile = mDeviceProfile
.toBuilder(this)
- .withDimensionsOverride(deviceProfile -> {
- // Update icon size
- deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
- deviceProfile.updateIconSize(1f, getResources());
- })
+ .withDimensionsOverride(overrideProvider)
.setIsTransientTaskbar(true)
.build();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index e4ebf65..d6016f1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -32,6 +32,7 @@
import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT
import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT
import com.android.launcher3.util.DisplayController
+import kotlin.math.min
/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
@@ -153,9 +154,10 @@
// Draw the background behind taskbar content.
canvas.drawRect(0f, 0f, canvas.width.toFloat(), persistentTaskbarHeight, paint)
} else {
- canvas.translate(0f, canvas.height - maxPersistentTaskbarHeight)
+ val persistentTaskbarHeight = min(maxPersistentTaskbarHeight, backgroundHeight)
+ canvas.translate(0f, canvas.height - persistentTaskbarHeight)
// Draw the background behind taskbar content.
- canvas.drawRect(0f, 0f, canvas.width.toFloat(), maxPersistentTaskbarHeight, paint)
+ canvas.drawRect(0f, 0f, canvas.width.toFloat(), persistentTaskbarHeight, paint)
}
// Draw the inverted rounded corners above the taskbar.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index d4f42d8..267b15c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -206,7 +206,9 @@
updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, false);
// TODO(b/279514548) Cleans up bad state that can occur when user interacts with
// taskbar on top of transparent activity.
- if (finalState == LauncherState.NORMAL && mLauncher.hasBeenResumed()) {
+ if (!FeatureFlags.enableHomeTransitionListener()
+ && finalState == LauncherState.NORMAL
+ && mLauncher.hasBeenResumed()) {
updateStateForFlag(FLAG_VISIBLE, true);
}
applyState();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index b500c3e..9bb7e67 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -21,6 +21,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
@@ -30,7 +31,6 @@
import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
import android.annotation.SuppressLint;
-import android.app.Activity;
import android.app.PendingIntent;
import android.content.ComponentCallbacks;
import android.content.Context;
@@ -61,7 +61,6 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
@@ -145,27 +144,25 @@
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
- private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
- new ActivityLifecycleCallbacksAdapter() {
- @Override
- public void onActivityDestroyed(Activity activity) {
- if (mActivity != activity) return;
- if (mActivity != null) {
- mActivity.removeOnDeviceProfileChangeListener(
- mDebugActivityDeviceProfileChanged);
- Log.d(TASKBAR_NOT_DESTROYED_TAG,
- "unregistering activity lifecycle callbacks from "
- + "onActivityDestroyed.");
- mActivity.unregisterActivityLifecycleCallbacks(this);
- }
- mActivity = null;
- debugWhyTaskbarNotDestroyed("clearActivity");
- if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
- }
- mUnfoldProgressProvider.setSourceProvider(null);
- }
- };
+ private final Runnable mActivityOnDestroyCallback = new Runnable() {
+ @Override
+ public void run() {
+ if (mActivity != null) {
+ mActivity.removeOnDeviceProfileChangeListener(
+ mDebugActivityDeviceProfileChanged);
+ Log.d(TASKBAR_NOT_DESTROYED_TAG,
+ "unregistering activity lifecycle callbacks from "
+ + "onActivityDestroyed.");
+ mActivity.removeEventCallback(EVENT_DESTROYED, this);
+ }
+ mActivity = null;
+ debugWhyTaskbarNotDestroyed("clearActivity");
+ if (mTaskbarActivityContext != null) {
+ mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT);
+ }
+ mUnfoldProgressProvider.setSourceProvider(null);
+ }
+ };
UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
new UnfoldTransitionProgressProvider.TransitionProgressListener() {
@@ -371,7 +368,7 @@
mActivity.addOnDeviceProfileChangeListener(mDebugActivityDeviceProfileChanged);
Log.d(TASKBAR_NOT_DESTROYED_TAG,
"registering activity lifecycle callbacks from setActivity().");
- mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
+ mActivity.addEventCallback(EVENT_DESTROYED, mActivityOnDestroyCallback);
UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
getUnfoldTransitionProgressProviderForActivity(activity);
if (unfoldTransitionProgressProvider != null) {
@@ -547,7 +544,7 @@
Log.d(TASKBAR_NOT_DESTROYED_TAG,
"unregistering activity lifecycle callbacks from "
+ "removeActivityCallbackAndListeners().");
- mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+ mActivity.removeEventCallback(EVENT_DESTROYED, mActivityOnDestroyCallback);
UnfoldTransitionProgressProvider unfoldTransitionProgressProvider =
getUnfoldTransitionProgressProviderForActivity(mActivity);
if (unfoldTransitionProgressProvider != null) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index a101c20..22ab79d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -33,6 +33,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.config.FeatureFlags.ENABLE_HOME_TRANSITION_LISTENER;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
@@ -263,7 +264,7 @@
mAppTransitionManager.registerRemoteAnimations();
mAppTransitionManager.registerRemoteTransitions();
- if (ENABLE_HOME_TRANSITION_LISTENER.get()) {
+ if (FeatureFlags.enableHomeTransitionListener()) {
mHomeTransitionController = new HomeTransitionController(this);
mHomeTransitionController.registerHomeTransitionListener();
}
@@ -375,7 +376,7 @@
}
if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) {
- if (!ENABLE_HOME_TRANSITION_LISTENER.get() && mTaskbarUIController != null) {
+ if (!FeatureFlags.enableHomeTransitionListener() && mTaskbarUIController != null) {
mTaskbarUIController.onLauncherVisibilityChanged(hasBeenResumed());
}
}
@@ -1182,11 +1183,6 @@
}
@Override
- public void tryClearAccessibilityFocus(View view) {
- view.clearAccessibilityFocus();
- }
-
- @Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index ccd83d2..b06a978 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -23,6 +23,8 @@
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
import static com.android.app.animation.Interpolators.DECELERATE;
import static com.android.app.animation.Interpolators.OVERSHOOT_1_2;
+import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
+import static com.android.launcher3.BaseActivity.EVENT_STARTED;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
@@ -62,7 +64,6 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
-import android.app.Activity;
import android.app.ActivityManager;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
@@ -89,6 +90,7 @@
import android.widget.Toast;
import android.window.PictureInPictureSurfaceTransaction;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -109,7 +111,6 @@
import com.android.launcher3.taskbar.TaskbarThresholdUtils;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.TraceHelper;
@@ -183,19 +184,13 @@
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
private boolean mRecentsViewScrollLinked = false;
- private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
- new ActivityLifecycleCallbacksAdapter() {
- @Override
- public void onActivityDestroyed(Activity activity) {
- if (mActivity != activity) {
- return;
- }
- ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
- mRecentsView = null;
- mActivity = null;
- mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
- }
- };
+
+ private final Runnable mLauncherOnDestroyCallback = () -> {
+ ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
+ mRecentsView = null;
+ mActivity = null;
+ mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
+ };
private static int FLAG_COUNT = 0;
private static int getNextStateFlag(String name) {
@@ -316,8 +311,9 @@
private final int mSplashMainWindowShiftLength;
private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
+ private final Runnable mLauncherOnStartCallback = this::onLauncherStart;
- private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
+ @Nullable private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
protected boolean mIsSwipingPipToHome;
// TODO(b/195473090) no split PIP for now, remove once we have more clarity
// can try to have RectFSpringAnim evaluate multiple rects at once
@@ -489,6 +485,7 @@
mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
return true;
}
+ resetLauncherListeners();
// The launcher may have been recreated as a result of device rotation.
int oldState = mStateCallback.getState() & ~LAUNCHER_UI_STATES;
@@ -512,7 +509,7 @@
if (alreadyOnHome) {
onLauncherStart();
} else {
- activity.runOnceOnStart(this::onLauncherStart);
+ activity.addEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
}
// Set up a entire animation lifecycle callback to notify the current recents view when
@@ -537,9 +534,8 @@
setupRecentsViewUi();
mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll);
- activity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
-
- mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks);
+ mActivity.runOnBindToTouchInteractionService(this::onLauncherBindToService);
+ mActivity.addEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
return true;
}
@@ -676,6 +672,9 @@
if (Arrays.stream(runningTasks).anyMatch(Objects::isNull)) {
return;
}
+ if (mRecentsView == null) {
+ return;
+ }
mRecentsView.onGestureAnimationStart(runningTasks, mDeviceState.getRotationTouchHelper());
}
@@ -1263,8 +1262,8 @@
return isSwipeUp ? ALL_APPS : LAST_TASK;
}
if (!isSwipeUp) {
- final boolean isCenteredOnNewTask =
- mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex();
+ final boolean isCenteredOnNewTask = mRecentsView != null
+ && mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex();
return willGoToNewTask || isCenteredOnNewTask ? NEW_TASK : LAST_TASK;
}
@@ -1540,11 +1539,13 @@
HomeAnimationFactory homeAnimFactory =
createHomeAnimationFactory(cookies, duration, isTranslucent, appCanEnterPip,
runningTaskTarget);
- mIsSwipingPipToHome = !mIsSwipeForSplit && appCanEnterPip;
+ SwipePipToHomeAnimator swipePipToHomeAnimator = !mIsSwipeForSplit && appCanEnterPip
+ ? createWindowAnimationToPip(homeAnimFactory, runningTaskTarget, start)
+ : null;
+ mIsSwipingPipToHome = swipePipToHomeAnimator != null;
final RectFSpringAnim[] windowAnim;
if (mIsSwipingPipToHome) {
- mSwipePipToHomeAnimator = createWindowAnimationToPip(
- homeAnimFactory, runningTaskTarget, start);
+ mSwipePipToHomeAnimator = swipePipToHomeAnimator;
mSwipePipToHomeAnimators[0] = mSwipePipToHomeAnimator;
if (mSwipePipToHomeReleaseCheck != null) {
mSwipePipToHomeReleaseCheck.setCanRelease(false);
@@ -1552,6 +1553,9 @@
// grab a screenshot before the PipContentOverlay gets parented on top of the task
UI_HELPER_EXECUTOR.execute(() -> {
+ if (mRecentsAnimationController == null) {
+ return;
+ }
// Directly use top task, split to pip handled on shell side
final int taskId = mGestureState.getTopRunningTaskId();
mTaskSnapshotCache.put(taskId,
@@ -1669,6 +1673,10 @@
@Nullable
private SwipePipToHomeAnimator createWindowAnimationToPip(HomeAnimationFactory homeAnimFactory,
RemoteAnimationTarget runningTaskTarget, float startProgress) {
+ if (mRecentsView == null) {
+ // Overview was destroyed, bail early.
+ return null;
+ }
// Directly animate the app to PiP (picture-in-picture) mode
final ActivityManager.RunningTaskInfo taskInfo = runningTaskTarget.taskInfo;
final RecentsOrientedState orientationState = mRemoteTargetHandles[0].getTaskViewSimulator()
@@ -1809,7 +1817,8 @@
private void continueComputingRecentsScrollIfNecessary() {
if (!mGestureState.hasState(STATE_RECENTS_SCROLLING_FINISHED)
&& !mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)
- && !mCanceled) {
+ && !mCanceled
+ && mRecentsView != null) {
computeRecentsScrollIfInvisible();
mRecentsView.postOnAnimation(this::continueComputingRecentsScrollIfNecessary);
}
@@ -1853,7 +1862,6 @@
if (mActivity != null) {
// In the off chance that the gesture ends before Launcher is started, we should clear
// the callback here so that it doesn't update with the wrong state
- mActivity.clearRunOnceOnStartCallback();
resetLauncherListeners();
}
if (mGestureState.isRecentsAnimationRunning() && mGestureState.getEndTarget() != null
@@ -1919,7 +1927,7 @@
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
if (mActivity != null) {
- mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks);
+ mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
}
}
@@ -1990,6 +1998,9 @@
* continued quick switch gesture, which cancels the previous handler but doesn't invalidate it.
*/
private void resetLauncherListeners() {
+ mActivity.removeEventCallback(EVENT_STARTED, mLauncherOnStartCallback);
+ mActivity.removeEventCallback(EVENT_DESTROYED, mLauncherOnDestroyCallback);
+
mActivity.getRootView().setOnApplyWindowInsetsListener(null);
if (mRecentsView != null) {
@@ -2111,7 +2122,7 @@
* from Launcher to WM.
*/
private void maybeAbortSwipePipToHome() {
- if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) {
+ if (mIsSwipingPipToHome && mSwipePipToHomeAnimator != null) {
SystemUiProxy.INSTANCE.get(mContext).abortSwipePipToHome(
mSwipePipToHomeAnimator.getTaskId(),
mSwipePipToHomeAnimator.getComponentName());
@@ -2125,7 +2136,10 @@
* This should happen before {@link #finishRecentsControllerToHome(Runnable)}.
*/
private void maybeFinishSwipePipToHome() {
- if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) {
+ if (mRecentsAnimationController == null) {
+ return;
+ }
+ if (mIsSwipingPipToHome && mSwipePipToHomeAnimator != null) {
mRecentsAnimationController.setFinishTaskTransaction(
mSwipePipToHomeAnimator.getTaskId(),
mSwipePipToHomeAnimator.getFinishTransaction(),
@@ -2149,7 +2163,7 @@
protected abstract void finishRecentsControllerToHome(Runnable callback);
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
- if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
+ if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED) || mRecentsView == null) {
return;
}
endLauncherTransitionController();
@@ -2183,6 +2197,9 @@
}
protected void linkRecentsViewScroll() {
+ if (mRecentsView == null) {
+ return;
+ }
SurfaceTransactionApplier applier = new SurfaceTransactionApplier(mRecentsView);
runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
.setSyncTransactionApplier(applier));
@@ -2190,9 +2207,13 @@
mRecentsAnimationTargets.addReleaseCheck(applier));
mRecentsView.addOnScrollChangedListener(mOnRecentsScrollListener);
- runOnRecentsAnimationAndLauncherBound(() ->
- mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
- mRecentsAnimationTargets));
+ runOnRecentsAnimationAndLauncherBound(() -> {
+ if (mRecentsView == null) {
+ return;
+ }
+ mRecentsView.setRecentsAnimationTargets(
+ mRecentsAnimationController, mRecentsAnimationTargets);
+ });
// Disable scrolling in RecentsView for trackpad 3-finger swipe up gesture.
if (!mGestureState.isThreeFingerTrackpadGesture()) {
@@ -2299,7 +2320,7 @@
}
@Override
- public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) {
+ public void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTargets) {
if (mRecentsAnimationController != null) {
boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTargets).anyMatch(
mGestureState.mLastStartedTaskIdPredicate);
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 468d96a..038a022 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,7 +17,6 @@
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_HOME_TRANSITION_LISTENER;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -63,6 +62,7 @@
import com.android.internal.logging.InstanceId;
import com.android.internal.util.ScreenshotRequest;
import com.android.internal.view.AppearanceRegion;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.ActiveGestureLog;
@@ -1048,7 +1048,7 @@
}
public void setHomeTransitionListener(IHomeTransitionListener listener) {
- if (!ENABLE_HOME_TRANSITION_LISTENER.get()) {
+ if (!FeatureFlags.enableHomeTransitionListener()) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
index bb028a7..df5765c 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransactionApplier.java
@@ -25,6 +25,8 @@
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewRootImpl;
+import androidx.annotation.NonNull;
+
import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
/**
@@ -48,7 +50,7 @@
/**
* @param targetView The view in the surface that acts as synchronization anchor.
*/
- public SurfaceTransactionApplier(View targetView) {
+ public SurfaceTransactionApplier(@NonNull View targetView) {
if (targetView.isAttachedToWindow()) {
initialize(targetView);
} else {
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
index d7b3431..cdadd71 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -18,11 +18,13 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import android.app.Activity;
+import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
+import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
+import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
import androidx.annotation.NonNull;
-import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
+import com.android.launcher3.BaseActivity;
import com.android.quickstep.RecentsModel;
/**
@@ -34,19 +36,28 @@
* If we hit either of those signals and the task is no longer valid, then the registered failure
* callback will be notified.
*/
-public class TaskRemovedDuringLaunchListener implements ActivityLifecycleCallbacksAdapter {
+public class TaskRemovedDuringLaunchListener {
- private Activity mActivity;
+ private BaseActivity mActivity;
private int mLaunchedTaskId = INVALID_TASK_ID;
private Runnable mTaskLaunchFailedCallback = null;
+ private final Runnable mUnregisterCallback = this::unregister;
+ private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
+
/**
* Registers a failure listener callback if it detects a scenario in which an app launch
* failed before the transition finished.
*/
- public void register(Activity activity, int launchedTaskId,
+ public void register(BaseActivity activity, int launchedTaskId,
@NonNull Runnable taskLaunchFailedCallback) {
- activity.registerActivityLifecycleCallbacks(this);
+ // The normal task launch case, Launcher stops and updates its state correctly
+ activity.addEventCallback(EVENT_STOPPED, mUnregisterCallback);
+ // The transition hasn't finished but Launcher was resumed, check if the launch failed
+ activity.addEventCallback(EVENT_RESUMED, mResumeCallback);
+ // If we somehow don't get any of the above signals, then just unregister this listener
+ activity.addEventCallback(EVENT_DESTROYED, mUnregisterCallback);
+
mActivity = activity;
mLaunchedTaskId = launchedTaskId;
mTaskLaunchFailedCallback = taskLaunchFailedCallback;
@@ -56,7 +67,10 @@
* Unregisters the failure listener.
*/
private void unregister() {
- mActivity.unregisterActivityLifecycleCallbacks(this);
+ mActivity.removeEventCallback(EVENT_STOPPED, mUnregisterCallback);
+ mActivity.removeEventCallback(EVENT_RESUMED, mResumeCallback);
+ mActivity.removeEventCallback(EVENT_DESTROYED, mUnregisterCallback);
+
mActivity = null;
mLaunchedTaskId = INVALID_TASK_ID;
mTaskLaunchFailedCallback = null;
@@ -70,24 +84,6 @@
checkTaskLaunchFailed();
}
- @Override
- public void onActivityStopped(Activity activity) {
- // The normal task launch case, Launcher stops and updates its state correctly
- unregister();
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- // The transition hasn't finished but Launcher was resumed, check if the launch failed
- checkTaskLaunchFailed();
- }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- // If we somehow don't get any of the above signals, then just unregister this listener
- unregister();
- }
-
private void checkTaskLaunchFailed() {
if (mLaunchedTaskId != INVALID_TASK_ID) {
final int launchedTaskId = mLaunchedTaskId;
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 767aa15..5d8e53e 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -17,6 +17,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -108,6 +109,7 @@
private boolean mIsDesktopTask;
private int mTaskRectTranslationX;
private int mTaskRectTranslationY;
+ private int mPivotOffsetX;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -179,9 +181,10 @@
// Ensure the task rect is inside the full task rect
mTaskRect.offset(fullTaskSize.left, fullTaskSize.top);
} else {
- fullTaskSize = mTaskRect;
+ fullTaskSize = new Rect(mTaskRect);
+ mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
}
- fullTaskSize.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+ fullTaskSize.offset(mTaskRectTranslationX + mPivotOffsetX, mTaskRectTranslationY);
return mOrientationState.getFullScreenScaleAndPivot(fullTaskSize, mDp, mPivot);
}
@@ -265,6 +268,11 @@
*/
public void addAppToOverviewAnim(PendingAnimation pa, TimeInterpolator interpolator) {
pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
+ if (enableGridOnlyOverview() && mDp.isTablet) {
+ int translationXToMiddle = mDp.widthPx / 2 - mTaskRect.centerX();
+ taskPrimaryTranslation.value = translationXToMiddle;
+ mPivotOffsetX = translationXToMiddle;
+ }
pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1, interpolator);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index c44d1f2..7972999 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2101,11 +2101,15 @@
}
float accumulatedTranslationX = 0;
+ float translateXToMiddle = enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
+ ? mActivity.getDeviceProfile().widthPx / 2 - mLastComputedGridTaskSize.centerX()
+ : 0;
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
taskView.updateTaskSize();
taskView.getPrimaryNonGridTranslationProperty().set(taskView, accumulatedTranslationX);
taskView.getSecondaryNonGridTranslationProperty().set(taskView, 0f);
+ taskView.setNonGridPivotTranslationX(translateXToMiddle);
// Compensate space caused by TaskView scaling.
float widthDiff =
taskView.getLayoutParams().width * (1 - taskView.getNonGridScale());
@@ -4322,14 +4326,19 @@
Utilities.getPivotsForScalingRectToRect(mTempRect, selectedTaskPosition,
mTempPointF);
- setPivotX(mTempPointF.x);
- setPivotY(mTempPointF.y);
} else {
+ mTempRect.set(mLastComputedTaskSize);
+ // Only update pivot when it is tablet and not in grid yet, so the pivot is correct
+ // for non-current tasks when swiping up to overview
+ if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
+ && !mOverviewGridEnabled) {
+ mTempRect.offset(mActivity.getDeviceProfile().widthPx / 2 - mTempRect.centerX(), 0);
+ }
getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
mActivity.getDeviceProfile(), mTempPointF);
- setPivotX(mTempPointF.x);
- setPivotY(mTempPointF.y);
}
+ setPivotX(mTempPointF.x);
+ setPivotY(mTempPointF.y);
}
private void updatePageOffsets() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 2b3cc5b..5093f22 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -385,6 +385,7 @@
// switch.
private float mNonGridTranslationX;
private float mNonGridTranslationY;
+ private float mNonGridPivotTranslationX;
// Used when in SplitScreenSelectState
private float mSplitSelectTranslationY;
private float mSplitSelectTranslationX;
@@ -1285,8 +1286,8 @@
}
protected void resetPersistentViewTransforms() {
- mNonGridTranslationX = mNonGridTranslationY =
- mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
+ mNonGridTranslationX = mNonGridTranslationY = mGridTranslationX =
+ mGridTranslationY = mBoxTranslationY = mNonGridPivotTranslationX = 0f;
resetViewTransforms();
}
@@ -1488,6 +1489,14 @@
applyTranslationX();
}
+ /**
+ * Set translation X for non-grid pivot
+ */
+ public void setNonGridPivotTranslationX(float nonGridPivotTranslationX) {
+ mNonGridPivotTranslationX = nonGridPivotTranslationX;
+ applyTranslationX();
+ }
+
public float getScrollAdjustment(boolean gridEnabled) {
float scrollAdjustment = 0;
if (gridEnabled) {
@@ -1530,7 +1539,8 @@
* change according to a temporary state (e.g. task offset).
*/
public float getPersistentTranslationX() {
- return getNonGridTrans(mNonGridTranslationX) + getGridTrans(mGridTranslationX);
+ return getNonGridTrans(mNonGridTranslationX) + getGridTrans(mGridTranslationX)
+ + getNonGridTrans(mNonGridPivotTranslationX);
}
/**
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 05a6452..1049314 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -29,7 +29,6 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
-import android.view.View;
import android.window.OnBackInvokedDispatcher;
import androidx.annotation.IntDef;
@@ -38,6 +37,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
@@ -153,6 +153,18 @@
private final ViewCache mViewCache = new ViewCache();
+ @Retention(SOURCE)
+ @IntDef({EVENT_STARTED, EVENT_RESUMED, EVENT_STOPPED, EVENT_DESTROYED})
+ public @interface ActivityEvent { }
+ public static final int EVENT_STARTED = 0;
+ public static final int EVENT_RESUMED = 1;
+ public static final int EVENT_STOPPED = 2;
+ public static final int EVENT_DESTROYED = 3;
+
+ // Callback array that corresponds to events defined in @ActivityEvent
+ private final RunnableList[] mEventCallbacks =
+ {new RunnableList(), new RunnableList(), new RunnableList(), new RunnableList()};
+
@Override
public ViewCache getViewCache() {
return mViewCache;
@@ -205,12 +217,14 @@
protected void onStart() {
addActivityFlags(ACTIVITY_STATE_STARTED);
super.onStart();
+ mEventCallbacks[EVENT_STARTED].executeAllAndClear();
}
@Override
protected void onResume() {
setResumed();
super.onResume();
+ mEventCallbacks[EVENT_RESUMED].executeAllAndClear();
}
@Override
@@ -232,6 +246,8 @@
removeActivityFlags(ACTIVITY_STATE_STARTED | ACTIVITY_STATE_USER_ACTIVE);
mForceInvisible = 0;
super.onStop();
+ mEventCallbacks[EVENT_STOPPED].executeAllAndClear();
+
// Reset the overridden sysui flags used for the task-swipe launch animation, this is a
// catch all for if we do not get resumed (and therefore not paused below)
@@ -239,6 +255,12 @@
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mEventCallbacks[EVENT_DESTROYED].executeAllAndClear();
+ }
+
+ @Override
protected void onPause() {
setPaused();
super.onPause();
@@ -258,7 +280,6 @@
} else {
removeActivityFlags(ACTIVITY_STATE_WINDOW_FOCUSED);
}
-
}
protected void registerBackDispatcher() {
@@ -364,9 +385,15 @@
}
/**
- * Attempts to clear accessibility focus on {@param view}.
+ * Adds a callback for the provided activity event
*/
- public void tryClearAccessibilityFocus(View view) {
+ public void addEventCallback(@ActivityEvent int event, Runnable callback) {
+ mEventCallbacks[event].add(callback);
+ }
+
+ /** Removes a previously added callback */
+ public void removeEventCallback(@ActivityEvent int event, Runnable callback) {
+ mEventCallbacks[event].remove(callback);
}
public interface MultiWindowModeChangedListener {
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 808cf70..f8ed4df 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -38,7 +38,6 @@
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.OnColorHintListener;
-import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.WallpaperColorHints;
@@ -51,8 +50,6 @@
public abstract class BaseDraggingActivity extends BaseActivity
implements OnColorHintListener, DisplayInfoChangeListener {
- private static final String TAG = "BaseDraggingActivity";
-
// When starting an action mode, setting this tag will cause the action mode to be cancelled
// automatically when user interacts with the launcher.
public static final Object AUTO_CANCEL_ACTION_MODE = new Object();
@@ -60,8 +57,6 @@
private ActionMode mCurrentActionMode;
protected boolean mIsSafeModeEnabled;
- private Runnable mOnStartCallback;
- private final RunnableList mOnResumeCallbacks = new RunnableList();
private int mThemeRes = R.style.AppTheme;
@Override
@@ -81,16 +76,6 @@
}
}
- @Override
- protected void onResume() {
- super.onResume();
- mOnResumeCallbacks.executeAllAndClear();
- }
-
- public void addOnResumeCallback(Runnable callback) {
- mOnResumeCallbacks.add(callback);
- }
-
@MainThread
@Override
public void onColorHintsChanged(int colorHints) {
@@ -146,42 +131,24 @@
@NonNull
public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
ActivityOptionsWrapper wrapper = super.getActivityLaunchOptions(v, item);
- addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy);
+ addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy);
return wrapper;
}
@Override
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
ActivityOptionsWrapper wrapper = super.makeDefaultActivityOptions(splashScreenStyle);
- addOnResumeCallback(wrapper.onEndCallback::executeAllAndDestroy);
+ addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy);
return wrapper;
}
@Override
- protected void onStart() {
- super.onStart();
-
- if (mOnStartCallback != null) {
- mOnStartCallback.run();
- mOnStartCallback = null;
- }
- }
-
- @Override
protected void onDestroy() {
super.onDestroy();
DisplayController.INSTANCE.get(this).removeChangeListener(this);
WallpaperColorHints.get(this).unregisterOnColorsChangedListener(this);
}
- public void runOnceOnStart(Runnable action) {
- mOnStartCallback = action;
- }
-
- public void clearRunOnceOnStartCallback() {
- mOnStartCallback = null;
- }
-
protected void onDeviceProfileInitiated() {
if (mDeviceProfile.isVerticalBarLayout()) {
mDeviceProfile.updateIsSeascape(this);
diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt
index 6560e16..78f2862 100644
--- a/src/com/android/launcher3/DropTargetHandler.kt
+++ b/src/com/android/launcher3/DropTargetHandler.kt
@@ -2,6 +2,7 @@
import android.content.ComponentName
import android.view.View
+import com.android.launcher3.BaseDraggingActivity.EVENT_RESUMED
import com.android.launcher3.DropTarget.DragObject
import com.android.launcher3.SecondaryDropTarget.DeferredOnComplete
import com.android.launcher3.dragndrop.DragLayer
@@ -32,7 +33,7 @@
if (d.dragSource is SecondaryDropTarget.DeferredOnComplete) {
target?.let {
deferred.mPackageName = it.packageName
- mLauncher.addOnResumeCallback { deferred.onLauncherResume() }
+ mLauncher.addEventCallback(EVENT_RESUMED) { deferred.onLauncherResume() }
}
?: deferred.sendFailure()
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 1f64cd8..edff48b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -690,7 +690,7 @@
private void switchOverlay(Supplier<LauncherOverlayManager> overlaySupplier) {
if (mOverlayManager != null) {
- mOverlayManager.onActivityDestroyed(this);
+ mOverlayManager.onActivityDestroyed();
}
mOverlayManager = overlaySupplier.get();
if (getRootView().isAttachedToWindow()) {
@@ -1031,7 +1031,7 @@
if (mDeferOverlayCallbacks) {
checkIfOverlayStillDeferred();
} else {
- mOverlayManager.onActivityStopped(this);
+ mOverlayManager.onActivityStopped();
}
hideKeyboard();
logStopAndResume(false /* isResume */);
@@ -1045,7 +1045,7 @@
TraceHelper.INSTANCE.beginSection(ON_START_EVT);
super.onStart();
if (!mDeferOverlayCallbacks) {
- mOverlayManager.onActivityStarted(this);
+ mOverlayManager.onActivityStarted();
}
mAppWidgetHolder.setActivityStarted(true);
@@ -1114,15 +1114,15 @@
// Move the client to the correct state. Calling the same method twice is no-op.
if (isStarted()) {
- mOverlayManager.onActivityStarted(this);
+ mOverlayManager.onActivityStarted();
}
if (hasBeenResumed()) {
- mOverlayManager.onActivityResumed(this);
+ mOverlayManager.onActivityResumed();
} else {
- mOverlayManager.onActivityPaused(this);
+ mOverlayManager.onActivityPaused();
}
if (!isStarted()) {
- mOverlayManager.onActivityStopped(this);
+ mOverlayManager.onActivityStopped();
}
}
@@ -1222,7 +1222,7 @@
if (mDeferOverlayCallbacks) {
scheduleDeferredCheck();
} else {
- mOverlayManager.onActivityResumed(this);
+ mOverlayManager.onActivityResumed();
}
DragView.removeAllViews(this);
@@ -1240,7 +1240,7 @@
mDropTargetBar.animateToVisibility(false);
if (!mDeferOverlayCallbacks) {
- mOverlayManager.onActivityPaused(this);
+ mOverlayManager.onActivityPaused();
}
mAppWidgetHolder.setActivityResumed(false);
}
@@ -1685,7 +1685,6 @@
}
super.onSaveInstanceState(outState);
- mOverlayManager.onActivitySaveInstanceState(this, outState);
}
@Override
@@ -1711,7 +1710,7 @@
clearPendingBinds();
LauncherAppState.getIDP(this).removeOnChangeListener(this);
- mOverlayManager.onActivityDestroyed(this);
+ mOverlayManager.onActivityDestroyed();
}
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
@@ -1744,7 +1743,7 @@
try {
super.startIntentSenderForResult(intent, requestCode,
fillInIntent, flagsMask, flagsValues, extraFlags, options);
- } catch (IntentSender.SendIntentException e) {
+ } catch (Exception e) {
throw new ActivityNotFoundException();
}
}
@@ -2006,7 +2005,7 @@
// Workaround an issue where the WM launch animation is clobbered when finishing the
// recents animation into launcher. Defer launching the activity until Launcher is
// next resumed.
- addOnResumeCallback(() -> {
+ addEventCallback(EVENT_RESUMED, () -> {
RunnableList actualResult = startActivitySafely(v, intent, item);
if (actualResult != null) {
actualResult.add(result::executeAllAndDestroy);
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index c6a9283..4f8caab 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -20,11 +20,12 @@
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.util.Log
-import android.view.ViewConfiguration
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
+import com.android.launcher3.config.FeatureFlags.LPNH_SLOP_PERCENTAGE
+import com.android.launcher3.config.FeatureFlags.LPNH_TIMEOUT_MS
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.pm.InstallSessionHelper
import com.android.launcher3.provider.RestoreDbTask
@@ -310,16 +311,16 @@
)
@JvmField
val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
- nonRestorableItem(
- "pref_long_press_nav_handle_slop_multiplier",
- 100,
+ nonRestorableItem(
+ "pref_long_press_nav_handle_slop_percentage",
+ LPNH_SLOP_PERCENTAGE.get(),
EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
nonRestorableItem(
"pref_long_press_nav_handle_timeout_ms",
- ViewConfiguration.getLongPressTimeout(),
+ LPNH_TIMEOUT_MS.get(),
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 4d8166c..4e7ec0b 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -21,8 +21,11 @@
import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag;
+import static com.android.launcher3.uioverrides.flags.FlagsFactory.getIntFlag;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
+import android.view.ViewConfiguration;
+
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BuildConfig;
@@ -113,9 +116,17 @@
"Allow entering All Apps from Overview (e.g. long swipe up from app)");
public static final BooleanFlag CUSTOM_LPNH_THRESHOLDS =
- getDebugFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
+ getReleaseFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
"Add dev options to customize the LPNH trigger slop and milliseconds");
+ public static final IntFlag LPNH_SLOP_PERCENTAGE =
+ getIntFlag(301680992, "LPNH_SLOP_PERCENTAGE", 100,
+ "Controls touch slop percentage for lpnh");
+
+ public static final IntFlag LPNH_TIMEOUT_MS =
+ getIntFlag(301680992, "LPNH_TIMEOUT_MS", ViewConfiguration.getLongPressTimeout(),
+ "Controls lpnh timeout in milliseconds");
+
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
"Enable option to show keyboard when going to all-apps");
@@ -305,10 +316,15 @@
"ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED,
"Enables taskbar thresholds that scale based on screen size.");
+ // Aconfig migration complete for ENABLE_HOME_TRANSITION_LISTENER.
public static final BooleanFlag ENABLE_HOME_TRANSITION_LISTENER = getDebugFlag(306053414,
- "ENABLE_HOME_TRANSITION_LISTENER", DISABLED,
+ "ENABLE_HOME_TRANSITION_LISTENER", TEAMFOOD,
"Enables launcher to listen to all transitions that include home activity.");
+ public static boolean enableHomeTransitionListener() {
+ return ENABLE_HOME_TRANSITION_LISTENER.get() || Flags.enableHomeTransitionListener();
+ }
+
// TODO(Block 21): Clean up flags
public static final BooleanFlag ENABLE_APP_ICON_FOR_INLINE_SHORTCUTS = getDebugFlag(270395087,
"ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", DISABLED, "Show app icon for inline shortcut");
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 8167b97..1360510 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -269,7 +269,6 @@
Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP,
Favorites.CELLY, 0), null);
}
- return;
}
case 31: {
LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
diff --git a/src/com/android/launcher3/util/RunnableList.java b/src/com/android/launcher3/util/RunnableList.java
index 644537b..f6e0c57 100644
--- a/src/com/android/launcher3/util/RunnableList.java
+++ b/src/com/android/launcher3/util/RunnableList.java
@@ -25,9 +25,7 @@
private ArrayList<Runnable> mList = null;
private boolean mDestroyed = false;
- /**
- * Ads a runnable to this list
- */
+ /** Adds a runnable to this list */
public void add(Runnable runnable) {
if (runnable == null) {
return;
@@ -42,6 +40,13 @@
mList.add(runnable);
}
+ /** Removes a previously added runnable */
+ public void remove(Runnable runnable) {
+ if (mList != null) {
+ mList.remove(runnable);
+ }
+ }
+
/**
* Destroys the list, executing any pending callbacks. All new callbacks are
* immediately executed
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
index 6b27503..54cc0bc 100644
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
+++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
@@ -15,16 +15,12 @@
*/
package com.android.systemui.plugins.shared;
-import android.app.Activity;
-import android.app.Application;
-import android.os.Bundle;
-
import java.io.PrintWriter;
/**
* Interface to control the overlay on Launcher
*/
-public interface LauncherOverlayManager extends Application.ActivityLifecycleCallbacks {
+public interface LauncherOverlayManager {
default void onDeviceProvideChanged() { }
@@ -41,26 +37,15 @@
default void hideOverlay(int duration) { }
- @Override
- default void onActivityCreated(Activity activity, Bundle bundle) { }
+ default void onActivityStarted() { }
- @Override
- default void onActivityStarted(Activity activity) { }
+ default void onActivityResumed() { }
- @Override
- default void onActivityResumed(Activity activity) { }
+ default void onActivityPaused() { }
- @Override
- default void onActivityPaused(Activity activity) { }
+ default void onActivityStopped() { }
- @Override
- default void onActivityStopped(Activity activity) { }
-
- @Override
- default void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
-
- @Override
- default void onActivityDestroyed(Activity activity) { }
+ default void onActivityDestroyed() { }
interface LauncherOverlay {
diff --git a/tests/src/com/android/launcher3/DeleteDropTargetTest.kt b/tests/src/com/android/launcher3/DeleteDropTargetTest.kt
index bcfb90b..46e66e4 100644
--- a/tests/src/com/android/launcher3/DeleteDropTargetTest.kt
+++ b/tests/src/com/android/launcher3/DeleteDropTargetTest.kt
@@ -32,9 +32,9 @@
buttonDropTarget.setTextMultiLine(false)
// No space for text
- assertThat(buttonDropTarget.isTextClippedVertically(30)).isTrue()
+ assertThat(buttonDropTarget.isTextClippedVertically(1)).isTrue()
// A lot of space for text so the text should not be clipped
- assertThat(buttonDropTarget.isTextClippedVertically(100)).isFalse()
+ assertThat(buttonDropTarget.isTextClippedVertically(1000)).isFalse()
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index aa5c770..a85b6bd 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -366,8 +366,10 @@
}
int focusedTaskHeight = mLauncher.getFocusedTaskHeightForTablet();
for (UiObject2 task : taskViews) {
- if (task.getVisibleBounds().height() == focusedTaskHeight) {
- return new OverviewTask(mLauncher, task, this);
+ OverviewTask overviewTask = new OverviewTask(mLauncher, task, this);
+
+ if (overviewTask.getVisibleHeight() == focusedTaskHeight) {
+ return overviewTask;
}
}
return null;
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 95a4802..06fac48 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -36,6 +36,8 @@
*/
public final class OverviewTask {
private static final String SYSTEMUI_PACKAGE = "com.android.systemui";
+ private static final String TASK_SNAPSHOT_1 = "snapshot";
+ private static final String TASK_SNAPSHOT_2 = "bottomright_snapshot";
static final Pattern TASK_START_EVENT = Pattern.compile("startActivityFromRecentsAsync");
static final Pattern SPLIT_SELECT_EVENT = Pattern.compile("enterSplitSelect");
@@ -55,14 +57,64 @@
mOverview.verifyActiveContainer();
}
+ /**
+ * Returns the height of the visible task, or the combined height of two tasks in split with a
+ * divider between.
+ */
int getVisibleHeight() {
+ if (isTaskSplit()) {
+ return getCombinedSplitTaskHeight();
+ }
+
return mTask.getVisibleBounds().height();
}
+ /**
+ * Calculates the visible height for split tasks, containing 2 snapshot tiles and a divider.
+ */
+ private int getCombinedSplitTaskHeight() {
+ UiObject2 taskSnapshot1 =
+ mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
+ UiObject2 taskSnapshot2 =
+ mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+
+ int top = Math.min(
+ taskSnapshot1.getVisibleBounds().top, taskSnapshot2.getVisibleBounds().top);
+ int bottom = Math.max(
+ taskSnapshot1.getVisibleBounds().bottom, taskSnapshot2.getVisibleBounds().bottom);
+
+ return bottom - top;
+ }
+
+ /**
+ * Returns the width of the visible task, or the combined width of two tasks in split with a
+ * divider between.
+ */
int getVisibleWidth() {
+ if (isTaskSplit()) {
+ return getCombinedSplitTaskWidth();
+ }
+
return mTask.getVisibleBounds().width();
}
+ /**
+ * Calculates the visible width for split tasks, containing 2 snapshot tiles and a divider.
+ */
+ private int getCombinedSplitTaskWidth() {
+ UiObject2 taskSnapshot1 =
+ mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_1);
+ UiObject2 taskSnapshot2 =
+ mLauncher.findObjectInContainer(mTask.getParent(), TASK_SNAPSHOT_2);
+
+ int left = Math.min(
+ taskSnapshot1.getVisibleBounds().left, taskSnapshot2.getVisibleBounds().left);
+ int right = Math.max(
+ taskSnapshot1.getVisibleBounds().right, taskSnapshot2.getVisibleBounds().right);
+
+ return right - left;
+ }
+
int getTaskCenterX() {
return mTask.getVisibleCenter().x;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Qsb.java b/tests/tapl/com/android/launcher3/tapl/Qsb.java
index 5ca80a3..fe2a63d 100644
--- a/tests/tapl/com/android/launcher3/tapl/Qsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/Qsb.java
@@ -22,6 +22,8 @@
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
+import java.util.regex.Pattern;
+
/**
* Operations on qsb from either Home screen or AllApp screen.
*/
@@ -30,7 +32,8 @@
private static final String ASSISTANT_APP_PACKAGE = "com.google.android.googlequicksearchbox";
private static final String ASSISTANT_ICON_RES_ID = "mic_icon";
private static final String LENS_ICON_RES_ID = "lens_icon";
- private static final String LENS_APP_TEXT_RES_ID = "lens_camera_cutout_text";
+ private static final Pattern LENS_APP_RES_PATTERN = Pattern.compile(
+ ASSISTANT_APP_PACKAGE + ":id/lens.*");
protected final LauncherInstrumentation mLauncher;
private final UiObject2 mContainer;
private final String mQsbResName;
@@ -96,8 +99,8 @@
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("clicked")) {
// Package name is not enough to check if the app is launched, because many
// elements are having googlequicksearchbox as package name. So it checks if the
- // corresponding text resource is displayed
- BySelector selector = By.res(ASSISTANT_APP_PACKAGE, LENS_APP_TEXT_RES_ID);
+ // corresponding app resource is displayed
+ BySelector selector = By.res(LENS_APP_RES_PATTERN);
mLauncher.assertTrue(
"Lens app didn't start: (" + selector + ")",
mLauncher.getDevice().wait(Until.hasObject(selector),