Merge "Adds supportsCommitHaptic" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 760d8ac..9080284 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -76,3 +76,10 @@
description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
bug: "307527314"
}
+
+flag {
+ name: "enable_unfolded_two_pane_picker"
+ namespace: "launcher"
+ description: "Enables two pane widget picker for unfolded foldables"
+ bug: "313922374"
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index cbb991d..b29ce6b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -133,11 +133,20 @@
GroupTask task = mControllerCallbacks.getTaskAt(index);
if (task == null) {
return Math.max(0, index);
- } else if (mOnDesktop) {
+ }
+ Task task2 = task.task2;
+ int runningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().taskId;
+ if (runningTaskId == task.task1.key.id
+ || (task2 != null && runningTaskId == task2.key.id)) {
+ // Ignore attempts to run the selected task if it is already running.
+ return -1;
+ }
+
+ if (mOnDesktop) {
UI_HELPER_EXECUTOR.execute(() ->
SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
.showDesktopApp(task.task1.key.id));
- } else if (task.task2 == null) {
+ } else if (task2 == null) {
UI_HELPER_EXECUTOR.execute(() ->
ActivityManagerWrapper.getInstance().startActivityFromRecents(
task.task1.key,
@@ -145,8 +154,7 @@
taskView == null ? mKeyboardQuickSwitchView : taskView, null)
.options));
} else {
- mControllers.uiController.launchSplitTasks(
- taskView == null ? mKeyboardQuickSwitchView : taskView, task);
+ mControllers.uiController.launchSplitTasks(task);
}
return -1;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index bbe73ff..b4754c6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -26,7 +26,6 @@
import android.os.RemoteException;
import android.util.Log;
import android.view.TaskTransitionSpec;
-import android.view.View;
import android.view.WindowManagerGlobal;
import androidx.annotation.NonNull;
@@ -386,8 +385,8 @@
}
@Override
- public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
- mLauncher.launchSplitTasks(taskView, groupTask);
+ public void launchSplitTasks(@NonNull GroupTask groupTask) {
+ mLauncher.launchSplitTasks(groupTask);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 445b312..aee3c6f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -297,11 +297,9 @@
}
/**
- * Launches the focused task in splitscreen.
- *
- * No-op if the view is not yet open.
+ * Launches the given task in split-screen.
*/
- public void launchSplitTasks(@NonNull View taskview, @NonNull GroupTask groupTask) { }
+ public void launchSplitTasks(@NonNull GroupTask groupTask) { }
/**
* Returns the matching view (if any) in the taskbar.
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 5b0c8c3..89b7fa4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -19,6 +19,7 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -34,8 +35,6 @@
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
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;
@@ -1263,24 +1262,19 @@
/**
* Launches the given {@link GroupTask} in splitscreen.
- *
- * If the second split task is missing, launches the first task normally.
*/
- public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
- if (groupTask.task2 == null) {
- UI_HELPER_EXECUTOR.execute(() ->
- ActivityManagerWrapper.getInstance().startActivityFromRecents(
- groupTask.task1.key,
- getActivityLaunchOptions(taskView, null).options));
- return;
- }
+ public void launchSplitTasks(@NonNull GroupTask groupTask) {
+ // Top/left and bottom/right tasks respectively.
+ Task task1 = groupTask.task1;
+ // task2 should never be null when calling this method. Allow a crash to catch invalid calls
+ Task task2 = groupTask.task2;
mSplitSelectStateController.launchExistingSplitPair(
null /* launchingTaskView */,
- groupTask.task1.key.id,
- groupTask.task2.key.id,
+ task1.key.id,
+ task2.key.id,
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
/* callback= */ success -> mSplitSelectStateController.resetState(),
- /* freezeTaskList= */ true,
+ /* freezeTaskList= */ false,
groupTask.mSplitBounds == null
? SNAP_TO_50_50
: groupTask.mSplitBounds.snapPosition);
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 5568459..9e58160 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -55,6 +55,7 @@
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.taskbar.LauncherTaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.systemui.shared.system.QuickStepContract;
@@ -416,6 +417,10 @@
if (mLauncher.isDestroyed()) {
return;
}
+ LauncherTaskbarUIController taskbarUIController = mLauncher.getTaskbarUIController();
+ if (taskbarUIController != null) {
+ taskbarUIController.onLauncherVisibilityChanged(true);
+ }
// TODO: Catch the moment when launcher becomes visible after the top app un-occludes
// launcher and start animating afterwards. Currently we occasionally get a flicker from
// animating when launcher is still invisible.
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 39edd70..22163b9 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -18,9 +18,11 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
+
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
+import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
@@ -344,6 +346,8 @@
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
mFallbackRecentsView.updateLocusId();
+ AccessibilityManagerCompat.sendTestProtocolEventToTest(
+ this, LAUNCHER_ACTIVITY_STOPPED_MESSAGE);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
deleted file mode 100644
index 27de20c..0000000
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ /dev/null
@@ -1,1515 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
-
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
-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;
-import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
-import static com.android.quickstep.util.LogUtils.splitFailureMessage;
-
-import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.app.PendingIntent;
-import android.app.PictureInPictureParams;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IBinder.DeathRecipient;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-import android.view.IRecentsAnimationController;
-import android.view.IRecentsAnimationRunner;
-import android.view.IRemoteAnimationRunner;
-import android.view.MotionEvent;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-import android.window.IOnBackInvokedCallback;
-import android.window.RemoteTransition;
-import android.window.TaskSnapshot;
-import android.window.TransitionFilter;
-
-import androidx.annotation.MainThread;
-import androidx.annotation.Nullable;
-import androidx.annotation.WorkerThread;
-
-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;
-import com.android.quickstep.util.AssistUtils;
-import com.android.systemui.shared.recents.ISystemUiProxy;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
-import com.android.systemui.shared.system.RecentsAnimationListener;
-import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
-import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
-import com.android.systemui.shared.system.smartspace.SmartspaceState;
-import com.android.systemui.unfold.progress.IUnfoldAnimation;
-import com.android.systemui.unfold.progress.IUnfoldTransitionListener;
-import com.android.wm.shell.back.IBackAnimation;
-import com.android.wm.shell.bubbles.IBubbles;
-import com.android.wm.shell.bubbles.IBubblesListener;
-import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
-import com.android.wm.shell.desktopmode.IDesktopMode;
-import com.android.wm.shell.desktopmode.IDesktopTaskListener;
-import com.android.wm.shell.draganddrop.IDragAndDrop;
-import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.pip.IPip;
-import com.android.wm.shell.pip.IPipAnimationListener;
-import com.android.wm.shell.recents.IRecentTasks;
-import com.android.wm.shell.recents.IRecentTasksListener;
-import com.android.wm.shell.splitscreen.ISplitScreen;
-import com.android.wm.shell.splitscreen.ISplitScreenListener;
-import com.android.wm.shell.splitscreen.ISplitSelectListener;
-import com.android.wm.shell.startingsurface.IStartingWindow;
-import com.android.wm.shell.startingsurface.IStartingWindowListener;
-import com.android.wm.shell.transition.IHomeTransitionListener;
-import com.android.wm.shell.transition.IShellTransitions;
-import com.android.wm.shell.util.GroupedRecentTaskInfo;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-
-/**
- * Holds the reference to SystemUI.
- */
-public class SystemUiProxy implements ISystemUiProxy {
- private static final String TAG = SystemUiProxy.class.getSimpleName();
-
- public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
- new MainThreadInitializedObject<>(SystemUiProxy::new);
-
- private static final int MSG_SET_SHELF_HEIGHT = 1;
- private static final int MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT = 2;
-
- private ISystemUiProxy mSystemUiProxy;
- private IPip mPip;
- private IBubbles mBubbles;
- private ISysuiUnlockAnimationController mSysuiUnlockAnimationController;
- private ISplitScreen mSplitScreen;
- private IOneHanded mOneHanded;
- private IShellTransitions mShellTransitions;
- private IStartingWindow mStartingWindow;
- private IRecentTasks mRecentTasks;
- private IBackAnimation mBackAnimation;
- private IDesktopMode mDesktopMode;
- private IUnfoldAnimation mUnfoldAnimation;
- private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
- MAIN_EXECUTOR.execute(() -> clearProxy());
- };
-
- // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
- // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
- // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
- // in case SysUI needs to rebind.
- private IPipAnimationListener mPipAnimationListener;
- private IBubblesListener mBubblesListener;
- private ISplitScreenListener mSplitScreenListener;
- private ISplitSelectListener mSplitSelectListener;
- private IStartingWindowListener mStartingWindowListener;
- private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
- private String mLauncherActivityClass;
- private IRecentTasksListener mRecentTasksListener;
- private IUnfoldTransitionListener mUnfoldAnimationListener;
- private IDesktopTaskListener mDesktopTaskListener;
- private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions =
- new LinkedHashMap<>();
- private IBinder mOriginalTransactionToken = null;
- private IOnBackInvokedCallback mBackToLauncherCallback;
- private IRemoteAnimationRunner mBackToLauncherRunner;
- private IDragAndDrop mDragAndDrop;
- private IHomeTransitionListener mHomeTransitionListener;
-
- // Used to dedupe calls to SystemUI
- private int mLastShelfHeight;
- private boolean mLastShelfVisible;
-
- // Used to dedupe calls to SystemUI
- private int mLastLauncherKeepClearAreaHeight;
- private boolean mLastLauncherKeepClearAreaHeightVisible;
-
- private final Context mContext;
- private final Handler mAsyncHandler;
-
- // TODO(141886704): Find a way to remove this
- private int mLastSystemUiStateFlags;
-
- /**
- * This is a singleton pending intent that is used to start recents via Shell (which is a
- * different process). It is bare-bones, so it's expected that the component and options will
- * be provided via fill-in intent.
- */
- private final PendingIntent mRecentsPendingIntent;
-
- public SystemUiProxy(Context context) {
- mContext = context;
- mAsyncHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessageAsync);
- final Intent baseIntent = new Intent().setPackage(mContext.getPackageName());
- final ActivityOptions options = ActivityOptions.makeBasic()
- .setPendingIntentCreatorBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
- mRecentsPendingIntent = PendingIntent.getActivity(mContext, 0, baseIntent,
- PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
- | Intent.FILL_IN_COMPONENT, options.toBundle());
- }
-
- @Override
- public void onBackPressed() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onBackPressed();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onBackPressed", e);
- }
- }
- }
-
- @Override
- public void onImeSwitcherPressed() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onImeSwitcherPressed();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onImeSwitcherPressed", e);
- }
- }
- }
-
- @Override
- public void setHomeRotationEnabled(boolean enabled) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.setHomeRotationEnabled(enabled);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onBackPressed", e);
- }
- }
- }
-
- @Override
- public IBinder asBinder() {
- // Do nothing
- return null;
- }
-
- /**
- * Sets proxy state, including death linkage, various listeners, and other configuration objects
- */
- @MainThread
- public void setProxy(ISystemUiProxy proxy, IPip pip, IBubbles bubbles, ISplitScreen splitScreen,
- IOneHanded oneHanded, IShellTransitions shellTransitions,
- IStartingWindow startingWindow, IRecentTasks recentTasks,
- ISysuiUnlockAnimationController sysuiUnlockAnimationController,
- IBackAnimation backAnimation, IDesktopMode desktopMode,
- IUnfoldAnimation unfoldAnimation, IDragAndDrop dragAndDrop) {
- Preconditions.assertUIThread();
- unlinkToDeath();
- mSystemUiProxy = proxy;
- mPip = pip;
- mBubbles = bubbles;
- mSplitScreen = splitScreen;
- mOneHanded = oneHanded;
- mShellTransitions = shellTransitions;
- mStartingWindow = startingWindow;
- mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
- mRecentTasks = recentTasks;
- mBackAnimation = backAnimation;
- mDesktopMode = desktopMode;
- mUnfoldAnimation = unfoldAnimation;
- mDragAndDrop = dragAndDrop;
- linkToDeath();
- // re-attach the listeners once missing due to setProxy has not been initialized yet.
- setPipAnimationListener(mPipAnimationListener);
- setBubblesListener(mBubblesListener);
- registerSplitScreenListener(mSplitScreenListener);
- registerSplitSelectListener(mSplitSelectListener);
- setHomeTransitionListener(mHomeTransitionListener);
- setStartingWindowListener(mStartingWindowListener);
- setLauncherUnlockAnimationController(
- mLauncherActivityClass, mLauncherUnlockAnimationController);
- new LinkedHashMap<>(mRemoteTransitions).forEach(this::registerRemoteTransition);
- setupTransactionQueue();
- registerRecentTasksListener(mRecentTasksListener);
- setBackToLauncherCallback(mBackToLauncherCallback, mBackToLauncherRunner);
- setUnfoldAnimationListener(mUnfoldAnimationListener);
- setDesktopTaskListener(mDesktopTaskListener);
- setAssistantOverridesRequested(
- AssistUtils.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
- }
-
- /**
- * Clear the proxy to release held resources and turn the majority of its operations into no-ops
- */
- @MainThread
- public void clearProxy() {
- setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
- }
-
- // TODO(141886704): Find a way to remove this
- public void setLastSystemUiStateFlags(int stateFlags) {
- mLastSystemUiStateFlags = stateFlags;
- }
-
- // TODO(141886704): Find a way to remove this
- public int getLastSystemUiStateFlags() {
- return mLastSystemUiStateFlags;
- }
-
- public boolean isActive() {
- return mSystemUiProxy != null;
- }
-
- private void linkToDeath() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.asBinder().linkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to link sysui proxy death recipient");
- }
- }
- }
-
- private void unlinkToDeath() {
- if (mSystemUiProxy != null) {
- mSystemUiProxy.asBinder().unlinkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
- }
- }
-
- @Override
- public void startScreenPinning(int taskId) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.startScreenPinning(taskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call startScreenPinning", e);
- }
- }
- }
-
- @Override
- public void onOverviewShown(boolean fromHome) {
- onOverviewShown(fromHome, TAG);
- }
-
- public void onOverviewShown(boolean fromHome, String tag) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onOverviewShown(fromHome);
- } catch (RemoteException e) {
- Log.w(tag, "Failed call onOverviewShown from: " + (fromHome ? "home" : "app"), e);
- }
- }
- }
-
- @MainThread
- @Override
- public void onStatusBarTouchEvent(MotionEvent event) {
- Preconditions.assertUIThread();
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onStatusBarTouchEvent(event);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onStatusBarTouchEvent with arg: " + event, e);
- }
- }
- }
-
- @Override
- public void onStatusBarTrackpadEvent(MotionEvent event) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onStatusBarTrackpadEvent(event);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onStatusBarTrackpadEvent with arg: " + event, e);
- }
- }
- }
-
- @Override
- public void onAssistantProgress(float progress) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onAssistantProgress(progress);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onAssistantProgress with progress: " + progress, e);
- }
- }
- }
-
- @Override
- public void onAssistantGestureCompletion(float velocity) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.onAssistantGestureCompletion(velocity);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onAssistantGestureCompletion", e);
- }
- }
- }
-
- @Override
- public void startAssistant(Bundle args) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.startAssistant(args);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call startAssistant", e);
- }
- }
- }
-
- @Override
- public void setAssistantOverridesRequested(int[] invocationTypes) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.setAssistantOverridesRequested(invocationTypes);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setAssistantOverridesRequested", e);
- }
- }
- }
-
- @Override
- public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.animateNavBarLongPress(isTouchDown, shrink, durationMs);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call animateNavBarLongPress", e);
- }
- }
- }
-
- @Override
- public void notifyAccessibilityButtonClicked(int displayId) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.notifyAccessibilityButtonClicked(displayId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call notifyAccessibilityButtonClicked", e);
- }
- }
- }
-
- @Override
- public void notifyAccessibilityButtonLongClicked() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.notifyAccessibilityButtonLongClicked();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call notifyAccessibilityButtonLongClicked", e);
- }
- }
- }
-
- @Override
- public void stopScreenPinning() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.stopScreenPinning();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call stopScreenPinning", e);
- }
- }
- }
-
- @Override
- public void notifyPrioritizedRotation(int rotation) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.notifyPrioritizedRotation(rotation);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call notifyPrioritizedRotation with arg: " + rotation, e);
- }
- }
- }
-
- @Override
- public void notifyTaskbarStatus(boolean visible, boolean stashed) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call notifyTaskbarStatus with arg: " +
- visible + ", " + stashed, e);
- }
- }
- }
-
- /**
- * NOTE: If called to suspend, caller MUST call this method to also un-suspend
- * @param suspend should be true to stop auto-hide, false to resume normal behavior
- */
- @Override
- public void notifyTaskbarAutohideSuspend(boolean suspend) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.notifyTaskbarAutohideSuspend(suspend);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call notifyTaskbarAutohideSuspend with arg: " +
- suspend, e);
- }
- }
- }
-
- @Override
- public void takeScreenshot(ScreenshotRequest request) {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.takeScreenshot(request);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call takeScreenshot");
- }
- }
- }
-
- @Override
- public void expandNotificationPanel() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.expandNotificationPanel();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call expandNotificationPanel", e);
- }
- }
- }
-
- @Override
- public void toggleNotificationPanel() {
- if (mSystemUiProxy != null) {
- try {
- mSystemUiProxy.toggleNotificationPanel();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call toggleNotificationPanel", e);
- }
- }
- }
-
- //
- // Pip
- //
-
- /**
- * Sets the shelf height.
- */
- public void setShelfHeight(boolean visible, int shelfHeight) {
- Message.obtain(mAsyncHandler, MSG_SET_SHELF_HEIGHT,
- visible ? 1 : 0 , shelfHeight).sendToTarget();
- }
-
- @WorkerThread
- private void setShelfHeightAsync(int visibleInt, int shelfHeight) {
- boolean visible = visibleInt != 0;
- boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight;
- IPip pip = mPip;
- if (pip != null && changed) {
- mLastShelfVisible = visible;
- mLastShelfHeight = shelfHeight;
- try {
- pip.setShelfHeight(visible, shelfHeight);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setShelfHeight visible: " + visible
- + " height: " + shelfHeight, e);
- }
- }
- }
-
- /**
- * Sets the height of the keep clear area that is going to be reported by
- * the Launcher for the Hotseat.
- */
- public void setLauncherKeepClearAreaHeight(boolean visible, int height) {
- Message.obtain(mAsyncHandler, MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT,
- visible ? 1 : 0 , height).sendToTarget();
- }
-
- @WorkerThread
- private void setLauncherKeepClearAreaHeight(int visibleInt, int height) {
- boolean visible = visibleInt != 0;
- boolean changed = visible != mLastLauncherKeepClearAreaHeightVisible
- || height != mLastLauncherKeepClearAreaHeight;
- IPip pip = mPip;
- if (pip != null && changed) {
- mLastLauncherKeepClearAreaHeightVisible = visible;
- mLastLauncherKeepClearAreaHeight = height;
- try {
- pip.setLauncherKeepClearAreaHeight(visible, height);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setLauncherKeepClearAreaHeight visible: " + visible
- + " height: " + height, e);
- }
- }
- }
-
- /**
- * Sets listener to get pip animation callbacks.
- */
- public void setPipAnimationListener(IPipAnimationListener listener) {
- if (mPip != null) {
- try {
- mPip.setPipAnimationListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
- }
- }
- mPipAnimationListener = listener;
- }
-
- /**
- * @return Destination bounds of auto-pip animation, {@code null} if the animation is not ready.
- */
- @Nullable
- public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
- PictureInPictureParams pictureInPictureParams, int launcherRotation,
- Rect hotseatKeepClearArea) {
- if (mPip != null) {
- try {
- return mPip.startSwipePipToHome(componentName, activityInfo,
- pictureInPictureParams, launcherRotation, hotseatKeepClearArea);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call startSwipePipToHome", e);
- }
- }
- return null;
- }
-
- /**
- * Notifies WM Shell that launcher has finished the preparation of the animation for swipe to
- * home. WM Shell can choose to fade out the overlay when entering PIP is finished, and WM Shell
- * should be responsible for cleaning up the overlay.
- */
- public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
- SurfaceControl overlay) {
- if (mPip != null) {
- try {
- mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call stopSwipePipToHome");
- }
- }
- }
-
- /**
- * Notifies WM Shell that launcher has aborted all the animation for swipe to home. WM Shell
- * can use this callback to clean up its internal states.
- */
- public void abortSwipePipToHome(int taskId, ComponentName componentName) {
- if (mPip != null) {
- try {
- mPip.abortSwipePipToHome(taskId, componentName);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call abortSwipePipToHome");
- }
- }
- }
-
- /**
- * Sets the next pip animation type to be the alpha animation.
- */
- public void setPipAnimationTypeToAlpha() {
- if (mPip != null) {
- try {
- mPip.setPipAnimationTypeToAlpha();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setPipAnimationTypeToAlpha", e);
- }
- }
- }
-
- /**
- * Sets the app icon size in pixel used by Launcher all apps.
- */
- public void setLauncherAppIconSize(int iconSizePx) {
- if (mPip != null) {
- try {
- mPip.setLauncherAppIconSize(iconSizePx);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setLauncherAppIconSize", e);
- }
- }
- }
-
- //
- // Bubbles
- //
-
- /**
- * Sets the listener to be notified of bubble state changes.
- */
- public void setBubblesListener(IBubblesListener listener) {
- if (mBubbles != null) {
- try {
- if (mBubblesListener != null) {
- // Clear out any previous listener
- mBubbles.unregisterBubbleListener(mBubblesListener);
- }
- if (listener != null) {
- mBubbles.registerBubbleListener(listener);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call registerBubblesListener");
- }
- }
- mBubblesListener = listener;
- }
-
- /**
- * Tells SysUI to show the bubble with the provided key.
- * @param key the key of the bubble to show.
- * @param bubbleBarOffsetX the offset of the bubble bar from the edge of the screen on the X
- * axis.
- * @param bubbleBarOffsetY the offset of the bubble bar from the edge of the screen on the Y
- * axis.
- */
- public void showBubble(String key, int bubbleBarOffsetX, int bubbleBarOffsetY) {
- if (mBubbles != null) {
- try {
- mBubbles.showBubble(key, bubbleBarOffsetX, bubbleBarOffsetY);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call showBubble");
- }
- }
- }
-
- /**
- * Tells SysUI to remove the bubble with the provided key.
- * @param key the key of the bubble to show.
- */
- public void removeBubble(String key) {
- if (mBubbles == null) return;
- try {
- mBubbles.removeBubble(key);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call removeBubble");
- }
- }
-
- /**
- * Tells SysUI to remove all bubbles.
- */
- public void removeAllBubbles() {
- if (mBubbles == null) return;
- try {
- mBubbles.removeAllBubbles();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call removeAllBubbles");
- }
- }
-
- /**
- * Tells SysUI to collapse the bubbles.
- */
- public void collapseBubbles() {
- if (mBubbles != null) {
- try {
- mBubbles.collapseBubbles();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call collapseBubbles");
- }
- }
- }
-
- /**
- * Tells SysUI when the bubble is being dragged.
- * Should be called only when the bubble bar is expanded.
- * @param bubbleKey the key of the bubble to collapse/expand
- * @param isBeingDragged whether the bubble is being dragged
- */
- public void onBubbleDrag(@Nullable String bubbleKey, boolean isBeingDragged) {
- if (mBubbles == null) return;
- try {
- mBubbles.onBubbleDrag(bubbleKey, isBeingDragged);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onBubbleDrag");
- }
- }
-
- /**
- * Tells SysUI to show user education relative to the reference point provided.
- * @param position the bubble bar top center position in Screen coordinates.
- */
- public void showUserEducation(Point position) {
- try {
- mBubbles.showUserEducation(position.x, position.y);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call showUserEducation");
- }
- }
-
- //
- // Splitscreen
- //
-
- public void registerSplitScreenListener(ISplitScreenListener listener) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.registerSplitScreenListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call registerSplitScreenListener");
- }
- }
- mSplitScreenListener = listener;
- }
-
- public void unregisterSplitScreenListener(ISplitScreenListener listener) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.unregisterSplitScreenListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call unregisterSplitScreenListener");
- }
- }
- mSplitScreenListener = null;
- }
-
- public void registerSplitSelectListener(ISplitSelectListener listener) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.registerSplitSelectListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call registerSplitSelectListener");
- }
- }
- mSplitSelectListener = listener;
- }
-
- public void unregisterSplitSelectListener(ISplitSelectListener listener) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.unregisterSplitSelectListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call unregisterSplitSelectListener");
- }
- }
- mSplitSelectListener = null;
- }
-
- /** Start multiple tasks in split-screen simultaneously. */
- public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2,
- @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition,
- RemoteTransition remoteTransition, InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition,
- snapPosition, remoteTransition, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage("startTasks", "RemoteException"), e);
- }
- }
- }
-
- public void startIntentAndTask(PendingIntent pendingIntent, int userId1, Bundle options1,
- int taskId, Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startIntentAndTask(pendingIntent, userId1, options1, taskId, options2,
- splitPosition, snapPosition, remoteTransition, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage("startIntentAndTask", "RemoteException"), e);
- }
- }
- }
-
- public void startIntents(PendingIntent pendingIntent1, int userId1,
- @Nullable ShortcutInfo shortcutInfo1, Bundle options1, PendingIntent pendingIntent2,
- int userId2, @Nullable ShortcutInfo shortcutInfo2, Bundle options2,
- @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition,
- RemoteTransition remoteTransition, InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startIntents(pendingIntent1, userId1, shortcutInfo1, options1,
- pendingIntent2, userId2, shortcutInfo2, options2, splitPosition,
- snapPosition, remoteTransition, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage("startIntents", "RemoteException"), e);
- }
- }
- }
-
- public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId,
- Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
- splitPosition, snapPosition, remoteTransition, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage("startShortcutAndTask", "RemoteException"), e);
- }
- }
- }
-
- /**
- * Start multiple tasks in split-screen simultaneously.
- */
- public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
- Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
- splitPosition, snapPosition, adapter, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startTasksWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1,
- Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, userId1,
- options1, taskId, options2, splitPosition, snapPosition, adapter,
- instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startIntentAndTaskWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1,
- int taskId, Bundle options2, @StagePosition int splitPosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
- taskId, options2, splitPosition, snapPosition, adapter, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startShortcutAndTaskWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- /**
- * Starts a pair of intents or shortcuts in split-screen using legacy transition. Passing a
- * non-null shortcut info means to start the app as a shortcut.
- */
- public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, int userId1,
- @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
- PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2,
- @Nullable Bundle options2, @StagePosition int sidePosition,
- @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
- InstanceId instanceId) {
- if (mSystemUiProxy != null) {
- try {
- mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, userId1,
- shortcutInfo1, options1, pendingIntent2, userId2, shortcutInfo2, options2,
- sidePosition, snapPosition, adapter, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage(
- "startIntentsWithLegacyTransition", "RemoteException"), e);
- }
- }
- }
-
- public void startShortcut(String packageName, String shortcutId, int position,
- Bundle options, UserHandle user, InstanceId instanceId) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.startShortcut(packageName, shortcutId, position, options,
- user, instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage("startShortcut", "RemoteException"), e);
- }
- }
- }
-
- public void startIntent(PendingIntent intent, int userId, Intent fillInIntent, int position,
- Bundle options, InstanceId instanceId) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.startIntent(intent, userId, fillInIntent, position, options,
- instanceId);
- } catch (RemoteException e) {
- Log.w(TAG, splitFailureMessage("startIntent", "RemoteException"), e);
- }
- }
- }
-
- public void removeFromSideStage(int taskId) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.removeFromSideStage(taskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call removeFromSideStage");
- }
- }
- }
-
- /**
- * Call this when going to recents so that shell can set-up and provide appropriate leashes
- * for animation (eg. DividerBar).
- *
- * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
- */
- @Nullable
- public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
- if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS && mSplitScreen != null) {
- try {
- return mSplitScreen.onGoingToRecentsLegacy(apps);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onGoingToRecentsLegacy");
- }
- }
- return null;
- }
-
- @Nullable
- public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
- if (mSplitScreen != null) {
- try {
- return mSplitScreen.onStartingSplitLegacy(apps);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onStartingSplitLegacy");
- }
- }
- return null;
- }
-
- //
- // One handed
- //
-
- public void startOneHandedMode() {
- if (mOneHanded != null) {
- try {
- mOneHanded.startOneHanded();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call startOneHandedMode", e);
- }
- }
- }
-
- public void stopOneHandedMode() {
- if (mOneHanded != null) {
- try {
- mOneHanded.stopOneHanded();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call stopOneHandedMode", e);
- }
- }
- }
-
- //
- // Remote transitions
- //
-
- public void registerRemoteTransition(
- RemoteTransition remoteTransition, TransitionFilter filter) {
- if (mShellTransitions != null) {
- try {
- mShellTransitions.registerRemote(filter, remoteTransition);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call registerRemoteTransition");
- }
- }
- if (!mRemoteTransitions.containsKey(remoteTransition)) {
- mRemoteTransitions.put(remoteTransition, filter);
- }
- }
-
- public void unregisterRemoteTransition(RemoteTransition remoteTransition) {
- if (mShellTransitions != null) {
- try {
- mShellTransitions.unregisterRemote(remoteTransition);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call registerRemoteTransition");
- }
- }
- mRemoteTransitions.remove(remoteTransition);
- }
-
- public void setHomeTransitionListener(IHomeTransitionListener listener) {
- if (!FeatureFlags.enableHomeTransitionListener()) {
- return;
- }
-
- mHomeTransitionListener = listener;
-
- if (mShellTransitions != null) {
- try {
- mShellTransitions.setHomeTransitionListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setHomeTransitionListener", e);
- }
- } else {
- Log.w(TAG, "Unable to call setHomeTransitionListener because ShellTransitions is null");
- }
- }
-
- /**
- * Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary
- * if Launcher and SystemUI need to coordinate transactions (eg. for shell transitions).
- */
- public void shareTransactionQueue() {
- if (mOriginalTransactionToken == null) {
- mOriginalTransactionToken = SurfaceControl.Transaction.getDefaultApplyToken();
- }
- setupTransactionQueue();
- }
-
- /**
- * Switch back to using Launcher's independent transaction queue.
- */
- public void unshareTransactionQueue() {
- if (mOriginalTransactionToken == null) {
- return;
- }
- SurfaceControl.Transaction.setDefaultApplyToken(mOriginalTransactionToken);
- mOriginalTransactionToken = null;
- }
-
- private void setupTransactionQueue() {
- if (mOriginalTransactionToken == null) {
- return;
- }
- if (mShellTransitions == null) {
- SurfaceControl.Transaction.setDefaultApplyToken(mOriginalTransactionToken);
- return;
- }
- final IBinder shellApplyToken;
- try {
- shellApplyToken = mShellTransitions.getShellApplyToken();
- } catch (RemoteException e) {
- Log.e(TAG, "Error getting Shell's apply token", e);
- return;
- }
- if (shellApplyToken == null) {
- Log.e(TAG, "Didn't receive apply token from Shell");
- return;
- }
- SurfaceControl.Transaction.setDefaultApplyToken(shellApplyToken);
- }
-
- //
- // Starting window
- //
-
- /**
- * Sets listener to get callbacks when launching a task.
- */
- public void setStartingWindowListener(IStartingWindowListener listener) {
- if (mStartingWindow != null) {
- try {
- mStartingWindow.setStartingWindowListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setStartingWindowListener", e);
- }
- }
- mStartingWindowListener = listener;
- }
-
- //
- // SmartSpace transitions
- //
-
- /**
- * Sets the instance of {@link ILauncherUnlockAnimationController} that System UI should use to
- * control the launcher side of the unlock animation. This will also cause us to dispatch the
- * current state of the smartspace to System UI (this will subsequently happen if the state
- * changes).
- */
- public void setLauncherUnlockAnimationController(
- String activityClass, ILauncherUnlockAnimationController controller) {
- if (mSysuiUnlockAnimationController != null) {
- try {
- mSysuiUnlockAnimationController.setLauncherUnlockController(
- activityClass, controller);
- if (controller != null) {
- controller.dispatchSmartspaceStateToSysui();
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setLauncherUnlockAnimationController", e);
- }
- }
- mLauncherActivityClass = activityClass;
- mLauncherUnlockAnimationController = controller;
- }
-
- /**
- * Tells System UI that the Launcher's smartspace state has been updated, so that it can prepare
- * the unlock animation accordingly.
- */
- public void notifySysuiSmartspaceStateUpdated(SmartspaceState state) {
- if (mSysuiUnlockAnimationController != null) {
- try {
- mSysuiUnlockAnimationController.onLauncherSmartspaceStateUpdated(state);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call notifySysuiSmartspaceStateUpdated", e);
- e.printStackTrace();
- }
- }
- }
-
- //
- // Recents
- //
-
- public void registerRecentTasksListener(IRecentTasksListener listener) {
- if (mRecentTasks != null) {
- try {
- mRecentTasks.registerRecentTasksListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call registerRecentTasksListener", e);
- }
- }
- mRecentTasksListener = listener;
- }
-
- public void unregisterRecentTasksListener(IRecentTasksListener listener) {
- if (mRecentTasks != null) {
- try {
- mRecentTasks.unregisterRecentTasksListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call unregisterRecentTasksListener");
- }
- }
- mRecentTasksListener = null;
- }
-
- //
- // Back navigation transitions
- //
-
- /** Sets the launcher {@link android.window.IOnBackInvokedCallback} to shell */
- public void setBackToLauncherCallback(IOnBackInvokedCallback callback,
- IRemoteAnimationRunner runner) {
- mBackToLauncherCallback = callback;
- mBackToLauncherRunner = runner;
- if (mBackAnimation == null || mBackToLauncherCallback == null) {
- return;
- }
- try {
- mBackAnimation.setBackToLauncherCallback(callback, runner);
- } catch (RemoteException | SecurityException e) {
- Log.e(TAG, "Failed call setBackToLauncherCallback", e);
- }
- }
-
- /** Clears the previously registered {@link IOnBackInvokedCallback}.
- *
- * @param callback The previously registered callback instance.
- */
- public void clearBackToLauncherCallback(IOnBackInvokedCallback callback) {
- if (mBackToLauncherCallback != callback) {
- return;
- }
- mBackToLauncherCallback = null;
- mBackToLauncherRunner = null;
- if (mBackAnimation == null) {
- return;
- }
- try {
- mBackAnimation.clearBackToLauncherCallback();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed call clearBackToLauncherCallback", e);
- }
- }
-
- /**
- * Called when the status bar color needs to be customized when back navigation.
- */
- public void customizeStatusBarAppearance(AppearanceRegion appearance) {
- if (mBackAnimation == null) {
- return;
- }
- try {
- mBackAnimation.customizeStatusBarAppearance(appearance);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed call useLauncherSysBarFlags", e);
- }
- }
-
- public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
- if (mRecentTasks == null) {
- Log.w(TAG, "getRecentTasks() failed due to null mRecentTasks");
- return new ArrayList<>();
- }
- try {
- final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
- RECENT_IGNORE_UNAVAILABLE, userId);
- if (rawTasks == null) {
- return new ArrayList<>();
- }
- return new ArrayList<>(Arrays.asList(rawTasks));
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call getRecentTasks", e);
- return new ArrayList<>();
- }
- }
-
- /**
- * Gets the set of running tasks.
- */
- public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
- if (mRecentTasks != null
- && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
- try {
- return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call getRunningTasks", e);
- }
- }
- return new ArrayList<>();
- }
-
- private boolean handleMessageAsync(Message msg) {
- switch (msg.what) {
- case MSG_SET_SHELF_HEIGHT:
- setShelfHeightAsync(msg.arg1, msg.arg2);
- return true;
- case MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT:
- setLauncherKeepClearAreaHeight(msg.arg1, msg.arg2);
- return true;
- }
-
- return false;
- }
-
- //
- // Desktop Mode
- //
-
- /** Call shell to show all apps active on the desktop */
- public void showDesktopApps(int displayId, @Nullable RemoteTransition transition) {
- if (mDesktopMode != null) {
- try {
- mDesktopMode.showDesktopApps(displayId, transition);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call showDesktopApps", e);
- }
- }
- }
-
- /** Call shell to stash desktop apps */
- public void stashDesktopApps(int displayId) {
- if (mDesktopMode != null) {
- try {
- mDesktopMode.stashDesktopApps(displayId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call stashDesktopApps", e);
- }
- }
- }
-
- /** Call shell to hide desktop apps that may be stashed */
- public void hideStashedDesktopApps(int displayId) {
- if (mDesktopMode != null) {
- try {
- mDesktopMode.hideStashedDesktopApps(displayId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call hideStashedDesktopApps", e);
- }
- }
- }
-
- /**
- * If task with the given id is on the desktop, bring it to front
- */
- public void showDesktopApp(int taskId) {
- if (mDesktopMode != null) {
- try {
- mDesktopMode.showDesktopApp(taskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call showDesktopApp", e);
- }
- }
- }
-
- /** Call shell to get number of visible freeform tasks */
- public int getVisibleDesktopTaskCount(int displayId) {
- if (mDesktopMode != null) {
- try {
- return mDesktopMode.getVisibleTaskCount(displayId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call getVisibleDesktopTaskCount", e);
- }
- }
- return 0;
- }
-
- /** Set a listener on shell to get updates about desktop task state */
- public void setDesktopTaskListener(@Nullable IDesktopTaskListener listener) {
- mDesktopTaskListener = listener;
- if (mDesktopMode != null) {
- try {
- mDesktopMode.setTaskListener(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setDesktopTaskListener", e);
- }
- }
- }
-
- /** Perform cleanup transactions after animation to split select is complete */
- public void onDesktopSplitSelectAnimComplete(ActivityManager.RunningTaskInfo taskInfo) {
- if (mDesktopMode != null) {
- try {
- mDesktopMode.onDesktopSplitSelectAnimComplete(taskInfo);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call onDesktopSplitSelectAnimComplete", e);
- }
- }
- }
-
- //
- // Unfold transition
- //
-
- /** Sets the unfold animation lister to sysui. */
- public void setUnfoldAnimationListener(IUnfoldTransitionListener callback) {
- mUnfoldAnimationListener = callback;
- if (mUnfoldAnimation == null) {
- return;
- }
- try {
- Log.d(TAG, "Registering unfold animation receiver");
- mUnfoldAnimation.setListener(callback);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed call setUnfoldAnimationListener", e);
- }
- }
-
- //
- // Recents
- //
-
- /**
- * Starts the recents activity. The caller should manage the thread on which this is called.
- */
- public boolean startRecentsActivity(Intent intent, ActivityOptions options,
- RecentsAnimationListener listener) {
- if (mRecentTasks == null) {
- ActiveGestureLog.INSTANCE.addLog("Null mRecentTasks", RECENT_TASKS_MISSING);
- return false;
- }
- final IRecentsAnimationRunner runner = new IRecentsAnimationRunner.Stub() {
- @Override
- public void onAnimationStart(IRecentsAnimationController controller,
- RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
- Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
- // Aidl bundles need to explicitly set class loader
- // https://developer.android.com/guide/components/aidl#Bundles
- if (extras != null) {
- extras.setClassLoader(getClass().getClassLoader());
- }
- listener.onAnimationStart(new RecentsAnimationControllerCompat(controller), apps,
- wallpapers, homeContentInsets, minimizedHomeBounds, extras);
- }
-
- @Override
- public void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots) {
- listener.onAnimationCanceled(
- ThumbnailData.wrap(taskIds, taskSnapshots));
- }
-
- @Override
- public void onTasksAppeared(RemoteAnimationTarget[] apps) {
- listener.onTasksAppeared(apps);
- }
- };
- final Bundle optsBundle = options.toBundle();
- try {
- mRecentTasks.startRecentsTransition(mRecentsPendingIntent, intent, optsBundle,
- mContext.getIApplicationThread(), runner);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "Error starting recents via shell", e);
- return false;
- }
- }
-
- //
- // Drag and drop
- //
-
- /**
- * For testing purposes. Returns `true` only if the shell drop target has shown and
- * drawn and is ready to handle drag events and the subsequent drop.
- */
- public boolean isDragAndDropReady() {
- if (mDragAndDrop == null) {
- return false;
- }
- try {
- return mDragAndDrop.isReadyToHandleDrag();
- } catch (RemoteException e) {
- Log.e(TAG, "Error querying drag state", e);
- return false;
- }
- }
-
- public void dump(PrintWriter pw) {
- pw.println(TAG + ":");
-
- pw.println("\tmSystemUiProxy=" + mSystemUiProxy);
- pw.println("\tmPip=" + mPip);
- pw.println("\tmPipAnimationListener=" + mPipAnimationListener);
- pw.println("\tmBubbles=" + mBubbles);
- pw.println("\tmBubblesListener=" + mBubblesListener);
- pw.println("\tmSplitScreen=" + mSplitScreen);
- pw.println("\tmSplitScreenListener=" + mSplitScreenListener);
- pw.println("\tmSplitSelectListener=" + mSplitSelectListener);
- pw.println("\tmOneHanded=" + mOneHanded);
- pw.println("\tmShellTransitions=" + mShellTransitions);
- pw.println("\tmHomeTransitionListener=" + mHomeTransitionListener);
- pw.println("\tmStartingWindow=" + mStartingWindow);
- pw.println("\tmStartingWindowListener=" + mStartingWindowListener);
- pw.println("\tmSysuiUnlockAnimationController=" + mSysuiUnlockAnimationController);
- pw.println("\tmLauncherActivityClass=" + mLauncherActivityClass);
- pw.println("\tmLauncherUnlockAnimationController=" + mLauncherUnlockAnimationController);
- pw.println("\tmRecentTasks=" + mRecentTasks);
- pw.println("\tmRecentTasksListener=" + mRecentTasksListener);
- pw.println("\tmBackAnimation=" + mBackAnimation);
- pw.println("\tmBackToLauncherCallback=" + mBackToLauncherCallback);
- pw.println("\tmBackToLauncherRunner=" + mBackToLauncherRunner);
- pw.println("\tmDesktopMode=" + mDesktopMode);
- pw.println("\tmDesktopTaskListener=" + mDesktopTaskListener);
- pw.println("\tmUnfoldAnimation=" + mUnfoldAnimation);
- pw.println("\tmUnfoldAnimationListener=" + mUnfoldAnimationListener);
- pw.println("\tmDragAndDrop=" + mDragAndDrop);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
new file mode 100644
index 0000000..c70642a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
@@ -0,0 +1,1232 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep
+
+import android.app.ActivityManager
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityOptions
+import android.app.PendingIntent
+import android.app.PictureInPictureParams
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.ShortcutInfo
+import android.graphics.Point
+import android.graphics.Rect
+import android.os.Bundle
+import android.os.Handler
+import android.os.IBinder
+import android.os.Message
+import android.os.RemoteException
+import android.os.UserHandle
+import android.util.Log
+import android.view.IRecentsAnimationController
+import android.view.IRecentsAnimationRunner
+import android.view.IRemoteAnimationRunner
+import android.view.MotionEvent
+import android.view.RemoteAnimationAdapter
+import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
+import android.window.IOnBackInvokedCallback
+import android.window.RemoteTransition
+import android.window.TaskSnapshot
+import android.window.TransitionFilter
+import androidx.annotation.MainThread
+import androidx.annotation.WorkerThread
+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.Executors
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.MainThreadInitializedObject
+import com.android.launcher3.util.Preconditions
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.quickstep.util.ActiveGestureErrorDetector
+import com.android.quickstep.util.ActiveGestureLog
+import com.android.quickstep.util.AssistUtils
+import com.android.quickstep.util.LogUtils.splitFailureMessage
+import com.android.systemui.shared.recents.ISystemUiProxy
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.RecentsAnimationControllerCompat
+import com.android.systemui.shared.system.RecentsAnimationListener
+import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController
+import com.android.systemui.shared.system.smartspace.SmartspaceState
+import com.android.systemui.unfold.progress.IUnfoldAnimation
+import com.android.systemui.unfold.progress.IUnfoldTransitionListener
+import com.android.wm.shell.back.IBackAnimation
+import com.android.wm.shell.bubbles.IBubbles
+import com.android.wm.shell.bubbles.IBubblesListener
+import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition
+import com.android.wm.shell.desktopmode.IDesktopMode
+import com.android.wm.shell.desktopmode.IDesktopTaskListener
+import com.android.wm.shell.draganddrop.IDragAndDrop
+import com.android.wm.shell.onehanded.IOneHanded
+import com.android.wm.shell.pip.IPip
+import com.android.wm.shell.pip.IPipAnimationListener
+import com.android.wm.shell.recents.IRecentTasks
+import com.android.wm.shell.recents.IRecentTasksListener
+import com.android.wm.shell.splitscreen.ISplitScreen
+import com.android.wm.shell.splitscreen.ISplitScreenListener
+import com.android.wm.shell.splitscreen.ISplitSelectListener
+import com.android.wm.shell.startingsurface.IStartingWindow
+import com.android.wm.shell.startingsurface.IStartingWindowListener
+import com.android.wm.shell.transition.IHomeTransitionListener
+import com.android.wm.shell.transition.IShellTransitions
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import java.io.PrintWriter
+
+/** Holds the reference to SystemUI. */
+class SystemUiProxy(private val context: Context) {
+
+ private val asyncHandler = Handler(UI_HELPER_EXECUTOR.looper, this::handleMessageAsync)
+
+ /**
+ * This is a singleton pending intent that is used to start recents via Shell (which is a
+ * different process). It is bare-bones, so it's expected that the component and options will be
+ * provided via fill-in intent.
+ */
+ private val recentsPendingIntent =
+ PendingIntent.getActivity(
+ context,
+ 0,
+ Intent().setPackage(context.packageName),
+ PendingIntent.FLAG_MUTABLE or
+ PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT or
+ Intent.FILL_IN_COMPONENT,
+ ActivityOptions.makeBasic()
+ .setPendingIntentCreatorBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
+ )
+ .toBundle()
+ )
+
+ private val systemUiProxyDeathRecipient =
+ IBinder.DeathRecipient { Executors.MAIN_EXECUTOR.execute { clearProxy() } }
+
+ private var systemUiProxy: ISystemUiProxy? = null
+
+ private var pip: IPip? = null
+ private var bubbles: IBubbles? = null
+ private var sysuiUnlockAnimationController: ISysuiUnlockAnimationController? = null
+ private var splitScreen: ISplitScreen? = null
+ private var oneHanded: IOneHanded? = null
+ private var shellTransitions: IShellTransitions? = null
+ private var startingWindow: IStartingWindow? = null
+ private var recentTasks: IRecentTasks? = null
+ private var backAnimation: IBackAnimation? = null
+ private var desktopMode: IDesktopMode? = null
+ private var unfoldAnimation: IUnfoldAnimation? = null
+
+ // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
+ // yet, and we'll need to set/register these listeners with SysUI when they do. Note that it is
+ // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
+ // in case SysUI needs to rebind.
+ private var pipAnimationListener: IPipAnimationListener? = null
+ private var bubblesListener: IBubblesListener? = null
+ private var splitScreenListener: ISplitScreenListener? = null
+ private var splitSelectListener: ISplitSelectListener? = null
+ private var startingWindowListener: IStartingWindowListener? = null
+ private var launcherUnlockAnimationController: ILauncherUnlockAnimationController? = null
+ private var launcherActivityClass: String? = null
+ private var recentTasksListener: IRecentTasksListener? = null
+ private var unfoldAnimationListener: IUnfoldTransitionListener? = null
+ private var desktopTaskListener: IDesktopTaskListener? = null
+ private val remoteTransitions = LinkedHashMap<RemoteTransition, TransitionFilter>()
+ private var originalTransactionToken: IBinder? = null
+ private var backToLauncherCallback: IOnBackInvokedCallback? = null
+ private var backToLauncherRunner: IRemoteAnimationRunner? = null
+ private var dragAndDrop: IDragAndDrop? = null
+ private var homeTransitionListener: IHomeTransitionListener? = null
+
+ // Used to dedupe calls to SystemUI
+ private var lastShelfHeight = 0
+ private var lastShelfVisible = false
+
+ // Used to dedupe calls to SystemUI
+ private var lastLauncherKeepClearAreaHeight = 0
+ private var lastLauncherKeepClearAreaHeightVisible = false
+
+ // TODO(141886704): Find a way to remove this
+ var lastSystemUiStateFlags = 0
+
+ /**
+ * Sets proxy state, including death linkage, various listeners, and other configuration objects
+ */
+ @MainThread
+ fun setProxy(
+ proxy: ISystemUiProxy?,
+ pip: IPip?,
+ bubbles: IBubbles?,
+ splitScreen: ISplitScreen?,
+ oneHanded: IOneHanded?,
+ shellTransitions: IShellTransitions?,
+ startingWindow: IStartingWindow?,
+ recentTasks: IRecentTasks?,
+ sysuiUnlockAnimationController: ISysuiUnlockAnimationController?,
+ backAnimation: IBackAnimation?,
+ desktopMode: IDesktopMode?,
+ unfoldAnimation: IUnfoldAnimation?,
+ dragAndDrop: IDragAndDrop?
+ ) {
+ Preconditions.assertUIThread()
+ unlinkToDeath()
+ systemUiProxy = proxy
+ this.pip = pip
+ this.bubbles = bubbles
+ this.splitScreen = splitScreen
+ this.oneHanded = oneHanded
+ this.shellTransitions = shellTransitions
+ this.startingWindow = startingWindow
+ this.sysuiUnlockAnimationController = sysuiUnlockAnimationController
+ this.recentTasks = recentTasks
+ this.backAnimation = backAnimation
+ this.desktopMode = desktopMode
+ this.unfoldAnimation = unfoldAnimation
+ this.dragAndDrop = dragAndDrop
+ linkToDeath()
+ // re-attach the listeners once missing due to setProxy has not been initialized yet.
+ setPipAnimationListener(pipAnimationListener)
+ setBubblesListener(bubblesListener)
+ registerSplitScreenListener(splitScreenListener)
+ registerSplitSelectListener(splitSelectListener)
+ setHomeTransitionListener(homeTransitionListener)
+ setStartingWindowListener(startingWindowListener)
+ setLauncherUnlockAnimationController(
+ launcherActivityClass,
+ launcherUnlockAnimationController
+ )
+ LinkedHashMap(remoteTransitions).forEach(this::registerRemoteTransition)
+ setupTransactionQueue()
+ registerRecentTasksListener(recentTasksListener)
+ setBackToLauncherCallback(backToLauncherCallback, backToLauncherRunner)
+ setUnfoldAnimationListener(unfoldAnimationListener)
+ setDesktopTaskListener(desktopTaskListener)
+ setAssistantOverridesRequested(
+ AssistUtils.newInstance(context).sysUiAssistOverrideInvocationTypes
+ )
+ }
+
+ /**
+ * Clear the proxy to release held resources and turn the majority of its operations into no-ops
+ */
+ @MainThread
+ fun clearProxy() {
+ setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null)
+ }
+
+ val isActive: Boolean
+ get() = systemUiProxy != null
+
+ private fun linkToDeath() {
+ tryOrLog("Failed to link sysui proxy death recipient") {
+ systemUiProxy?.asBinder()?.linkToDeath(systemUiProxyDeathRecipient, 0 /* flags */)
+ }
+ }
+
+ private fun unlinkToDeath() {
+ systemUiProxy?.asBinder()?.unlinkToDeath(systemUiProxyDeathRecipient, 0 /* flags */)
+ }
+
+ fun onBackPressed() {
+ tryOrLog("Failed call onBackPressed") { systemUiProxy?.onBackPressed() }
+ }
+
+ fun onImeSwitcherPressed() {
+ tryOrLog("Failed call onImeSwitcherPressed") { systemUiProxy?.onImeSwitcherPressed() }
+ }
+
+ fun setHomeRotationEnabled(enabled: Boolean) {
+ tryOrLog("Failed call setHomeRotationEnabled") {
+ systemUiProxy?.setHomeRotationEnabled(enabled)
+ }
+ }
+
+ fun startScreenPinning(taskId: Int) {
+ tryOrLog("Failed call startScreenPinning") { systemUiProxy?.startScreenPinning(taskId) }
+ }
+
+ fun onOverviewShown(fromHome: Boolean, tag: String?) {
+ try {
+ systemUiProxy?.onOverviewShown(fromHome)
+ } catch (e: RemoteException) {
+ Log.w(tag, "Failed call onOverviewShown from: ${if (fromHome) "home" else "app"}", e)
+ }
+ }
+
+ @MainThread
+ fun onStatusBarTouchEvent(event: MotionEvent) {
+ Preconditions.assertUIThread()
+ tryOrLog("Failed call onStatusBarTouchEvent with arg: $event") {
+ systemUiProxy?.onStatusBarTouchEvent(event)
+ }
+ }
+
+ fun onStatusBarTrackpadEvent(event: MotionEvent) {
+ tryOrLog("Failed call onStatusBarTrackpadEvent with arg: $event") {
+ systemUiProxy?.onStatusBarTrackpadEvent(event)
+ }
+ }
+
+ fun onAssistantProgress(progress: Float) {
+ tryOrLog("Failed call onAssistantProgress with progress: $progress") {
+ systemUiProxy?.onAssistantProgress(progress)
+ }
+ }
+
+ fun onAssistantGestureCompletion(velocity: Float) {
+ tryOrLog("Failed call onAssistantGestureCompletion") {
+ systemUiProxy?.onAssistantGestureCompletion(velocity)
+ }
+ }
+
+ fun startAssistant(args: Bundle?) {
+ tryOrLog("Failed call startAssistant") { systemUiProxy?.startAssistant(args) }
+ }
+
+ fun setAssistantOverridesRequested(invocationTypes: IntArray?) {
+ tryOrLog("Failed call setAssistantOverridesRequested") {
+ systemUiProxy?.setAssistantOverridesRequested(invocationTypes)
+ }
+ }
+
+ fun animateNavBarLongPress(isTouchDown: Boolean, shrink:Boolean, durationMs: Long) {
+ tryOrLog("Failed call animateNavBarLongPress") {
+ systemUiProxy?.animateNavBarLongPress(isTouchDown, shrink, durationMs)
+ }
+ }
+
+ fun notifyAccessibilityButtonClicked(displayId: Int) {
+ tryOrLog("Failed call notifyAccessibilityButtonClicked") {
+ systemUiProxy?.notifyAccessibilityButtonClicked(displayId)
+ }
+ }
+
+ fun notifyAccessibilityButtonLongClicked() {
+ tryOrLog("Failed call notifyAccessibilityButtonLongClicked") {
+ systemUiProxy?.notifyAccessibilityButtonLongClicked()
+ }
+ }
+
+ fun stopScreenPinning() {
+ tryOrLog("Failed call stopScreenPinning") { systemUiProxy?.stopScreenPinning() }
+ }
+
+ fun notifyPrioritizedRotation(rotation: Int) {
+ tryOrLog("Failed call notifyPrioritizedRotation with arg: $rotation") {
+ systemUiProxy?.notifyPrioritizedRotation(rotation)
+ }
+ }
+
+ fun notifyTaskbarStatus(visible: Boolean, stashed: Boolean) {
+ tryOrLog("Failed call notifyTaskbarStatus with arg: $visible, $stashed") {
+ systemUiProxy?.notifyTaskbarStatus(visible, stashed)
+ }
+ }
+
+ /**
+ * NOTE: If called to suspend, caller MUST call this method to also un-suspend
+ *
+ * @param suspend should be true to stop auto-hide, false to resume normal behavior
+ */
+ fun notifyTaskbarAutohideSuspend(suspend: Boolean) {
+ tryOrLog("Failed call notifyTaskbarAutohideSuspend with arg: $suspend") {
+ systemUiProxy?.notifyTaskbarAutohideSuspend(suspend)
+ }
+ }
+
+ fun takeScreenshot(request: ScreenshotRequest?) {
+ tryOrLog("Failed call takeScreenshot") { systemUiProxy?.takeScreenshot(request) }
+ }
+
+ fun expandNotificationPanel() {
+ tryOrLog("Failed call expandNotificationPanel") { systemUiProxy?.expandNotificationPanel() }
+ }
+
+ fun toggleNotificationPanel() {
+ tryOrLog("Failed call toggleNotificationPanel") { systemUiProxy?.toggleNotificationPanel() }
+ }
+
+ //
+ // Pip
+ //
+ /** Sets the shelf height. */
+ fun setShelfHeight(visible: Boolean, shelfHeight: Int) {
+ Message.obtain(asyncHandler, MSG_SET_SHELF_HEIGHT, if (visible) 1 else 0, shelfHeight)
+ .sendToTarget()
+ }
+
+ @WorkerThread
+ private fun setShelfHeightAsync(visibleInt: Int, shelfHeight: Int) {
+ val visible = visibleInt != 0
+ if (visible == lastShelfVisible && shelfHeight == lastShelfHeight) return
+
+ pip?.let {
+ tryOrLog("Failed call setShelfHeight visible: $visible height: $shelfHeight") {
+ it.setShelfHeight(visible, shelfHeight)
+ lastShelfVisible = visible
+ lastShelfHeight = shelfHeight
+ }
+ }
+ }
+
+ /**
+ * Sets the height of the keep clear area that is going to be reported by the Launcher for the
+ * Hotseat.
+ */
+ fun setLauncherKeepClearAreaHeight(visible: Boolean, height: Int) {
+ Message.obtain(
+ asyncHandler,
+ MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT,
+ if (visible) 1 else 0,
+ height
+ )
+ .sendToTarget()
+ }
+
+ @WorkerThread
+ private fun setLauncherKeepClearAreaHeight(visibleInt: Int, height: Int) {
+ val visible = visibleInt != 0
+ if (
+ visible == lastLauncherKeepClearAreaHeightVisible &&
+ height == lastLauncherKeepClearAreaHeight
+ )
+ return
+
+ pip?.let {
+ tryOrLog("Failed call setLauncherKeepClearAreaHeight vis: $visible height: $height") {
+ it.setLauncherKeepClearAreaHeight(visible, height)
+ lastLauncherKeepClearAreaHeightVisible = visible
+ lastLauncherKeepClearAreaHeight = height
+ }
+ }
+ }
+
+ /** Sets listener to get pip animation callbacks. */
+ fun setPipAnimationListener(listener: IPipAnimationListener?) {
+ tryOrLog("Failed call setPinnedStackAnimationListener") {
+ pip?.setPipAnimationListener(listener)
+ }
+ pipAnimationListener = listener
+ }
+
+ /** @return Destination bounds of auto-pip animation, `null` if the animation is not ready. */
+ fun startSwipePipToHome(
+ componentName: ComponentName?,
+ activityInfo: ActivityInfo?,
+ pictureInPictureParams: PictureInPictureParams?,
+ launcherRotation: Int,
+ hotseatKeepClearArea: Rect?
+ ): Rect? {
+ return tryOrElse("Failed call startSwipePipToHome", null) {
+ return pip?.startSwipePipToHome(
+ componentName,
+ activityInfo,
+ pictureInPictureParams,
+ launcherRotation,
+ hotseatKeepClearArea
+ )
+ }
+ }
+
+ /**
+ * Notifies WM Shell that launcher has finished the preparation of the animation for swipe to
+ * home. WM Shell can choose to fade out the overlay when entering PIP is finished, and WM Shell
+ * should be responsible for cleaning up the overlay.
+ */
+ fun stopSwipePipToHome(
+ taskId: Int,
+ componentName: ComponentName?,
+ destinationBounds: Rect?,
+ overlay: SurfaceControl?
+ ) {
+ tryOrLog("Failed call stopSwipePipToHome") {
+ pip?.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay)
+ }
+ }
+
+ /**
+ * Notifies WM Shell that launcher has aborted all the animation for swipe to home. WM Shell can
+ * use this callback to clean up its internal states.
+ */
+ fun abortSwipePipToHome(taskId: Int, componentName: ComponentName?) {
+ tryOrLog("Failed call abortSwipePipToHome") {
+ pip?.abortSwipePipToHome(taskId, componentName)
+ }
+ }
+
+ /** Sets the next pip animation type to be the alpha animation. */
+ fun setPipAnimationTypeToAlpha() {
+ tryOrLog("Failed call setPipAnimationTypeToAlpha") { pip?.setPipAnimationTypeToAlpha() }
+ }
+
+ /** Sets the app icon size in pixel used by Launcher all apps. */
+ fun setLauncherAppIconSize(iconSizePx: Int) {
+ tryOrLog("Failed call setLauncherAppIconSize") { pip?.setLauncherAppIconSize(iconSizePx) }
+ }
+
+ //
+ // Bubbles
+ //
+ /** Sets the listener to be notified of bubble state changes. */
+ fun setBubblesListener(listener: IBubblesListener?) {
+ bubbles?.let {
+ tryOrLog("Failed call setLauncherAppIconSize") {
+ bubblesListener?.let(it::unregisterBubbleListener)
+ listener?.let(it::registerBubbleListener)
+ }
+ }
+ bubblesListener = listener
+ }
+
+ /**
+ * Tells SysUI to show the bubble with the provided key.
+ *
+ * @param key the key of the bubble to show.
+ * @param bubbleBarOffsetX the offset of the bubble bar from the edge of the screen on the X
+ * axis.
+ * @param bubbleBarOffsetY the offset of the bubble bar from the edge of the screen on the Y
+ * axis.
+ */
+ fun showBubble(key: String?, bubbleBarOffsetX: Int, bubbleBarOffsetY: Int) {
+ tryOrLog("Failed call showBubble") {
+ bubbles?.showBubble(key, bubbleBarOffsetX, bubbleBarOffsetY)
+ }
+ }
+
+ /**
+ * Tells SysUI to remove the bubble with the provided key.
+ *
+ * @param key the key of the bubble to show.
+ */
+ fun removeBubble(key: String?) {
+ tryOrLog("Failed call removeBubble") { bubbles?.removeBubble(key) }
+ }
+
+ /** Tells SysUI to remove all bubbles. */
+ fun removeAllBubbles() {
+ tryOrLog("Failed call removeAllBubbles") { bubbles?.removeAllBubbles() }
+ }
+
+ /** Tells SysUI to collapse the bubbles. */
+ fun collapseBubbles() {
+ tryOrLog("Failed call collapseBubbles") { bubbles?.collapseBubbles() }
+ }
+
+ /**
+ * Tells SysUI when the bubble is being dragged. Should be called only when the bubble bar is
+ * expanded.
+ *
+ * @param bubbleKey the key of the bubble to collapse/expand
+ * @param isBeingDragged whether the bubble is being dragged
+ */
+ fun onBubbleDrag(bubbleKey: String?, isBeingDragged: Boolean) {
+ tryOrLog("Failed call onBubbleDrag") { bubbles?.onBubbleDrag(bubbleKey, isBeingDragged) }
+ }
+
+ /**
+ * Tells SysUI to show user education relative to the reference point provided.
+ *
+ * @param position the bubble bar top center position in Screen coordinates.
+ */
+ fun showUserEducation(position: Point) {
+ tryOrLog("Failed call showUserEducation") {
+ bubbles?.showUserEducation(position.x, position.y)
+ }
+ }
+
+ //
+ // Splitscreen
+ //
+ fun registerSplitScreenListener(listener: ISplitScreenListener?) {
+ tryOrLog("Failed call registerSplitScreenListener") {
+ splitScreen?.registerSplitScreenListener(listener)
+ }
+ splitScreenListener = listener
+ }
+
+ fun registerSplitSelectListener(listener: ISplitSelectListener?) {
+ tryOrLog("Failed call registerSplitScreenListener") {
+ splitScreen?.registerSplitSelectListener(listener)
+ }
+ splitSelectListener = listener
+ }
+
+ /** Start multiple tasks in split-screen simultaneously. */
+ fun startTasks(
+ taskId1: Int,
+ options1: Bundle?,
+ taskId2: Int,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ remoteTransition: RemoteTransition?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startTasks", "RemoteException")) {
+ splitScreen?.startTasks(
+ taskId1,
+ options1,
+ taskId2,
+ options2,
+ splitPosition,
+ snapPosition,
+ remoteTransition,
+ instanceId
+ )
+ }
+ }
+
+ fun startIntentAndTask(
+ pendingIntent: PendingIntent?,
+ userId1: Int,
+ options1: Bundle?,
+ taskId: Int,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ remoteTransition: RemoteTransition?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startIntentAndTask", "RemoteException")) {
+ splitScreen?.startIntentAndTask(
+ pendingIntent,
+ userId1,
+ options1,
+ taskId,
+ options2,
+ splitPosition,
+ snapPosition,
+ remoteTransition,
+ instanceId
+ )
+ }
+ }
+
+ fun startIntents(
+ pendingIntent1: PendingIntent?,
+ userId1: Int,
+ shortcutInfo1: ShortcutInfo?,
+ options1: Bundle?,
+ pendingIntent2: PendingIntent?,
+ userId2: Int,
+ shortcutInfo2: ShortcutInfo?,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ remoteTransition: RemoteTransition?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startIntents", "RemoteException")) {
+ splitScreen?.startIntents(
+ pendingIntent1,
+ userId1,
+ shortcutInfo1,
+ options1,
+ pendingIntent2,
+ userId2,
+ shortcutInfo2,
+ options2,
+ splitPosition,
+ snapPosition,
+ remoteTransition,
+ instanceId
+ )
+ }
+ }
+
+ fun startShortcutAndTask(
+ shortcutInfo: ShortcutInfo?,
+ options1: Bundle?,
+ taskId: Int,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ remoteTransition: RemoteTransition?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startShortcutAndTask", "RemoteException")) {
+ splitScreen?.startShortcutAndTask(
+ shortcutInfo,
+ options1,
+ taskId,
+ options2,
+ splitPosition,
+ snapPosition,
+ remoteTransition,
+ instanceId
+ )
+ }
+ }
+
+ /** Start multiple tasks in split-screen simultaneously. */
+ fun startTasksWithLegacyTransition(
+ taskId1: Int,
+ options1: Bundle?,
+ taskId2: Int,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ adapter: RemoteAnimationAdapter?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startTasksWithLegacyTransition", "RemoteException")) {
+ splitScreen?.startTasksWithLegacyTransition(
+ taskId1,
+ options1,
+ taskId2,
+ options2,
+ splitPosition,
+ snapPosition,
+ adapter,
+ instanceId
+ )
+ }
+ }
+
+ fun startIntentAndTaskWithLegacyTransition(
+ pendingIntent: PendingIntent?,
+ userId1: Int,
+ options1: Bundle?,
+ taskId: Int,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ adapter: RemoteAnimationAdapter?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startIntentAndTaskWithLegacyTransition", "RemoteException")) {
+ splitScreen?.startIntentAndTaskWithLegacyTransition(
+ pendingIntent,
+ userId1,
+ options1,
+ taskId,
+ options2,
+ splitPosition,
+ snapPosition,
+ adapter,
+ instanceId
+ )
+ }
+ }
+
+ fun startShortcutAndTaskWithLegacyTransition(
+ shortcutInfo: ShortcutInfo?,
+ options1: Bundle?,
+ taskId: Int,
+ options2: Bundle?,
+ @StagePosition splitPosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ adapter: RemoteAnimationAdapter?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(
+ splitFailureMessage("startShortcutAndTaskWithLegacyTransition", "RemoteException")
+ ) {
+ splitScreen?.startShortcutAndTaskWithLegacyTransition(
+ shortcutInfo,
+ options1,
+ taskId,
+ options2,
+ splitPosition,
+ snapPosition,
+ adapter,
+ instanceId
+ )
+ }
+ }
+
+ /**
+ * Starts a pair of intents or shortcuts in split-screen using legacy transition. Passing a
+ * non-null shortcut info means to start the app as a shortcut.
+ */
+ fun startIntentsWithLegacyTransition(
+ pendingIntent1: PendingIntent?,
+ userId1: Int,
+ shortcutInfo1: ShortcutInfo?,
+ options1: Bundle?,
+ pendingIntent2: PendingIntent?,
+ userId2: Int,
+ shortcutInfo2: ShortcutInfo?,
+ options2: Bundle?,
+ @StagePosition sidePosition: Int,
+ @PersistentSnapPosition snapPosition: Int,
+ adapter: RemoteAnimationAdapter?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startIntentsWithLegacyTransition", "RemoteException")) {
+ splitScreen?.startIntentsWithLegacyTransition(
+ pendingIntent1,
+ userId1,
+ shortcutInfo1,
+ options1,
+ pendingIntent2,
+ userId2,
+ shortcutInfo2,
+ options2,
+ sidePosition,
+ snapPosition,
+ adapter,
+ instanceId
+ )
+ }
+ }
+
+ fun startShortcut(
+ packageName: String?,
+ shortcutId: String?,
+ position: Int,
+ options: Bundle?,
+ user: UserHandle?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startShortcut", "RemoteException")) {
+ splitScreen?.startShortcut(packageName, shortcutId, position, options, user, instanceId)
+ }
+ }
+
+ fun startIntent(
+ intent: PendingIntent?,
+ userId: Int,
+ fillInIntent: Intent?,
+ position: Int,
+ options: Bundle?,
+ instanceId: InstanceId?
+ ) {
+ tryOrLog(splitFailureMessage("startIntent", "RemoteException")) {
+ splitScreen?.startIntent(intent, userId, fillInIntent, position, options, instanceId)
+ }
+ }
+
+ /**
+ * Call this when going to recents so that shell can set-up and provide appropriate leashes for
+ * animation (eg. DividerBar).
+ *
+ * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
+ */
+ fun onGoingToRecentsLegacy(
+ apps: Array<RemoteAnimationTarget?>?
+ ): Array<RemoteAnimationTarget>? {
+ if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) return null
+ return tryOrElse("Failed call onGoingToRecentsLegacy", null) {
+ return splitScreen?.onGoingToRecentsLegacy(apps)
+ }
+ }
+
+ fun onStartingSplitLegacy(apps: Array<RemoteAnimationTarget?>?): Array<RemoteAnimationTarget>? {
+ return tryOrElse("Failed call onStartingSplitLegacy", null) {
+ return splitScreen?.onStartingSplitLegacy(apps)
+ }
+ }
+
+ //
+ // One handed
+ //
+ fun startOneHandedMode() {
+ tryOrLog("Failed call startOneHandedMode") { oneHanded?.startOneHanded() }
+ }
+
+ fun stopOneHandedMode() {
+ tryOrLog("Failed call startOneHandedstopOneHandedModeMode") { oneHanded?.stopOneHanded() }
+ }
+
+ //
+ // Remote transitions
+ //
+ fun registerRemoteTransition(remoteTransition: RemoteTransition, filter: TransitionFilter) {
+ tryOrLog("Failed call registerRemoteTransition") {
+ shellTransitions?.registerRemote(filter, remoteTransition)
+ }
+ if (!remoteTransitions.containsKey(remoteTransition)) {
+ remoteTransitions[remoteTransition] = filter
+ }
+ }
+
+ fun unregisterRemoteTransition(remoteTransition: RemoteTransition) {
+ tryOrLog("Failed call unregisterRemoteTransition") {
+ shellTransitions?.unregisterRemote(remoteTransition)
+ }
+ remoteTransitions.remove(remoteTransition)
+ }
+
+ fun setHomeTransitionListener(listener: IHomeTransitionListener?) {
+ if (!FeatureFlags.enableHomeTransitionListener()) return
+
+ homeTransitionListener = listener
+
+ tryOrLog("Failed call unregisterRemoteTransition") {
+ shellTransitions?.setHomeTransitionListener(listener)
+ ?: Log.w(
+ TAG,
+ "Unable to call setHomeTransitionListener because ShellTransitions is null"
+ )
+ }
+ }
+
+ /**
+ * Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary if
+ * Launcher and SystemUI need to coordinate transactions (eg. for shell transitions).
+ */
+ fun shareTransactionQueue() {
+ if (originalTransactionToken == null) {
+ originalTransactionToken = SurfaceControl.Transaction.getDefaultApplyToken()
+ }
+ setupTransactionQueue()
+ }
+
+ /** Switch back to using Launcher's independent transaction queue. */
+ fun unshareTransactionQueue() {
+ originalTransactionToken?.let { SurfaceControl.Transaction.setDefaultApplyToken(it) }
+ originalTransactionToken = null
+ }
+
+ private fun setupTransactionQueue() {
+ originalTransactionToken ?: return
+
+ var transitions = shellTransitions ?: run {
+ SurfaceControl.Transaction.setDefaultApplyToken(originalTransactionToken)
+ return
+ }
+ tryOrLog("Error getting Shell's apply token") {
+ transitions.getShellApplyToken()?.apply {
+ SurfaceControl.Transaction.setDefaultApplyToken(this)
+ } ?: Log.e(TAG, "Didn't receive apply token from Shell")
+ }
+ }
+
+ //
+ // Starting window
+ //
+ /** Sets listener to get callbacks when launching a task. */
+ fun setStartingWindowListener(listener: IStartingWindowListener?) {
+ tryOrLog("Failed call setStartingWindowListener") {
+ startingWindow?.setStartingWindowListener(listener)
+ }
+ startingWindowListener = listener
+ }
+
+ //
+ // SmartSpace transitions
+ //
+ /**
+ * Sets the instance of [ILauncherUnlockAnimationController] that System UI should use to
+ * control the launcher side of the unlock animation. This will also cause us to dispatch the
+ * current state of the smartspace to System UI (this will subsequently happen if the state
+ * changes).
+ */
+ fun setLauncherUnlockAnimationController(
+ activityClass: String?,
+ controller: ILauncherUnlockAnimationController?
+ ) {
+ tryOrLog("Failed call setLauncherUnlockAnimationController") {
+ sysuiUnlockAnimationController?.let {
+ it.setLauncherUnlockController(activityClass, controller)
+ controller?.dispatchSmartspaceStateToSysui()
+ }
+ }
+
+ launcherActivityClass = activityClass
+ launcherUnlockAnimationController = controller
+ }
+
+ /**
+ * Tells System UI that the Launcher's smartspace state has been updated, so that it can prepare
+ * the unlock animation accordingly.
+ */
+ fun notifySysuiSmartspaceStateUpdated(state: SmartspaceState?) {
+ tryOrLog("Failed call notifySysuiSmartspaceStateUpdated") {
+ sysuiUnlockAnimationController?.onLauncherSmartspaceStateUpdated(state)
+ }
+ }
+
+ //
+ // Recents
+ //
+ fun registerRecentTasksListener(listener: IRecentTasksListener?) {
+ tryOrLog("Failed call registerRecentTasksListener") {
+ recentTasks?.registerRecentTasksListener(listener)
+ }
+ recentTasksListener = listener
+ }
+
+ //
+ // Back navigation transitions
+ //
+ /** Sets the launcher [android.window.IOnBackInvokedCallback] to shell */
+ fun setBackToLauncherCallback(
+ callback: IOnBackInvokedCallback?,
+ runner: IRemoteAnimationRunner?
+ ) {
+ backToLauncherCallback = callback
+ backToLauncherRunner = runner
+
+ callback ?: return
+ tryOrLog("Failed call setBackToLauncherCallback") {
+ backAnimation?.setBackToLauncherCallback(callback, runner)
+ }
+ }
+
+ /**
+ * Clears the previously registered [IOnBackInvokedCallback].
+ *
+ * @param callback The previously registered callback instance.
+ */
+ fun clearBackToLauncherCallback(callback: IOnBackInvokedCallback) {
+ if (backToLauncherCallback != callback) {
+ return
+ }
+ backToLauncherCallback = null
+ backToLauncherRunner = null
+ tryOrLog("Failed call clearBackToLauncherCallback") {
+ backAnimation?.clearBackToLauncherCallback()
+ }
+ }
+
+ /** Called when the status bar color needs to be customized when back navigation. */
+ fun customizeStatusBarAppearance(appearance: AppearanceRegion?) {
+ tryOrLog("Failed call customizeStatusBarAppearance") {
+ backAnimation?.customizeStatusBarAppearance(appearance)
+ }
+ }
+
+ fun getRecentTasks(numTasks: Int, userId: Int): ArrayList<GroupedRecentTaskInfo> {
+ return tryOrElse("Failed call getRecentTasks", ArrayList()) {
+ return recentTasks
+ ?.getRecentTasks(numTasks, ActivityManager.RECENT_IGNORE_UNAVAILABLE, userId)
+ ?.let { ArrayList(it.asList()) }
+ ?: ArrayList()
+ }
+ }
+
+ /** Gets the set of running tasks. */
+ fun getRunningTasks(numTasks: Int): ArrayList<RunningTaskInfo> {
+ if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_PC)) {
+ return ArrayList()
+ }
+
+ return tryOrElse("Failed call getRunningTasks", ArrayList()) {
+ recentTasks?.getRunningTasks(numTasks)?.let { ArrayList(it.asList()) } ?: ArrayList()
+ }
+ }
+
+ private fun handleMessageAsync(msg: Message): Boolean {
+ when (msg.what) {
+ MSG_SET_SHELF_HEIGHT -> {
+ setShelfHeightAsync(msg.arg1, msg.arg2)
+ return true
+ }
+ MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT -> {
+ setLauncherKeepClearAreaHeight(msg.arg1, msg.arg2)
+ return true
+ }
+ }
+ return false
+ }
+
+ //
+ // Desktop Mode
+ //
+ /** Call shell to show all apps active on the desktop */
+ fun showDesktopApps(displayId: Int, transition: RemoteTransition?) {
+ tryOrLog("Failed call showDesktopApps") {
+ desktopMode?.showDesktopApps(displayId, transition)
+ }
+ }
+
+ /** Call shell to stash desktop apps */
+ fun stashDesktopApps(displayId: Int) {
+ tryOrLog("Failed call stashDesktopApps") { desktopMode?.stashDesktopApps(displayId) }
+ }
+
+ /** Call shell to hide desktop apps that may be stashed */
+ fun hideStashedDesktopApps(displayId: Int) {
+ tryOrLog("Failed call hideStashedDesktopApps") {
+ desktopMode?.hideStashedDesktopApps(displayId)
+ }
+ }
+
+ /** If task with the given id is on the desktop, bring it to front */
+ fun showDesktopApp(taskId: Int) {
+ tryOrLog("Failed call showDesktopApp") { desktopMode?.showDesktopApp(taskId) }
+ }
+
+ /** Call shell to get number of visible freeform tasks */
+ fun getVisibleDesktopTaskCount(displayId: Int): Int {
+ return tryOrElse("Failed call getVisibleDesktopTaskCount", 0) {
+ return desktopMode?.getVisibleTaskCount(displayId) ?: 0
+ }
+ }
+
+ /** Set a listener on shell to get updates about desktop task state */
+ fun setDesktopTaskListener(listener: IDesktopTaskListener?) {
+ desktopTaskListener = listener
+ tryOrLog("Failed call setDesktopTaskListener") { desktopMode?.setTaskListener(listener) }
+ }
+
+ /** Perform cleanup transactions after animation to split select is complete */
+ fun onDesktopSplitSelectAnimComplete(taskInfo: RunningTaskInfo?) {
+ tryOrLog("Failed call onDesktopSplitSelectAnimComplete") {
+ desktopMode?.onDesktopSplitSelectAnimComplete(taskInfo)
+ }
+ }
+ //
+ // Unfold transition
+ //
+ /** Sets the unfold animation lister to sysui. */
+ fun setUnfoldAnimationListener(callback: IUnfoldTransitionListener?) {
+ unfoldAnimationListener = callback
+ tryOrLog("Failed call setUnfoldAnimationListener") {
+ unfoldAnimation?.setListener(callback)
+ }
+ }
+
+ //
+ // Recents
+ //
+ /** Starts the recents activity. The caller should manage the thread on which this is called. */
+ fun startRecentsActivity(
+ intent: Intent?,
+ options: ActivityOptions,
+ listener: RecentsAnimationListener
+ ): Boolean {
+
+ val runner: IRecentsAnimationRunner =
+ object : IRecentsAnimationRunner.Stub() {
+ override fun onAnimationStart(
+ controller: IRecentsAnimationController,
+ apps: Array<RemoteAnimationTarget>,
+ wallpapers: Array<RemoteAnimationTarget>,
+ homeContentInsets: Rect,
+ minimizedHomeBounds: Rect,
+ extras: Bundle?
+ ) {
+ // Aidl bundles need to explicitly set class loader
+ // https://developer.android.com/guide/components/aidl#Bundles
+ extras?.classLoader = javaClass.classLoader
+ listener.onAnimationStart(
+ RecentsAnimationControllerCompat(controller),
+ apps,
+ wallpapers,
+ homeContentInsets,
+ minimizedHomeBounds,
+ extras
+ )
+ }
+
+ override fun onAnimationCanceled(
+ taskIds: IntArray,
+ taskSnapshots: Array<TaskSnapshot>
+ ) {
+ listener.onAnimationCanceled(ThumbnailData.wrap(taskIds, taskSnapshots))
+ }
+
+ override fun onTasksAppeared(apps: Array<RemoteAnimationTarget>) {
+ listener.onTasksAppeared(apps)
+ }
+ }
+
+ return tryOrElse("Error starting recents via shell", false) {
+ recentTasks?.let {
+ it.startRecentsTransition(
+ recentsPendingIntent,
+ intent,
+ options.toBundle(),
+ context.iApplicationThread,
+ runner
+ )
+ return true
+ }
+ ?: run {
+ ActiveGestureLog.INSTANCE.addLog(
+ "Null recentTasks",
+ ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING
+ )
+ false
+ }
+ }
+ }
+
+ //
+ // Drag and drop
+ //
+
+ /**
+ * For testing purposes. Returns `true` only if the shell drop target has shown and drawn and is
+ * ready to handle drag events and the subsequent drop.
+ */
+ val isDragAndDropReady: Boolean
+ get() =
+ tryOrElse("Error querying drag state", false) {
+ dragAndDrop?.isReadyToHandleDrag ?: false
+ }
+
+ fun dump(pw: PrintWriter) {
+ pw.println("$TAG:")
+ pw.println("\tsystemUiProxy=$systemUiProxy")
+ pw.println("\tpip=$pip")
+ pw.println("\tpipAnimationListener=$pipAnimationListener")
+ pw.println("\tbubbles=$bubbles")
+ pw.println("\tbubblesListener=$bubblesListener")
+ pw.println("\tsplitScreen=$splitScreen")
+ pw.println("\tsplitScreenListener=$splitScreenListener")
+ pw.println("\tsplitSelectListener=$splitSelectListener")
+ pw.println("\toneHanded=$oneHanded")
+ pw.println("\tshellTransitions=$shellTransitions")
+ pw.println("\thomeTransitionListener=$homeTransitionListener")
+ pw.println("\tstartingWindow=$startingWindow")
+ pw.println("\tstartingWindowListener=$startingWindowListener")
+ pw.println("\tsysuiUnlockAnimationController=$sysuiUnlockAnimationController")
+ pw.println("\tlauncherActivityClass=$launcherActivityClass")
+ pw.println("\tlauncherUnlockAnimationController=$launcherUnlockAnimationController")
+ pw.println("\trecentTasks=$recentTasks")
+ pw.println("\trecentTasksListener=$recentTasksListener")
+ pw.println("\tbackAnimation=$backAnimation")
+ pw.println("\tbackToLauncherCallback=$backToLauncherCallback")
+ pw.println("\tbackToLauncherRunner=$backToLauncherRunner")
+ pw.println("\tdesktopMode=$desktopMode")
+ pw.println("\tdesktopTaskListener=$desktopTaskListener")
+ pw.println("\tunfoldAnimation=$unfoldAnimation")
+ pw.println("\tunfoldAnimationListener=$unfoldAnimationListener")
+ pw.println("\tdragAndDrop=$dragAndDrop")
+ }
+
+ companion object {
+ private const val TAG = "SystemUiProxy"
+ private const val MSG_SET_SHELF_HEIGHT = 1
+ private const val MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT = 2
+
+ @JvmField
+ val INSTANCE = MainThreadInitializedObject { context: Context -> SystemUiProxy(context) }
+
+ private inline fun tryOrLog(msg: String, f: () -> Unit) =
+ try {
+ f()
+ } catch (e: RemoteException) {
+ Log.w(TAG, msg, e)
+ }
+
+ private inline fun <T> tryOrElse(msg: String, fallback: T, f: () -> T): T =
+ try {
+ f()
+ } catch (e: RemoteException) {
+ Log.w(TAG, msg, e)
+ fallback
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index e5fca4b..9e21595 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -195,11 +195,15 @@
return null;
}
- CancellableTask<ThumbnailData> request = new CancellableTask<ThumbnailData>() {
+ CancellableTask<ThumbnailData> request = new CancellableTask<>() {
@Override
public ThumbnailData getResultOnBg() {
- return ActivityManagerWrapper.getInstance().getTaskThumbnail(
+ ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance().getTaskThumbnail(
key.id, lowResolution);
+ if (thumbnailData.thumbnail != null) {
+ return thumbnailData;
+ }
+ return ActivityManagerWrapper.getInstance().takeTaskThumbnail(key.id);
}
@Override
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 137ffe8..025003b 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -432,7 +432,7 @@
<dimen name="split_instructions_start_margin_cancel">8dp</dimen>
<!-- Workspace grid visualization parameters -->
- <dimen name="grid_visualization_rounding_radius">28dp</dimen>
+ <dimen name="grid_visualization_rounding_radius">16dp</dimen>
<dimen name="grid_visualization_horizontal_cell_spacing">6dp</dimen>
<dimen name="grid_visualization_vertical_cell_spacing">6dp</dimen>
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index d8f6689..77eb07e 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -92,9 +92,6 @@
boolean isEnabled = !mAllApps.getAppsStore()
.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
- if (getCurrentState() == updatedState) {
- return;
- }
setCurrentState(updatedState);
resetPrivateSpaceDecorator(updatedState);
}
@@ -126,19 +123,27 @@
@VisibleForTesting
void resetPrivateSpaceDecorator(int updatedState) {
+ ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
if (updatedState == STATE_ENABLED) {
- // Add Private Space Decorator to the Recycler view.
+ // Create a new decorator instance if not already available.
if (mPrivateAppsSectionDecorator == null) {
mPrivateAppsSectionDecorator = new PrivateAppsSectionDecorator(
mAllApps.mActivityContext,
- mAllApps.mAH.get(MAIN).mAppsList);
+ mainAdapterHolder.mAppsList);
}
- mAllApps.mAH.get(MAIN).mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator);
+ for (int i = 0; i < mainAdapterHolder.mRecyclerView.getItemDecorationCount(); i++) {
+ if (mainAdapterHolder.mRecyclerView.getItemDecorationAt(i)
+ .equals(mPrivateAppsSectionDecorator)) {
+ // No need to add another decorator if one is already present in recycler view.
+ return;
+ }
+ }
+ // Add Private Space Decorator to the Recycler view.
+ mainAdapterHolder.mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator);
} else {
// Remove Private Space Decorator from the Recycler view.
if (mPrivateAppsSectionDecorator != null) {
- mAllApps.mAH.get(MAIN).mRecyclerView
- .removeItemDecoration(mPrivateAppsSectionDecorator);
+ mainAdapterHolder.mRecyclerView.removeItemDecoration(mPrivateAppsSectionDecorator);
}
}
}
diff --git a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
index 57fab2d..2dc8d81 100644
--- a/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/ItemFocusIndicatorHelper.java
@@ -29,8 +29,7 @@
import android.util.FloatProperty;
import android.view.View;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.Themes;
+import com.android.launcher3.R;
/**
* A helper class to draw background of a focused item.
@@ -103,9 +102,8 @@
setAlpha(0);
mShift = 0;
- if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
- mRadius = Themes.getDialogCornerRadius(container.getContext());
- }
+ mRadius = container.getResources().getDimensionPixelSize(
+ R.dimen.grid_visualization_rounding_radius);
}
protected void setAlpha(float alpha) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 1b1d347..40bb6ad 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -15,8 +15,8 @@
*/
package com.android.launcher3.testing;
-import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -297,8 +297,10 @@
}
protected boolean isLauncherInitialized() {
- return Launcher.ACTIVITY_TRACKER.getCreatedActivity() == null
- || LauncherAppState.getInstance(mContext).getModel().isModelLoaded();
+ Launcher launcher = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
+ return launcher == null
+ || (LauncherAppState.getInstance(mContext).getModel().isModelLoaded()
+ && !launcher.isBindingItems());
}
protected Activity getCurrentActivity() {
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 5ec1022..9855b20 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -105,6 +105,7 @@
mNavBarScrimPaint.setColor(navBarScrimColor);
invalidate();
}
+ setupNavBarColor();
}
@Override
@@ -218,10 +219,18 @@
}
protected void setupNavBarColor() {
- boolean isSheetDark = Themes.getAttrBoolean(getContext(), R.attr.isMainColorDark);
- getSystemUiController().updateUiState(
- SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
- isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
+ boolean isNavBarDark = Themes.getAttrBoolean(getContext(), R.attr.isMainColorDark);
+
+ // In light mode, landscape reverses navbar background color.
+ boolean isPhoneLandscape =
+ !mActivityContext.getDeviceProfile().isTablet && mInsets.bottom == 0;
+ if (!isNavBarDark && isPhoneLandscape) {
+ isNavBarDark = true;
+ }
+
+ getSystemUiController().updateUiState(SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
+ isNavBarDark ? SystemUiController.FLAG_DARK_NAV
+ : SystemUiController.FLAG_LIGHT_NAV);
}
protected SystemUiController getSystemUiController() {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index dbfe5ad..da90f17 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -24,7 +24,6 @@
import android.animation.Animator;
import android.content.Context;
-import android.content.pm.LauncherApps;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -106,9 +105,7 @@
private final UserHandle mCurrentUser = Process.myUserHandle();
private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter =
entry -> mCurrentUser.equals(entry.mPkgItem.user);
- private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
- entry -> !mCurrentUser.equals(entry.mPkgItem.user)
- && !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
+ private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter;
protected final boolean mHasWorkProfile;
protected boolean mHasRecommendedWidgets;
protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
@@ -182,20 +179,23 @@
public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mDeviceProfile = mActivityContext.getDeviceProfile();
- mHasWorkProfile = context.getSystemService(LauncherApps.class).getProfiles().size() > 1;
mOrientation = context.getResources().getConfiguration().orientation;
+ mUserCache = UserCache.INSTANCE.get(context);
+ mHasWorkProfile = mUserCache.getUserProfiles()
+ .stream()
+ .anyMatch(user -> mUserCache.getUserInfo(user).isWork());
+ mWorkWidgetsFilter = entry -> mHasWorkProfile
+ && mUserCache.getUserInfo(entry.mPkgItem.user).isWork();
mAdapters.put(AdapterHolder.PRIMARY, new AdapterHolder(AdapterHolder.PRIMARY));
mAdapters.put(AdapterHolder.WORK, new AdapterHolder(AdapterHolder.WORK));
mAdapters.put(AdapterHolder.SEARCH, new AdapterHolder(AdapterHolder.SEARCH));
Resources resources = getResources();
+ mUserManagerState.init(UserCache.INSTANCE.get(context),
+ context.getSystemService(UserManager.class));
mTabsHeight = mHasWorkProfile
? resources.getDimensionPixelSize(R.dimen.all_apps_header_pill_height)
: 0;
-
- mUserCache = UserCache.INSTANCE.get(context);
- mUserManagerState.init(UserCache.INSTANCE.get(context),
- context.getSystemService(UserManager.class));
}
public WidgetsFullSheet(Context context, AttributeSet attrs) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index dd8ab81..fb81700 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -585,6 +585,7 @@
if (hasSystemLauncherObject(OVERVIEW_RES_ID)) return "Overview";
if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace";
if (hasLauncherObject(APPS_RES_ID)) return "AllApps";
+ if (hasLauncherObject(TASKBAR_RES_ID)) return "Taskbar";
if (mDevice.hasObject(By.pkg(getLauncherPackageName()).depth(0))) {
return "<Launcher in invalid state>";
}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 8a34f0d..068482e 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,8 +16,6 @@
package com.android.launcher3.tapl;
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
import android.graphics.Rect;
import androidx.annotation.NonNull;
@@ -192,8 +190,8 @@
private List<Integer> getCurrentTasksCenterXList() {
return mLauncher.isTablet()
? mOverview.getCurrentTasksForTablet().stream()
- .map(OverviewTask::getTaskCenterX)
- .collect(Collectors.toList())
+ .map(OverviewTask::getTaskCenterX)
+ .collect(Collectors.toList())
: List.of(mOverview.getCurrentTask().getTaskCenterX());
}
@@ -203,11 +201,11 @@
public LaunchedAppState open() {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
verifyActiveContainer();
- mLauncher.executeAndWaitForEvent(
+ mLauncher.executeAndWaitForLauncherEvent(
() -> mLauncher.clickLauncherObject(mTask),
- event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
- () -> "Launching task didn't open a new window: "
- + mTask.getParent().getContentDescription(),
+ event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE
+ .equals(event.getClassName().toString()),
+ () -> "Launcher activity didn't stop",
"clicking an overview task");
if (mOverview.getContainerType()
== LauncherInstrumentation.ContainerType.SPLIT_SCREEN_SELECT) {