1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.quickstep;
17 
18 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
19 
20 import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
21 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
22 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
23 import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
24 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
25 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
26 import static com.android.window.flags.Flags.enableDesktopWindowingMode;
27 import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
28 
29 import android.app.ActivityManager;
30 import android.app.ActivityOptions;
31 import android.app.PendingIntent;
32 import android.app.PictureInPictureParams;
33 import android.content.ComponentName;
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.pm.ActivityInfo;
37 import android.content.pm.ShortcutInfo;
38 import android.graphics.Point;
39 import android.graphics.Rect;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.IBinder;
43 import android.os.IBinder.DeathRecipient;
44 import android.os.Message;
45 import android.os.RemoteException;
46 import android.os.UserHandle;
47 import android.util.Log;
48 import android.view.IRecentsAnimationController;
49 import android.view.IRecentsAnimationRunner;
50 import android.view.IRemoteAnimationRunner;
51 import android.view.MotionEvent;
52 import android.view.RemoteAnimationAdapter;
53 import android.view.RemoteAnimationTarget;
54 import android.view.SurfaceControl;
55 import android.window.IOnBackInvokedCallback;
56 import android.window.RemoteTransition;
57 import android.window.TaskSnapshot;
58 import android.window.TransitionFilter;
59 
60 import androidx.annotation.MainThread;
61 import androidx.annotation.Nullable;
62 import androidx.annotation.WorkerThread;
63 
64 import com.android.internal.logging.InstanceId;
65 import com.android.internal.util.ScreenshotRequest;
66 import com.android.internal.view.AppearanceRegion;
67 import com.android.launcher3.util.MainThreadInitializedObject;
68 import com.android.launcher3.util.Preconditions;
69 import com.android.launcher3.util.SafeCloseable;
70 import com.android.quickstep.util.ActiveGestureLog;
71 import com.android.quickstep.util.AssistUtils;
72 import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
73 import com.android.systemui.shared.recents.ISystemUiProxy;
74 import com.android.systemui.shared.recents.model.ThumbnailData;
75 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
76 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
77 import com.android.systemui.shared.system.RecentsAnimationListener;
78 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
79 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
80 import com.android.systemui.shared.system.smartspace.SmartspaceState;
81 import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
82 import com.android.systemui.unfold.progress.IUnfoldAnimation;
83 import com.android.systemui.unfold.progress.IUnfoldTransitionListener;
84 import com.android.wm.shell.back.IBackAnimation;
85 import com.android.wm.shell.bubbles.IBubbles;
86 import com.android.wm.shell.bubbles.IBubblesListener;
87 import com.android.wm.shell.common.bubbles.BubbleBarLocation;
88 import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
89 import com.android.wm.shell.common.pip.IPip;
90 import com.android.wm.shell.common.pip.IPipAnimationListener;
91 import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
92 import com.android.wm.shell.desktopmode.IDesktopMode;
93 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
94 import com.android.wm.shell.draganddrop.IDragAndDrop;
95 import com.android.wm.shell.onehanded.IOneHanded;
96 import com.android.wm.shell.recents.IRecentTasks;
97 import com.android.wm.shell.recents.IRecentTasksListener;
98 import com.android.wm.shell.shared.IShellTransitions;
99 import com.android.wm.shell.splitscreen.ISplitScreen;
100 import com.android.wm.shell.splitscreen.ISplitScreenListener;
101 import com.android.wm.shell.splitscreen.ISplitSelectListener;
102 import com.android.wm.shell.startingsurface.IStartingWindow;
103 import com.android.wm.shell.startingsurface.IStartingWindowListener;
104 import com.android.wm.shell.util.GroupedRecentTaskInfo;
105 
106 import java.io.PrintWriter;
107 import java.util.ArrayList;
108 import java.util.Arrays;
109 import java.util.LinkedHashMap;
110 import java.util.List;
111 
112 /**
113  * Holds the reference to SystemUI.
114  */
115 public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
116     private static final String TAG = "SystemUiProxy";
117 
118     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
119             new MainThreadInitializedObject<>(SystemUiProxy::new);
120 
121     private static final int MSG_SET_SHELF_HEIGHT = 1;
122     private static final int MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT = 2;
123 
124     private ISystemUiProxy mSystemUiProxy;
125     private IPip mPip;
126     private IBubbles mBubbles;
127     private ISysuiUnlockAnimationController mSysuiUnlockAnimationController;
128     private ISplitScreen mSplitScreen;
129     private IOneHanded mOneHanded;
130     private IShellTransitions mShellTransitions;
131     private IStartingWindow mStartingWindow;
132     private IRecentTasks mRecentTasks;
133     private IBackAnimation mBackAnimation;
134     private IDesktopMode mDesktopMode;
135     private IUnfoldAnimation mUnfoldAnimation;
136     private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
137         MAIN_EXECUTOR.execute(() -> clearProxy());
138     };
139 
140     // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
141     // yet, and we'll need to set/register these listeners with SysUI when they do.  Note that it is
142     // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
143     // in case SysUI needs to rebind.
144     private IPipAnimationListener mPipAnimationListener;
145     private IBubblesListener mBubblesListener;
146     private ISplitScreenListener mSplitScreenListener;
147     private ISplitSelectListener mSplitSelectListener;
148     private IStartingWindowListener mStartingWindowListener;
149     private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
150     private String mLauncherActivityClass;
151     private IRecentTasksListener mRecentTasksListener;
152     private IUnfoldTransitionListener mUnfoldAnimationListener;
153     private IDesktopTaskListener mDesktopTaskListener;
154     private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions =
155             new LinkedHashMap<>();
156 
157     private final List<Runnable> mStateChangeCallbacks = new ArrayList<>();
158 
159     private IBinder mOriginalTransactionToken = null;
160     private IOnBackInvokedCallback mBackToLauncherCallback;
161     private IRemoteAnimationRunner mBackToLauncherRunner;
162     private IDragAndDrop mDragAndDrop;
163     private final HomeVisibilityState mHomeVisibilityState = new HomeVisibilityState();
164 
165     // Used to dedupe calls to SystemUI
166     private int mLastShelfHeight;
167     private boolean mLastShelfVisible;
168 
169     // Used to dedupe calls to SystemUI
170     private int mLastLauncherKeepClearAreaHeight;
171     private boolean mLastLauncherKeepClearAreaHeightVisible;
172 
173     private final Context mContext;
174     private final Handler mAsyncHandler;
175 
176     // TODO(141886704): Find a way to remove this
177     @SystemUiStateFlags
178     private long mLastSystemUiStateFlags;
179 
180     /**
181      * This is a singleton pending intent that is used to start recents via Shell (which is a
182      * different process). It is bare-bones, so it's expected that the component and options will
183      * be provided via fill-in intent.
184      */
185     private final PendingIntent mRecentsPendingIntent;
186 
187     @Nullable
188     private final ProxyUnfoldTransitionProvider mUnfoldTransitionProvider;
189 
SystemUiProxy(Context context)190     private SystemUiProxy(Context context) {
191         mContext = context;
192         mAsyncHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessageAsync);
193         final Intent baseIntent = new Intent().setPackage(mContext.getPackageName());
194         final ActivityOptions options = ActivityOptions.makeBasic()
195                 .setPendingIntentCreatorBackgroundActivityStartMode(
196                         ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
197         mRecentsPendingIntent = PendingIntent.getActivity(mContext, 0, baseIntent,
198                 PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT
199                         | Intent.FILL_IN_COMPONENT, options.toBundle());
200 
201         mUnfoldTransitionProvider =
202                 (enableUnfoldStateAnimation() && new ResourceUnfoldTransitionConfig().isEnabled())
203                          ? new ProxyUnfoldTransitionProvider() : null;
204     }
205 
206     @Override
close()207     public void close() { }
208 
209     @Override
onBackPressed()210     public void onBackPressed() {
211         if (mSystemUiProxy != null) {
212             try {
213                 mSystemUiProxy.onBackPressed();
214             } catch (RemoteException e) {
215                 Log.w(TAG, "Failed call onBackPressed", e);
216             }
217         }
218     }
219 
220     @Override
onImeSwitcherPressed()221     public void onImeSwitcherPressed() {
222         if (mSystemUiProxy != null) {
223             try {
224                 mSystemUiProxy.onImeSwitcherPressed();
225             } catch (RemoteException e) {
226                 Log.w(TAG, "Failed call onImeSwitcherPressed", e);
227             }
228         }
229     }
230 
231     @Override
setHomeRotationEnabled(boolean enabled)232     public void setHomeRotationEnabled(boolean enabled) {
233         if (mSystemUiProxy != null) {
234             try {
235                 mSystemUiProxy.setHomeRotationEnabled(enabled);
236             } catch (RemoteException e) {
237                 Log.w(TAG, "Failed call onBackPressed", e);
238             }
239         }
240     }
241 
242     @Override
asBinder()243     public IBinder asBinder() {
244         // Do nothing
245         return null;
246     }
247 
248     /**
249      * Sets proxy state, including death linkage, various listeners, and other configuration objects
250      */
251     @MainThread
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)252     public void setProxy(ISystemUiProxy proxy, IPip pip, IBubbles bubbles, ISplitScreen splitScreen,
253             IOneHanded oneHanded, IShellTransitions shellTransitions,
254             IStartingWindow startingWindow, IRecentTasks recentTasks,
255             ISysuiUnlockAnimationController sysuiUnlockAnimationController,
256             IBackAnimation backAnimation, IDesktopMode desktopMode,
257             IUnfoldAnimation unfoldAnimation, IDragAndDrop dragAndDrop) {
258         Preconditions.assertUIThread();
259         unlinkToDeath();
260         mSystemUiProxy = proxy;
261         mPip = pip;
262         mBubbles = bubbles;
263         mSplitScreen = splitScreen;
264         mOneHanded = oneHanded;
265         mShellTransitions = shellTransitions;
266         mStartingWindow = startingWindow;
267         mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
268         mRecentTasks = recentTasks;
269         mBackAnimation = backAnimation;
270         mDesktopMode = desktopMode;
271         mUnfoldAnimation = enableUnfoldStateAnimation() ? null : unfoldAnimation;
272         mDragAndDrop = dragAndDrop;
273         linkToDeath();
274         // re-attach the listeners once missing due to setProxy has not been initialized yet.
275         setPipAnimationListener(mPipAnimationListener);
276         setBubblesListener(mBubblesListener);
277         registerSplitScreenListener(mSplitScreenListener);
278         registerSplitSelectListener(mSplitSelectListener);
279         mHomeVisibilityState.init(mShellTransitions);
280         setStartingWindowListener(mStartingWindowListener);
281         setLauncherUnlockAnimationController(
282                 mLauncherActivityClass, mLauncherUnlockAnimationController);
283         new LinkedHashMap<>(mRemoteTransitions).forEach(this::registerRemoteTransition);
284         setupTransactionQueue();
285         registerRecentTasksListener(mRecentTasksListener);
286         setBackToLauncherCallback(mBackToLauncherCallback, mBackToLauncherRunner);
287         setUnfoldAnimationListener(mUnfoldAnimationListener);
288         setDesktopTaskListener(mDesktopTaskListener);
289         setAssistantOverridesRequested(
290                 AssistUtils.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
291         mStateChangeCallbacks.forEach(Runnable::run);
292 
293         if (mUnfoldTransitionProvider != null) {
294             if (unfoldAnimation != null) {
295                 try {
296                     unfoldAnimation.setListener(mUnfoldTransitionProvider);
297                     mUnfoldTransitionProvider.setActive(true);
298                 } catch (RemoteException e) {
299                     // Ignore
300                 }
301             } else {
302                 mUnfoldTransitionProvider.setActive(false);
303             }
304         }
305     }
306 
307     /**
308      * Clear the proxy to release held resources and turn the majority of its operations into no-ops
309      */
310     @MainThread
clearProxy()311     public void clearProxy() {
312         setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
313     }
314 
315     /**
316      * Adds a callback to be notified whenever the active state changes
317      */
addOnStateChangeListener(Runnable callback)318     public void addOnStateChangeListener(Runnable callback) {
319         mStateChangeCallbacks.add(callback);
320     }
321 
322     /**
323      * Removes a previously added state change callback
324      */
removeOnStateChangeListener(Runnable callback)325     public void removeOnStateChangeListener(Runnable callback) {
326         mStateChangeCallbacks.remove(callback);
327     }
328 
329     // TODO(141886704): Find a way to remove this
setLastSystemUiStateFlags(@ystemUiStateFlags long stateFlags)330     public void setLastSystemUiStateFlags(@SystemUiStateFlags long stateFlags) {
331         mLastSystemUiStateFlags = stateFlags;
332     }
333 
334     // TODO(141886704): Find a way to remove this
335     @SystemUiStateFlags
getLastSystemUiStateFlags()336     public long getLastSystemUiStateFlags() {
337         return mLastSystemUiStateFlags;
338     }
339 
isActive()340     public boolean isActive() {
341         return mSystemUiProxy != null;
342     }
343 
linkToDeath()344     private void linkToDeath() {
345         if (mSystemUiProxy != null) {
346             try {
347                 mSystemUiProxy.asBinder().linkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
348             } catch (RemoteException e) {
349                 Log.e(TAG, "Failed to link sysui proxy death recipient");
350             }
351         }
352     }
353 
unlinkToDeath()354     private void unlinkToDeath() {
355         if (mSystemUiProxy != null) {
356             mSystemUiProxy.asBinder().unlinkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
357         }
358     }
359 
360     @Override
startScreenPinning(int taskId)361     public void startScreenPinning(int taskId) {
362         if (mSystemUiProxy != null) {
363             try {
364                 mSystemUiProxy.startScreenPinning(taskId);
365             } catch (RemoteException e) {
366                 Log.w(TAG, "Failed call startScreenPinning", e);
367             }
368         }
369     }
370 
371     @Override
onOverviewShown(boolean fromHome)372     public void onOverviewShown(boolean fromHome) {
373         onOverviewShown(fromHome, TAG);
374     }
375 
onOverviewShown(boolean fromHome, String tag)376     public void onOverviewShown(boolean fromHome, String tag) {
377         if (mSystemUiProxy != null) {
378             try {
379                 mSystemUiProxy.onOverviewShown(fromHome);
380             } catch (RemoteException e) {
381                 Log.w(tag, "Failed call onOverviewShown from: " + (fromHome ? "home" : "app"), e);
382             }
383         }
384     }
385 
386     @MainThread
387     @Override
onStatusBarTouchEvent(MotionEvent event)388     public void onStatusBarTouchEvent(MotionEvent event) {
389         Preconditions.assertUIThread();
390         if (mSystemUiProxy != null) {
391             try {
392                 mSystemUiProxy.onStatusBarTouchEvent(event);
393             } catch (RemoteException e) {
394                 Log.w(TAG, "Failed call onStatusBarTouchEvent with arg: " + event, e);
395             }
396         }
397     }
398 
399     @Override
onStatusBarTrackpadEvent(MotionEvent event)400     public void onStatusBarTrackpadEvent(MotionEvent event) {
401         if (mSystemUiProxy != null) {
402             try {
403                 mSystemUiProxy.onStatusBarTrackpadEvent(event);
404             } catch (RemoteException e) {
405                 Log.w(TAG, "Failed call onStatusBarTrackpadEvent with arg: " + event, e);
406             }
407         }
408     }
409 
410     @Override
onAssistantProgress(float progress)411     public void onAssistantProgress(float progress) {
412         if (mSystemUiProxy != null) {
413             try {
414                 mSystemUiProxy.onAssistantProgress(progress);
415             } catch (RemoteException e) {
416                 Log.w(TAG, "Failed call onAssistantProgress with progress: " + progress, e);
417             }
418         }
419     }
420 
421     @Override
onAssistantGestureCompletion(float velocity)422     public void onAssistantGestureCompletion(float velocity) {
423         if (mSystemUiProxy != null) {
424             try {
425                 mSystemUiProxy.onAssistantGestureCompletion(velocity);
426             } catch (RemoteException e) {
427                 Log.w(TAG, "Failed call onAssistantGestureCompletion", e);
428             }
429         }
430     }
431 
432     @Override
startAssistant(Bundle args)433     public void startAssistant(Bundle args) {
434         if (mSystemUiProxy != null) {
435             try {
436                 mSystemUiProxy.startAssistant(args);
437             } catch (RemoteException e) {
438                 Log.w(TAG, "Failed call startAssistant", e);
439             }
440         }
441     }
442 
443     @Override
setAssistantOverridesRequested(int[] invocationTypes)444     public void setAssistantOverridesRequested(int[] invocationTypes) {
445         if (mSystemUiProxy != null) {
446             try {
447                 mSystemUiProxy.setAssistantOverridesRequested(invocationTypes);
448             } catch (RemoteException e) {
449                 Log.w(TAG, "Failed call setAssistantOverridesRequested", e);
450             }
451         }
452     }
453 
454     @Override
animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs)455     public void animateNavBarLongPress(boolean isTouchDown, boolean shrink, long durationMs) {
456         if (mSystemUiProxy != null) {
457             try {
458                 mSystemUiProxy.animateNavBarLongPress(isTouchDown, shrink, durationMs);
459             } catch (RemoteException e) {
460                 Log.w(TAG, "Failed call animateNavBarLongPress", e);
461             }
462         }
463     }
464 
465     @Override
setOverrideHomeButtonLongPress(long duration, float slopMultiplier, boolean haptic)466     public void setOverrideHomeButtonLongPress(long duration, float slopMultiplier,
467             boolean haptic) {
468         if (mSystemUiProxy != null) {
469             try {
470                 mSystemUiProxy.setOverrideHomeButtonLongPress(duration, slopMultiplier, haptic);
471             } catch (RemoteException e) {
472                 Log.w(TAG, "Failed call setOverrideHomeButtonLongPress", e);
473             }
474         }
475     }
476 
477     @Override
notifyAccessibilityButtonClicked(int displayId)478     public void notifyAccessibilityButtonClicked(int displayId) {
479         if (mSystemUiProxy != null) {
480             try {
481                 mSystemUiProxy.notifyAccessibilityButtonClicked(displayId);
482             } catch (RemoteException e) {
483                 Log.w(TAG, "Failed call notifyAccessibilityButtonClicked", e);
484             }
485         }
486     }
487 
488     @Override
notifyAccessibilityButtonLongClicked()489     public void notifyAccessibilityButtonLongClicked() {
490         if (mSystemUiProxy != null) {
491             try {
492                 mSystemUiProxy.notifyAccessibilityButtonLongClicked();
493             } catch (RemoteException e) {
494                 Log.w(TAG, "Failed call notifyAccessibilityButtonLongClicked", e);
495             }
496         }
497     }
498 
499     @Override
stopScreenPinning()500     public void stopScreenPinning() {
501         if (mSystemUiProxy != null) {
502             try {
503                 mSystemUiProxy.stopScreenPinning();
504             } catch (RemoteException e) {
505                 Log.w(TAG, "Failed call stopScreenPinning", e);
506             }
507         }
508     }
509 
510     @Override
notifyPrioritizedRotation(int rotation)511     public void notifyPrioritizedRotation(int rotation) {
512         if (mSystemUiProxy != null) {
513             try {
514                 mSystemUiProxy.notifyPrioritizedRotation(rotation);
515             } catch (RemoteException e) {
516                 Log.w(TAG, "Failed call notifyPrioritizedRotation with arg: " + rotation, e);
517             }
518         }
519     }
520 
521     @Override
notifyTaskbarStatus(boolean visible, boolean stashed)522     public void notifyTaskbarStatus(boolean visible, boolean stashed) {
523         if (mSystemUiProxy != null) {
524             try {
525                 mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
526             } catch (RemoteException e) {
527                 Log.w(TAG, "Failed call notifyTaskbarStatus with arg: " +
528                         visible + ", " + stashed, e);
529             }
530         }
531     }
532 
533     /**
534      * NOTE: If called to suspend, caller MUST call this method to also un-suspend
535      * @param suspend should be true to stop auto-hide, false to resume normal behavior
536      */
537     @Override
notifyTaskbarAutohideSuspend(boolean suspend)538     public void notifyTaskbarAutohideSuspend(boolean suspend) {
539         if (mSystemUiProxy != null) {
540             try {
541                 mSystemUiProxy.notifyTaskbarAutohideSuspend(suspend);
542             } catch (RemoteException e) {
543                 Log.w(TAG, "Failed call notifyTaskbarAutohideSuspend with arg: " +
544                         suspend, e);
545             }
546         }
547     }
548 
549     @Override
takeScreenshot(ScreenshotRequest request)550     public void takeScreenshot(ScreenshotRequest request) {
551         if (mSystemUiProxy != null) {
552             try {
553                 mSystemUiProxy.takeScreenshot(request);
554             } catch (RemoteException e) {
555                 Log.w(TAG, "Failed call takeScreenshot");
556             }
557         }
558     }
559 
560     @Override
expandNotificationPanel()561     public void expandNotificationPanel() {
562         if (mSystemUiProxy != null) {
563             try {
564                 mSystemUiProxy.expandNotificationPanel();
565             } catch (RemoteException e) {
566                 Log.w(TAG, "Failed call expandNotificationPanel", e);
567             }
568         }
569     }
570 
571     @Override
toggleNotificationPanel()572     public void toggleNotificationPanel() {
573         if (mSystemUiProxy != null) {
574             try {
575                 mSystemUiProxy.toggleNotificationPanel();
576             } catch (RemoteException e) {
577                 Log.w(TAG, "Failed call toggleNotificationPanel", e);
578             }
579         }
580     }
581 
582     @Override
toggleQuickSettingsPanel()583     public void toggleQuickSettingsPanel() {
584         if (mSystemUiProxy != null) {
585             try {
586                 mSystemUiProxy.toggleQuickSettingsPanel();
587             } catch (RemoteException e) {
588                 Log.w(TAG, "Failed call toggleQuickSettingsPanel", e);
589             }
590         }
591     }
592 
593     //
594     // Pip
595     //
596 
597     /**
598      * Sets the shelf height.
599      */
setShelfHeight(boolean visible, int shelfHeight)600     public void setShelfHeight(boolean visible, int shelfHeight) {
601         Message.obtain(mAsyncHandler, MSG_SET_SHELF_HEIGHT,
602                 visible ? 1 : 0 , shelfHeight).sendToTarget();
603     }
604 
605     @WorkerThread
setShelfHeightAsync(int visibleInt, int shelfHeight)606     private void setShelfHeightAsync(int visibleInt, int shelfHeight) {
607         boolean visible = visibleInt != 0;
608         boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight;
609         IPip pip = mPip;
610         if (pip != null && changed) {
611             mLastShelfVisible = visible;
612             mLastShelfHeight = shelfHeight;
613             try {
614                 pip.setShelfHeight(visible, shelfHeight);
615             } catch (RemoteException e) {
616                 Log.w(TAG, "Failed call setShelfHeight visible: " + visible
617                         + " height: " + shelfHeight, e);
618             }
619         }
620     }
621 
622     /**
623      * Sets the height of the keep clear area that is going to be reported by
624      * the Launcher for the Hotseat.
625      */
setLauncherKeepClearAreaHeight(boolean visible, int height)626     public void setLauncherKeepClearAreaHeight(boolean visible, int height) {
627         Message.obtain(mAsyncHandler, MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT,
628                 visible ? 1 : 0 , height).sendToTarget();
629     }
630 
631     @WorkerThread
setLauncherKeepClearAreaHeight(int visibleInt, int height)632     private void setLauncherKeepClearAreaHeight(int visibleInt, int height) {
633         boolean visible = visibleInt != 0;
634         boolean changed = visible != mLastLauncherKeepClearAreaHeightVisible
635                 || height != mLastLauncherKeepClearAreaHeight;
636         IPip pip = mPip;
637         if (pip != null && changed) {
638             mLastLauncherKeepClearAreaHeightVisible = visible;
639             mLastLauncherKeepClearAreaHeight = height;
640             try {
641                 pip.setLauncherKeepClearAreaHeight(visible, height);
642             } catch (RemoteException e) {
643                 Log.w(TAG, "Failed call setLauncherKeepClearAreaHeight visible: " + visible
644                         + " height: " + height, e);
645             }
646         }
647     }
648 
649     /**
650      * Sets listener to get pip animation callbacks.
651      */
setPipAnimationListener(IPipAnimationListener listener)652     public void setPipAnimationListener(IPipAnimationListener listener) {
653         if (mPip != null) {
654             try {
655                 mPip.setPipAnimationListener(listener);
656             } catch (RemoteException e) {
657                 Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
658             }
659         }
660         mPipAnimationListener = listener;
661     }
662 
663     /**
664      * @return Destination bounds of auto-pip animation, {@code null} if the animation is not ready.
665      */
666     @Nullable
startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, PictureInPictureParams pictureInPictureParams, int launcherRotation, Rect hotseatKeepClearArea)667     public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
668             PictureInPictureParams pictureInPictureParams, int launcherRotation,
669             Rect hotseatKeepClearArea) {
670         if (mPip != null) {
671             try {
672                 return mPip.startSwipePipToHome(componentName, activityInfo,
673                         pictureInPictureParams, launcherRotation, hotseatKeepClearArea);
674             } catch (RemoteException e) {
675                 Log.w(TAG, "Failed call startSwipePipToHome", e);
676             }
677         }
678         return null;
679     }
680 
681     /**
682      * Notifies WM Shell that launcher has finished the preparation of the animation for swipe to
683      * home. WM Shell can choose to fade out the overlay when entering PIP is finished, and WM Shell
684      * should be responsible for cleaning up the overlay.
685      */
stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds, SurfaceControl overlay, Rect appBounds, Rect sourceRectHint)686     public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
687             SurfaceControl overlay, Rect appBounds, Rect sourceRectHint) {
688         if (mPip != null) {
689             try {
690                 mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay,
691                         appBounds, sourceRectHint);
692             } catch (RemoteException e) {
693                 Log.w(TAG, "Failed call stopSwipePipToHome");
694             }
695         }
696     }
697 
698     /**
699      * Notifies WM Shell that launcher has aborted all the animation for swipe to home. WM Shell
700      * can use this callback to clean up its internal states.
701      */
abortSwipePipToHome(int taskId, ComponentName componentName)702     public void abortSwipePipToHome(int taskId, ComponentName componentName) {
703         if (mPip != null) {
704             try {
705                 mPip.abortSwipePipToHome(taskId, componentName);
706             } catch (RemoteException e) {
707                 Log.w(TAG, "Failed call abortSwipePipToHome");
708             }
709         }
710     }
711 
712     /**
713      * Sets the next pip animation type to be the alpha animation.
714      */
setPipAnimationTypeToAlpha()715     public void setPipAnimationTypeToAlpha() {
716         if (mPip != null) {
717             try {
718                 mPip.setPipAnimationTypeToAlpha();
719             } catch (RemoteException e) {
720                 Log.w(TAG, "Failed call setPipAnimationTypeToAlpha", e);
721             }
722         }
723     }
724 
725     /**
726      * Sets the app icon size in pixel used by Launcher all apps.
727      */
setLauncherAppIconSize(int iconSizePx)728     public void setLauncherAppIconSize(int iconSizePx) {
729         if (mPip != null) {
730             try {
731                 mPip.setLauncherAppIconSize(iconSizePx);
732             } catch (RemoteException e) {
733                 Log.w(TAG, "Failed call setLauncherAppIconSize", e);
734             }
735         }
736     }
737 
738     //
739     // Bubbles
740     //
741 
742     /**
743      * Sets the listener to be notified of bubble state changes.
744      */
setBubblesListener(IBubblesListener listener)745     public void setBubblesListener(IBubblesListener listener) {
746         if (mBubbles != null) {
747             try {
748                 if (mBubblesListener != null) {
749                     // Clear out any previous listener
750                     mBubbles.unregisterBubbleListener(mBubblesListener);
751                 }
752                 if (listener != null) {
753                     mBubbles.registerBubbleListener(listener);
754                 }
755             } catch (RemoteException e) {
756                 Log.w(TAG, "Failed call registerBubblesListener");
757             }
758         }
759         mBubblesListener = listener;
760     }
761 
762     /**
763      * Tells SysUI to show the bubble with the provided key.
764      * @param key the key of the bubble to show.
765      * @param top top coordinate of bubble bar on screen
766      */
showBubble(String key, int top)767     public void showBubble(String key, int top) {
768         if (mBubbles != null) {
769             try {
770                 mBubbles.showBubble(key, top);
771             } catch (RemoteException e) {
772                 Log.w(TAG, "Failed call showBubble");
773             }
774         }
775     }
776 
777     /**
778      * Tells SysUI to remove all bubbles.
779      */
removeAllBubbles()780     public void removeAllBubbles() {
781         if (mBubbles == null) return;
782         try {
783             mBubbles.removeAllBubbles();
784         } catch (RemoteException e) {
785             Log.w(TAG, "Failed call removeAllBubbles");
786         }
787     }
788 
789     /**
790      * Tells SysUI to collapse the bubbles.
791      */
collapseBubbles()792     public void collapseBubbles() {
793         if (mBubbles != null) {
794             try {
795                 mBubbles.collapseBubbles();
796             } catch (RemoteException e) {
797                 Log.w(TAG, "Failed call collapseBubbles");
798             }
799         }
800     }
801 
802     /**
803      * Tells SysUI when the bubble is being dragged.
804      * Should be called only when the bubble bar is expanded.
805      * @param bubbleKey key of the bubble being dragged
806      */
startBubbleDrag(@ullable String bubbleKey)807     public void startBubbleDrag(@Nullable String bubbleKey) {
808         if (mBubbles == null) return;
809         try {
810             mBubbles.startBubbleDrag(bubbleKey);
811         } catch (RemoteException e) {
812             Log.w(TAG, "Failed call startBubbleDrag");
813         }
814     }
815 
816     /**
817      * Tells SysUI when the bubble stops being dragged.
818      * Should be called only when the bubble bar is expanded.
819      *
820      * @param location location of the bubble bar
821      * @param top      new top coordinate for bubble bar on screen
822      */
stopBubbleDrag(BubbleBarLocation location, int top)823     public void stopBubbleDrag(BubbleBarLocation location, int top) {
824         if (mBubbles == null) return;
825         try {
826             mBubbles.stopBubbleDrag(location, top);
827         } catch (RemoteException e) {
828             Log.w(TAG, "Failed call stopBubbleDrag");
829         }
830     }
831 
832     /**
833      * Tells SysUI to dismiss the bubble with the provided key.
834      * @param key the key of the bubble to dismiss.
835      */
dragBubbleToDismiss(String key)836     public void dragBubbleToDismiss(String key) {
837         if (mBubbles == null) return;
838         try {
839             mBubbles.dragBubbleToDismiss(key);
840         } catch (RemoteException e) {
841             Log.w(TAG, "Failed call dragBubbleToDismiss");
842         }
843     }
844 
845     /**
846      * Tells SysUI to show user education relative to the reference point provided.
847      * @param position the bubble bar top center position in Screen coordinates.
848      */
showUserEducation(Point position)849     public void showUserEducation(Point position) {
850         try {
851             mBubbles.showUserEducation(position.x, position.y);
852         } catch (RemoteException e) {
853             Log.w(TAG, "Failed call showUserEducation");
854         }
855     }
856 
857     /**
858      * Tells SysUI to update the bubble bar location to the new location.
859      * @param location new location for the bubble bar
860      */
setBubbleBarLocation(BubbleBarLocation location)861     public void setBubbleBarLocation(BubbleBarLocation location) {
862         try {
863             mBubbles.setBubbleBarLocation(location);
864         } catch (RemoteException e) {
865             Log.w(TAG, "Failed call setBubbleBarLocation");
866         }
867     }
868 
869     /**
870      * Tells SysUI the top coordinate of bubble bar on screen
871      *
872      * @param topOnScreen top coordinate for bubble bar on screen
873      */
updateBubbleBarTopOnScreen(int topOnScreen)874     public void updateBubbleBarTopOnScreen(int topOnScreen) {
875         try {
876             if (mBubbles != null) {
877                 mBubbles.updateBubbleBarTopOnScreen(topOnScreen);
878             }
879         } catch (RemoteException e) {
880             Log.w(TAG, "Failed call updateBubbleBarTopOnScreen");
881         }
882     }
883 
884     //
885     // Splitscreen
886     //
887 
registerSplitScreenListener(ISplitScreenListener listener)888     public void registerSplitScreenListener(ISplitScreenListener listener) {
889         if (mSplitScreen != null) {
890             try {
891                 mSplitScreen.registerSplitScreenListener(listener);
892             } catch (RemoteException e) {
893                 Log.w(TAG, "Failed call registerSplitScreenListener");
894             }
895         }
896         mSplitScreenListener = listener;
897     }
898 
unregisterSplitScreenListener(ISplitScreenListener listener)899     public void unregisterSplitScreenListener(ISplitScreenListener listener) {
900         if (mSplitScreen != null) {
901             try {
902                 mSplitScreen.unregisterSplitScreenListener(listener);
903             } catch (RemoteException e) {
904                 Log.w(TAG, "Failed call unregisterSplitScreenListener");
905             }
906         }
907         mSplitScreenListener = null;
908     }
909 
registerSplitSelectListener(ISplitSelectListener listener)910     public void registerSplitSelectListener(ISplitSelectListener listener) {
911         if (mSplitScreen != null) {
912             try {
913                 mSplitScreen.registerSplitSelectListener(listener);
914             } catch (RemoteException e) {
915                 Log.w(TAG, "Failed call registerSplitSelectListener");
916             }
917         }
918         mSplitSelectListener = listener;
919     }
920 
unregisterSplitSelectListener(ISplitSelectListener listener)921     public void unregisterSplitSelectListener(ISplitSelectListener listener) {
922         if (mSplitScreen != null) {
923             try {
924                 mSplitScreen.unregisterSplitSelectListener(listener);
925             } catch (RemoteException e) {
926                 Log.w(TAG, "Failed call unregisterSplitSelectListener");
927             }
928         }
929         mSplitSelectListener = null;
930     }
931 
932     /** Start multiple tasks in split-screen simultaneously. */
startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2, @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition, InstanceId instanceId)933     public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2,
934             @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition,
935             RemoteTransition remoteTransition, InstanceId instanceId) {
936         if (mSystemUiProxy != null) {
937             try {
938                 mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition,
939                         snapPosition, remoteTransition, instanceId);
940             } catch (RemoteException e) {
941                 Log.w(TAG, splitFailureMessage("startTasks", "RemoteException"), e);
942             }
943         }
944     }
945 
startIntentAndTask(PendingIntent pendingIntent, int userId1, Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition, InstanceId instanceId)946     public void startIntentAndTask(PendingIntent pendingIntent, int userId1, Bundle options1,
947             int taskId, Bundle options2, @StagePosition int splitPosition,
948             @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition,
949             InstanceId instanceId) {
950         if (mSystemUiProxy != null) {
951             try {
952                 mSplitScreen.startIntentAndTask(pendingIntent, userId1, options1, taskId, options2,
953                         splitPosition, snapPosition, remoteTransition, instanceId);
954             } catch (RemoteException e) {
955                 Log.w(TAG, splitFailureMessage("startIntentAndTask", "RemoteException"), e);
956             }
957         }
958     }
959 
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)960     public void startIntents(PendingIntent pendingIntent1, int userId1,
961             @Nullable ShortcutInfo shortcutInfo1, Bundle options1, PendingIntent pendingIntent2,
962             int userId2, @Nullable ShortcutInfo shortcutInfo2, Bundle options2,
963             @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition,
964             RemoteTransition remoteTransition, InstanceId instanceId) {
965         if (mSystemUiProxy != null) {
966             try {
967                 mSplitScreen.startIntents(pendingIntent1, userId1, shortcutInfo1, options1,
968                         pendingIntent2, userId2, shortcutInfo2, options2, splitPosition,
969                         snapPosition, remoteTransition, instanceId);
970             } catch (RemoteException e) {
971                 Log.w(TAG, splitFailureMessage("startIntents", "RemoteException"), e);
972             }
973         }
974     }
975 
startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition, InstanceId instanceId)976     public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId,
977             Bundle options2, @StagePosition int splitPosition,
978             @PersistentSnapPosition int snapPosition, RemoteTransition remoteTransition,
979             InstanceId instanceId) {
980         if (mSystemUiProxy != null) {
981             try {
982                 mSplitScreen.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
983                         splitPosition, snapPosition, remoteTransition, instanceId);
984             } catch (RemoteException e) {
985                 Log.w(TAG, splitFailureMessage("startShortcutAndTask", "RemoteException"), e);
986             }
987         }
988     }
989 
990     /**
991      * Start multiple tasks in split-screen simultaneously.
992      */
startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2, Bundle options2, @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId)993     public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
994             Bundle options2, @StagePosition int splitPosition,
995             @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
996             InstanceId instanceId) {
997         if (mSystemUiProxy != null) {
998             try {
999                 mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
1000                         splitPosition, snapPosition, adapter, instanceId);
1001             } catch (RemoteException e) {
1002                 Log.w(TAG, splitFailureMessage(
1003                         "startTasksWithLegacyTransition", "RemoteException"), e);
1004             }
1005         }
1006     }
1007 
startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1, Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId)1008     public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1,
1009             Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition,
1010             @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
1011             InstanceId instanceId) {
1012         if (mSystemUiProxy != null) {
1013             try {
1014                 mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, userId1,
1015                         options1, taskId, options2, splitPosition, snapPosition, adapter,
1016                         instanceId);
1017             } catch (RemoteException e) {
1018                 Log.w(TAG, splitFailureMessage(
1019                         "startIntentAndTaskWithLegacyTransition", "RemoteException"), e);
1020             }
1021         }
1022     }
1023 
startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition, @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId)1024     public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1,
1025             int taskId, Bundle options2, @StagePosition int splitPosition,
1026             @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
1027             InstanceId instanceId) {
1028         if (mSystemUiProxy != null) {
1029             try {
1030                 mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
1031                         taskId, options2, splitPosition, snapPosition, adapter, instanceId);
1032             } catch (RemoteException e) {
1033                 Log.w(TAG, splitFailureMessage(
1034                         "startShortcutAndTaskWithLegacyTransition", "RemoteException"), e);
1035             }
1036         }
1037     }
1038 
1039     /**
1040      * Starts a pair of intents or shortcuts in split-screen using legacy transition. Passing a
1041      * non-null shortcut info means to start the app as a shortcut.
1042      */
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)1043     public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, int userId1,
1044             @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
1045             PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2,
1046             @Nullable Bundle options2, @StagePosition int sidePosition,
1047             @PersistentSnapPosition int snapPosition, RemoteAnimationAdapter adapter,
1048             InstanceId instanceId) {
1049         if (mSystemUiProxy != null) {
1050             try {
1051                 mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, userId1,
1052                         shortcutInfo1, options1, pendingIntent2, userId2, shortcutInfo2, options2,
1053                         sidePosition, snapPosition, adapter, instanceId);
1054             } catch (RemoteException e) {
1055                 Log.w(TAG, splitFailureMessage(
1056                         "startIntentsWithLegacyTransition", "RemoteException"), e);
1057             }
1058         }
1059     }
1060 
startShortcut(String packageName, String shortcutId, int position, Bundle options, UserHandle user, InstanceId instanceId)1061     public void startShortcut(String packageName, String shortcutId, int position,
1062             Bundle options, UserHandle user, InstanceId instanceId) {
1063         if (mSplitScreen != null) {
1064             try {
1065                 mSplitScreen.startShortcut(packageName, shortcutId, position, options,
1066                         user, instanceId);
1067             } catch (RemoteException e) {
1068                 Log.w(TAG, splitFailureMessage("startShortcut", "RemoteException"), e);
1069             }
1070         }
1071     }
1072 
startIntent(PendingIntent intent, int userId, Intent fillInIntent, int position, Bundle options, InstanceId instanceId)1073     public void startIntent(PendingIntent intent, int userId, Intent fillInIntent, int position,
1074             Bundle options, InstanceId instanceId) {
1075         if (mSplitScreen != null) {
1076             try {
1077                 mSplitScreen.startIntent(intent, userId, fillInIntent, position, options,
1078                         instanceId);
1079             } catch (RemoteException e) {
1080                 Log.w(TAG, splitFailureMessage("startIntent", "RemoteException"), e);
1081             }
1082         }
1083     }
1084 
removeFromSideStage(int taskId)1085     public void removeFromSideStage(int taskId) {
1086         if (mSplitScreen != null) {
1087             try {
1088                 mSplitScreen.removeFromSideStage(taskId);
1089             } catch (RemoteException e) {
1090                 Log.w(TAG, "Failed call removeFromSideStage");
1091             }
1092         }
1093     }
1094 
1095     /**
1096      * Call this when going to recents so that shell can set-up and provide appropriate leashes
1097      * for animation (eg. DividerBar).
1098      *
1099      * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
1100      */
1101     @Nullable
onGoingToRecentsLegacy(RemoteAnimationTarget[] apps)1102     public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
1103         if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS && mSplitScreen != null) {
1104             try {
1105                 return mSplitScreen.onGoingToRecentsLegacy(apps);
1106             } catch (RemoteException e) {
1107                 Log.w(TAG, "Failed call onGoingToRecentsLegacy");
1108             }
1109         }
1110         return null;
1111     }
1112 
1113     @Nullable
onStartingSplitLegacy(RemoteAnimationTarget[] apps)1114     public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
1115         if (mSplitScreen != null) {
1116             try {
1117                 return mSplitScreen.onStartingSplitLegacy(apps);
1118             } catch (RemoteException e) {
1119                 Log.w(TAG, "Failed call onStartingSplitLegacy");
1120             }
1121         }
1122         return null;
1123     }
1124 
1125     //
1126     // One handed
1127     //
1128 
startOneHandedMode()1129     public void startOneHandedMode() {
1130         if (mOneHanded != null) {
1131             try {
1132                 mOneHanded.startOneHanded();
1133             } catch (RemoteException e) {
1134                 Log.w(TAG, "Failed call startOneHandedMode", e);
1135             }
1136         }
1137     }
1138 
stopOneHandedMode()1139     public void stopOneHandedMode() {
1140         if (mOneHanded != null) {
1141             try {
1142                 mOneHanded.stopOneHanded();
1143             } catch (RemoteException e) {
1144                 Log.w(TAG, "Failed call stopOneHandedMode", e);
1145             }
1146         }
1147     }
1148 
1149     //
1150     // Remote transitions
1151     //
1152 
registerRemoteTransition( RemoteTransition remoteTransition, TransitionFilter filter)1153     public void registerRemoteTransition(
1154             RemoteTransition remoteTransition, TransitionFilter filter) {
1155         if (mShellTransitions != null) {
1156             try {
1157                 mShellTransitions.registerRemote(filter, remoteTransition);
1158             } catch (RemoteException e) {
1159                 Log.w(TAG, "Failed call registerRemoteTransition");
1160             }
1161         }
1162         if (!mRemoteTransitions.containsKey(remoteTransition)) {
1163             mRemoteTransitions.put(remoteTransition, filter);
1164         }
1165     }
1166 
unregisterRemoteTransition(RemoteTransition remoteTransition)1167     public void unregisterRemoteTransition(RemoteTransition remoteTransition) {
1168         if (mShellTransitions != null) {
1169             try {
1170                 mShellTransitions.unregisterRemote(remoteTransition);
1171             } catch (RemoteException e) {
1172                 Log.w(TAG, "Failed call registerRemoteTransition");
1173             }
1174         }
1175         mRemoteTransitions.remove(remoteTransition);
1176     }
1177 
getHomeVisibilityState()1178     public HomeVisibilityState getHomeVisibilityState() {
1179         return mHomeVisibilityState;
1180     }
1181 
1182     /**
1183      * Returns a surface which can be used to attach overlays to home task or null if
1184      * the task doesn't exist or sysui is not connected
1185      */
1186     @Nullable
getHomeTaskOverlayContainer()1187     public SurfaceControl getHomeTaskOverlayContainer() {
1188         // Use a local reference as this method can be called on a worker thread, which can lead
1189         // to NullPointer exceptions if mShellTransitions is modified on the main thread.
1190         IShellTransitions shellTransitions = mShellTransitions;
1191         if (shellTransitions != null) {
1192             try {
1193                 return mShellTransitions.getHomeTaskOverlayContainer();
1194             } catch (RemoteException e) {
1195                 Log.w(TAG, "Failed call getOverlayContainerForTask", e);
1196             }
1197         }
1198         return null;
1199     }
1200 
1201     /**
1202      * Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary
1203      * if Launcher and SystemUI need to coordinate transactions (eg. for shell transitions).
1204      */
shareTransactionQueue()1205     public void shareTransactionQueue() {
1206         if (mOriginalTransactionToken == null) {
1207             mOriginalTransactionToken = SurfaceControl.Transaction.getDefaultApplyToken();
1208         }
1209         setupTransactionQueue();
1210     }
1211 
1212     /**
1213      * Switch back to using Launcher's independent transaction queue.
1214      */
unshareTransactionQueue()1215     public void unshareTransactionQueue() {
1216         if (mOriginalTransactionToken == null) {
1217             return;
1218         }
1219         SurfaceControl.Transaction.setDefaultApplyToken(mOriginalTransactionToken);
1220         mOriginalTransactionToken = null;
1221     }
1222 
setupTransactionQueue()1223     private void setupTransactionQueue() {
1224         if (mOriginalTransactionToken == null) {
1225             return;
1226         }
1227         if (mShellTransitions == null) {
1228             SurfaceControl.Transaction.setDefaultApplyToken(mOriginalTransactionToken);
1229             return;
1230         }
1231         final IBinder shellApplyToken;
1232         try {
1233             shellApplyToken = mShellTransitions.getShellApplyToken();
1234         } catch (RemoteException e) {
1235             Log.e(TAG, "Error getting Shell's apply token", e);
1236             return;
1237         }
1238         if (shellApplyToken == null) {
1239             Log.e(TAG, "Didn't receive apply token from Shell");
1240             return;
1241         }
1242         SurfaceControl.Transaction.setDefaultApplyToken(shellApplyToken);
1243     }
1244 
1245     //
1246     // Starting window
1247     //
1248 
1249     /**
1250      * Sets listener to get callbacks when launching a task.
1251      */
setStartingWindowListener(IStartingWindowListener listener)1252     public void setStartingWindowListener(IStartingWindowListener listener) {
1253         if (mStartingWindow != null) {
1254             try {
1255                 mStartingWindow.setStartingWindowListener(listener);
1256             } catch (RemoteException e) {
1257                 Log.w(TAG, "Failed call setStartingWindowListener", e);
1258             }
1259         }
1260         mStartingWindowListener = listener;
1261     }
1262 
1263     //
1264     // SmartSpace transitions
1265     //
1266 
1267     /**
1268      * Sets the instance of {@link ILauncherUnlockAnimationController} that System UI should use to
1269      * control the launcher side of the unlock animation. This will also cause us to dispatch the
1270      * current state of the smartspace to System UI (this will subsequently happen if the state
1271      * changes).
1272      */
setLauncherUnlockAnimationController( String activityClass, ILauncherUnlockAnimationController controller)1273     public void setLauncherUnlockAnimationController(
1274             String activityClass, ILauncherUnlockAnimationController controller) {
1275         if (mSysuiUnlockAnimationController != null) {
1276             try {
1277                 mSysuiUnlockAnimationController.setLauncherUnlockController(
1278                         activityClass, controller);
1279                 if (controller != null) {
1280                     controller.dispatchSmartspaceStateToSysui();
1281                 }
1282             } catch (RemoteException e) {
1283                 Log.w(TAG, "Failed call setLauncherUnlockAnimationController", e);
1284             }
1285         }
1286         mLauncherActivityClass = activityClass;
1287         mLauncherUnlockAnimationController = controller;
1288     }
1289 
1290     /**
1291      * Tells System UI that the Launcher's smartspace state has been updated, so that it can prepare
1292      * the unlock animation accordingly.
1293      */
notifySysuiSmartspaceStateUpdated(SmartspaceState state)1294     public void notifySysuiSmartspaceStateUpdated(SmartspaceState state) {
1295         if (mSysuiUnlockAnimationController != null) {
1296             try {
1297                 mSysuiUnlockAnimationController.onLauncherSmartspaceStateUpdated(state);
1298             } catch (RemoteException e) {
1299                 Log.w(TAG, "Failed call notifySysuiSmartspaceStateUpdated", e);
1300                 e.printStackTrace();
1301             }
1302         }
1303     }
1304 
1305     //
1306     // Recents
1307     //
1308 
registerRecentTasksListener(IRecentTasksListener listener)1309     public void registerRecentTasksListener(IRecentTasksListener listener) {
1310         if (mRecentTasks != null) {
1311             try {
1312                 mRecentTasks.registerRecentTasksListener(listener);
1313             } catch (RemoteException e) {
1314                 Log.w(TAG, "Failed call registerRecentTasksListener", e);
1315             }
1316         }
1317         mRecentTasksListener = listener;
1318     }
1319 
unregisterRecentTasksListener(IRecentTasksListener listener)1320     public void unregisterRecentTasksListener(IRecentTasksListener listener) {
1321         if (mRecentTasks != null) {
1322             try {
1323                 mRecentTasks.unregisterRecentTasksListener(listener);
1324             } catch (RemoteException e) {
1325                 Log.w(TAG, "Failed call unregisterRecentTasksListener");
1326             }
1327         }
1328         mRecentTasksListener = null;
1329     }
1330 
1331     //
1332     // Back navigation transitions
1333     //
1334 
1335     /** Sets the launcher {@link android.window.IOnBackInvokedCallback} to shell */
setBackToLauncherCallback(IOnBackInvokedCallback callback, IRemoteAnimationRunner runner)1336     public void setBackToLauncherCallback(IOnBackInvokedCallback callback,
1337             IRemoteAnimationRunner runner) {
1338         mBackToLauncherCallback = callback;
1339         mBackToLauncherRunner = runner;
1340         if (mBackAnimation == null || mBackToLauncherCallback == null) {
1341             return;
1342         }
1343         try {
1344             mBackAnimation.setBackToLauncherCallback(callback, runner);
1345         } catch (RemoteException | SecurityException e) {
1346             Log.e(TAG, "Failed call setBackToLauncherCallback", e);
1347         }
1348     }
1349 
1350     /** Clears the previously registered {@link IOnBackInvokedCallback}.
1351      *
1352      * @param callback The previously registered callback instance.
1353      */
clearBackToLauncherCallback(IOnBackInvokedCallback callback)1354     public void clearBackToLauncherCallback(IOnBackInvokedCallback callback) {
1355         if (mBackToLauncherCallback != callback) {
1356             return;
1357         }
1358         mBackToLauncherCallback = null;
1359         mBackToLauncherRunner = null;
1360         if (mBackAnimation == null) {
1361             return;
1362         }
1363         try {
1364             mBackAnimation.clearBackToLauncherCallback();
1365         } catch (RemoteException e) {
1366             Log.e(TAG, "Failed call clearBackToLauncherCallback", e);
1367         }
1368     }
1369 
1370     /**
1371      * Called when the status bar color needs to be customized when back navigation.
1372      */
customizeStatusBarAppearance(AppearanceRegion appearance)1373     public void customizeStatusBarAppearance(AppearanceRegion appearance) {
1374         if (mBackAnimation == null) {
1375             return;
1376         }
1377         try {
1378             mBackAnimation.customizeStatusBarAppearance(appearance);
1379         } catch (RemoteException e) {
1380             Log.e(TAG, "Failed call useLauncherSysBarFlags", e);
1381         }
1382     }
1383 
getRecentTasks(int numTasks, int userId)1384     public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
1385         if (mRecentTasks == null) {
1386             Log.w(TAG, "getRecentTasks() failed due to null mRecentTasks");
1387             return new ArrayList<>();
1388         }
1389         try {
1390             final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
1391                     RECENT_IGNORE_UNAVAILABLE, userId);
1392             if (rawTasks == null) {
1393                 return new ArrayList<>();
1394             }
1395             return new ArrayList<>(Arrays.asList(rawTasks));
1396         } catch (RemoteException e) {
1397             Log.w(TAG, "Failed call getRecentTasks", e);
1398             return new ArrayList<>();
1399         }
1400     }
1401 
1402     /**
1403      * Gets the set of running tasks.
1404      */
getRunningTasks(int numTasks)1405     public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
1406         if (mRecentTasks != null && shouldEnableRunningTasksForDesktopMode()) {
1407             try {
1408                 return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
1409             } catch (RemoteException e) {
1410                 Log.w(TAG, "Failed call getRunningTasks", e);
1411             }
1412         }
1413         return new ArrayList<>();
1414     }
1415 
shouldEnableRunningTasksForDesktopMode()1416     private boolean shouldEnableRunningTasksForDesktopMode() {
1417         // TODO(b/335401172): unify DesktopMode checks in Launcher
1418         return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
1419     }
1420 
handleMessageAsync(Message msg)1421     private boolean handleMessageAsync(Message msg) {
1422         switch (msg.what) {
1423             case MSG_SET_SHELF_HEIGHT:
1424                 setShelfHeightAsync(msg.arg1, msg.arg2);
1425                 return true;
1426             case MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT:
1427                 setLauncherKeepClearAreaHeight(msg.arg1, msg.arg2);
1428                 return true;
1429         }
1430 
1431         return false;
1432     }
1433 
1434     //
1435     // Desktop Mode
1436     //
1437 
1438     /** Call shell to show all apps active on the desktop */
showDesktopApps(int displayId, @Nullable RemoteTransition transition)1439     public void showDesktopApps(int displayId, @Nullable RemoteTransition transition) {
1440         if (mDesktopMode != null) {
1441             try {
1442                 mDesktopMode.showDesktopApps(displayId, transition);
1443             } catch (RemoteException e) {
1444                 Log.w(TAG, "Failed call showDesktopApps", e);
1445             }
1446         }
1447     }
1448 
1449     /**
1450      * If task with the given id is on the desktop, bring it to front
1451      */
showDesktopApp(int taskId)1452     public void showDesktopApp(int taskId) {
1453         if (mDesktopMode != null) {
1454             try {
1455                 mDesktopMode.showDesktopApp(taskId);
1456             } catch (RemoteException e) {
1457                 Log.w(TAG, "Failed call showDesktopApp", e);
1458             }
1459         }
1460     }
1461 
1462     /** Call shell to get number of visible freeform tasks */
getVisibleDesktopTaskCount(int displayId)1463     public int getVisibleDesktopTaskCount(int displayId) {
1464         if (mDesktopMode != null) {
1465             try {
1466                 return mDesktopMode.getVisibleTaskCount(displayId);
1467             } catch (RemoteException e) {
1468                 Log.w(TAG, "Failed call getVisibleDesktopTaskCount", e);
1469             }
1470         }
1471         return 0;
1472     }
1473 
1474     /** Set a listener on shell to get updates about desktop task state */
setDesktopTaskListener(@ullable IDesktopTaskListener listener)1475     public void setDesktopTaskListener(@Nullable IDesktopTaskListener listener) {
1476         mDesktopTaskListener = listener;
1477         if (mDesktopMode != null) {
1478             try {
1479                 mDesktopMode.setTaskListener(listener);
1480             } catch (RemoteException e) {
1481                 Log.w(TAG, "Failed call setDesktopTaskListener", e);
1482             }
1483         }
1484     }
1485 
1486     /** Perform cleanup transactions after animation to split select is complete */
onDesktopSplitSelectAnimComplete(ActivityManager.RunningTaskInfo taskInfo)1487     public void onDesktopSplitSelectAnimComplete(ActivityManager.RunningTaskInfo taskInfo) {
1488         if (mDesktopMode != null) {
1489             try {
1490                 mDesktopMode.onDesktopSplitSelectAnimComplete(taskInfo);
1491             } catch (RemoteException e) {
1492                 Log.w(TAG, "Failed call onDesktopSplitSelectAnimComplete", e);
1493             }
1494         }
1495     }
1496 
1497     /** Call shell to move a task with given `taskId` to desktop  */
moveToDesktop(int taskId, DesktopModeTransitionSource transitionSource)1498     public void moveToDesktop(int taskId, DesktopModeTransitionSource transitionSource) {
1499         if (mDesktopMode != null) {
1500             try {
1501                 mDesktopMode.moveToDesktop(taskId, transitionSource);
1502             } catch (RemoteException e) {
1503                 Log.w(TAG, "Failed call moveToDesktop", e);
1504             }
1505         }
1506     }
1507 
1508     //
1509     // Unfold transition
1510     //
1511 
1512     /** Sets the unfold animation lister to sysui. */
setUnfoldAnimationListener(IUnfoldTransitionListener callback)1513     public void setUnfoldAnimationListener(IUnfoldTransitionListener callback) {
1514         mUnfoldAnimationListener = callback;
1515         if (mUnfoldAnimation == null) {
1516             return;
1517         }
1518         try {
1519             Log.d(TAG, "Registering unfold animation receiver");
1520             mUnfoldAnimation.setListener(callback);
1521         } catch (RemoteException e) {
1522             Log.e(TAG, "Failed call setUnfoldAnimationListener", e);
1523         }
1524     }
1525 
1526     @Nullable
getUnfoldTransitionProvider()1527     public ProxyUnfoldTransitionProvider getUnfoldTransitionProvider() {
1528         return mUnfoldTransitionProvider;
1529     }
1530 
1531     //
1532     // Recents
1533     //
1534 
1535     /**
1536      * Starts the recents activity. The caller should manage the thread on which this is called.
1537      */
startRecentsActivity(Intent intent, ActivityOptions options, RecentsAnimationListener listener)1538     public boolean startRecentsActivity(Intent intent, ActivityOptions options,
1539             RecentsAnimationListener listener) {
1540         if (mRecentTasks == null) {
1541             ActiveGestureLog.INSTANCE.addLog("Null mRecentTasks", RECENT_TASKS_MISSING);
1542             return false;
1543         }
1544         final IRecentsAnimationRunner runner = new IRecentsAnimationRunner.Stub() {
1545             @Override
1546             public void onAnimationStart(IRecentsAnimationController controller,
1547                     RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
1548                     Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
1549                 // Aidl bundles need to explicitly set class loader
1550                 // https://developer.android.com/guide/components/aidl#Bundles
1551                 if (extras != null) {
1552                     extras.setClassLoader(getClass().getClassLoader());
1553                 }
1554                 listener.onAnimationStart(new RecentsAnimationControllerCompat(controller), apps,
1555                         wallpapers, homeContentInsets, minimizedHomeBounds, extras);
1556             }
1557 
1558             @Override
1559             public void onAnimationCanceled(int[] taskIds, TaskSnapshot[] taskSnapshots) {
1560                 listener.onAnimationCanceled(
1561                         ThumbnailData.wrap(taskIds, taskSnapshots));
1562             }
1563 
1564             @Override
1565             public void onTasksAppeared(RemoteAnimationTarget[] apps) {
1566                 listener.onTasksAppeared(apps);
1567             }
1568         };
1569         final Bundle optsBundle = options.toBundle();
1570         try {
1571             mRecentTasks.startRecentsTransition(mRecentsPendingIntent, intent, optsBundle,
1572                     mContext.getIApplicationThread(), runner);
1573             return true;
1574         } catch (RemoteException e) {
1575             Log.e(TAG, "Error starting recents via shell", e);
1576             return false;
1577         }
1578     }
1579 
1580     //
1581     // Drag and drop
1582     //
1583 
1584     /**
1585      * For testing purposes.  Returns `true` only if the shell drop target has shown and
1586      * drawn and is ready to handle drag events and the subsequent drop.
1587      */
isDragAndDropReady()1588     public boolean isDragAndDropReady() {
1589         if (mDragAndDrop == null) {
1590             return false;
1591         }
1592         try {
1593             return mDragAndDrop.isReadyToHandleDrag();
1594         } catch (RemoteException e) {
1595             Log.e(TAG, "Error querying drag state", e);
1596             return false;
1597         }
1598     }
1599 
dump(PrintWriter pw)1600     public void dump(PrintWriter pw) {
1601         pw.println(TAG + ":");
1602 
1603         pw.println("\tmSystemUiProxy=" + mSystemUiProxy);
1604         pw.println("\tmPip=" + mPip);
1605         pw.println("\tmPipAnimationListener=" + mPipAnimationListener);
1606         pw.println("\tmBubbles=" + mBubbles);
1607         pw.println("\tmBubblesListener=" + mBubblesListener);
1608         pw.println("\tmSplitScreen=" + mSplitScreen);
1609         pw.println("\tmSplitScreenListener=" + mSplitScreenListener);
1610         pw.println("\tmSplitSelectListener=" + mSplitSelectListener);
1611         pw.println("\tmOneHanded=" + mOneHanded);
1612         pw.println("\tmShellTransitions=" + mShellTransitions);
1613         pw.println("\tmHomeVisibilityState=" + mHomeVisibilityState);
1614         pw.println("\tmStartingWindow=" + mStartingWindow);
1615         pw.println("\tmStartingWindowListener=" + mStartingWindowListener);
1616         pw.println("\tmSysuiUnlockAnimationController=" + mSysuiUnlockAnimationController);
1617         pw.println("\tmLauncherActivityClass=" + mLauncherActivityClass);
1618         pw.println("\tmLauncherUnlockAnimationController=" + mLauncherUnlockAnimationController);
1619         pw.println("\tmRecentTasks=" + mRecentTasks);
1620         pw.println("\tmRecentTasksListener=" + mRecentTasksListener);
1621         pw.println("\tmBackAnimation=" + mBackAnimation);
1622         pw.println("\tmBackToLauncherCallback=" + mBackToLauncherCallback);
1623         pw.println("\tmBackToLauncherRunner=" + mBackToLauncherRunner);
1624         pw.println("\tmDesktopMode=" + mDesktopMode);
1625         pw.println("\tmDesktopTaskListener=" + mDesktopTaskListener);
1626         pw.println("\tmUnfoldAnimation=" + mUnfoldAnimation);
1627         pw.println("\tmUnfoldAnimationListener=" + mUnfoldAnimationListener);
1628         pw.println("\tmDragAndDrop=" + mDragAndDrop);
1629     }
1630 }
1631