• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.util.Executors.MAIN_EXECUTOR;
21 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
22 
23 import android.app.ActivityManager;
24 import android.app.PendingIntent;
25 import android.app.PictureInPictureParams;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.pm.ActivityInfo;
30 import android.content.pm.PackageManager;
31 import android.content.pm.ShortcutInfo;
32 import android.graphics.Rect;
33 import android.os.Bundle;
34 import android.os.Handler;
35 import android.os.IBinder;
36 import android.os.IBinder.DeathRecipient;
37 import android.os.Message;
38 import android.os.RemoteException;
39 import android.os.UserHandle;
40 import android.util.Log;
41 import android.view.MotionEvent;
42 import android.view.RemoteAnimationAdapter;
43 import android.view.RemoteAnimationTarget;
44 import android.view.SurfaceControl;
45 import android.window.IOnBackInvokedCallback;
46 import android.window.RemoteTransition;
47 import android.window.TransitionFilter;
48 
49 import androidx.annotation.Nullable;
50 import androidx.annotation.WorkerThread;
51 
52 import com.android.internal.logging.InstanceId;
53 import com.android.internal.util.ScreenshotRequest;
54 import com.android.launcher3.util.MainThreadInitializedObject;
55 import com.android.launcher3.util.SplitConfigurationOptions;
56 import com.android.systemui.shared.recents.ISystemUiProxy;
57 import com.android.systemui.shared.system.smartspace.ILauncherUnlockAnimationController;
58 import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController;
59 import com.android.systemui.shared.system.smartspace.SmartspaceState;
60 import com.android.systemui.unfold.progress.IUnfoldAnimation;
61 import com.android.systemui.unfold.progress.IUnfoldTransitionListener;
62 import com.android.wm.shell.back.IBackAnimation;
63 import com.android.wm.shell.desktopmode.IDesktopMode;
64 import com.android.wm.shell.onehanded.IOneHanded;
65 import com.android.wm.shell.pip.IPip;
66 import com.android.wm.shell.pip.IPipAnimationListener;
67 import com.android.wm.shell.recents.IRecentTasks;
68 import com.android.wm.shell.recents.IRecentTasksListener;
69 import com.android.wm.shell.splitscreen.ISplitScreen;
70 import com.android.wm.shell.splitscreen.ISplitScreenListener;
71 import com.android.wm.shell.startingsurface.IStartingWindow;
72 import com.android.wm.shell.startingsurface.IStartingWindowListener;
73 import com.android.wm.shell.transition.IShellTransitions;
74 import com.android.wm.shell.util.GroupedRecentTaskInfo;
75 
76 import java.util.ArrayList;
77 import java.util.Arrays;
78 import java.util.LinkedHashMap;
79 
80 /**
81  * Holds the reference to SystemUI.
82  */
83 public class SystemUiProxy implements ISystemUiProxy {
84     private static final String TAG = SystemUiProxy.class.getSimpleName();
85 
86     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
87             new MainThreadInitializedObject<>(SystemUiProxy::new);
88 
89     private static final int MSG_SET_SHELF_HEIGHT = 1;
90     private static final int MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT = 2;
91 
92     private ISystemUiProxy mSystemUiProxy;
93     private IPip mPip;
94     private ISysuiUnlockAnimationController mSysuiUnlockAnimationController;
95     private ISplitScreen mSplitScreen;
96     private IOneHanded mOneHanded;
97     private IShellTransitions mShellTransitions;
98     private IStartingWindow mStartingWindow;
99     private IRecentTasks mRecentTasks;
100     private IBackAnimation mBackAnimation;
101     private IDesktopMode mDesktopMode;
102     private IUnfoldAnimation mUnfoldAnimation;
103     private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
104         MAIN_EXECUTOR.execute(() -> clearProxy());
105     };
106 
107     // Save the listeners passed into the proxy since OverviewProxyService may not have been bound
108     // yet, and we'll need to set/register these listeners with SysUI when they do.  Note that it is
109     // up to the caller to clear the listeners to prevent leaks as these can be held indefinitely
110     // in case SysUI needs to rebind.
111     private IPipAnimationListener mPipAnimationListener;
112     private ISplitScreenListener mSplitScreenListener;
113     private IStartingWindowListener mStartingWindowListener;
114     private ILauncherUnlockAnimationController mLauncherUnlockAnimationController;
115     private IRecentTasksListener mRecentTasksListener;
116     private IUnfoldTransitionListener mUnfoldAnimationListener;
117     private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions =
118             new LinkedHashMap<>();
119     private IOnBackInvokedCallback mBackToLauncherCallback;
120 
121     // Used to dedupe calls to SystemUI
122     private int mLastShelfHeight;
123     private boolean mLastShelfVisible;
124 
125     // Used to dedupe calls to SystemUI
126     private int mLastLauncherKeepClearAreaHeight;
127     private boolean mLastLauncherKeepClearAreaHeightVisible;
128 
129     private final Context mContext;
130     private final Handler mAsyncHandler;
131 
132     // TODO(141886704): Find a way to remove this
133     private int mLastSystemUiStateFlags;
134 
SystemUiProxy(Context context)135     public SystemUiProxy(Context context) {
136         mContext = context;
137         mAsyncHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessageAsync);
138     }
139 
140     @Override
onBackPressed()141     public void onBackPressed() {
142         if (mSystemUiProxy != null) {
143             try {
144                 mSystemUiProxy.onBackPressed();
145             } catch (RemoteException e) {
146                 Log.w(TAG, "Failed call onBackPressed", e);
147             }
148         }
149     }
150 
151     @Override
onImeSwitcherPressed()152     public void onImeSwitcherPressed() {
153         if (mSystemUiProxy != null) {
154             try {
155                 mSystemUiProxy.onImeSwitcherPressed();
156             } catch (RemoteException e) {
157                 Log.w(TAG, "Failed call onImeSwitcherPressed", e);
158             }
159         }
160     }
161 
162     @Override
setHomeRotationEnabled(boolean enabled)163     public void setHomeRotationEnabled(boolean enabled) {
164         if (mSystemUiProxy != null) {
165             try {
166                 mSystemUiProxy.setHomeRotationEnabled(enabled);
167             } catch (RemoteException e) {
168                 Log.w(TAG, "Failed call onBackPressed", e);
169             }
170         }
171     }
172 
173     @Override
asBinder()174     public IBinder asBinder() {
175         // Do nothing
176         return null;
177     }
178 
setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen, IOneHanded oneHanded, IShellTransitions shellTransitions, IStartingWindow startingWindow, IRecentTasks recentTasks, ISysuiUnlockAnimationController sysuiUnlockAnimationController, IBackAnimation backAnimation, IDesktopMode desktopMode, IUnfoldAnimation unfoldAnimation)179     public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
180             IOneHanded oneHanded, IShellTransitions shellTransitions,
181             IStartingWindow startingWindow, IRecentTasks recentTasks,
182             ISysuiUnlockAnimationController sysuiUnlockAnimationController,
183             IBackAnimation backAnimation, IDesktopMode desktopMode,
184             IUnfoldAnimation unfoldAnimation) {
185         unlinkToDeath();
186         mSystemUiProxy = proxy;
187         mPip = pip;
188         mSplitScreen = splitScreen;
189         mOneHanded = oneHanded;
190         mShellTransitions = shellTransitions;
191         mStartingWindow = startingWindow;
192         mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
193         mRecentTasks = recentTasks;
194         mBackAnimation = backAnimation;
195         mDesktopMode = desktopMode;
196         mUnfoldAnimation = unfoldAnimation;
197         linkToDeath();
198         // re-attach the listeners once missing due to setProxy has not been initialized yet.
199         if (mPipAnimationListener != null && mPip != null) {
200             setPipAnimationListener(mPipAnimationListener);
201         }
202         if (mSplitScreenListener != null && mSplitScreen != null) {
203             registerSplitScreenListener(mSplitScreenListener);
204         }
205         if (mStartingWindowListener != null && mStartingWindow != null) {
206             setStartingWindowListener(mStartingWindowListener);
207         }
208         if (mSysuiUnlockAnimationController != null && mLauncherUnlockAnimationController != null) {
209             setLauncherUnlockAnimationController(mLauncherUnlockAnimationController);
210         }
211         new LinkedHashMap<>(mRemoteTransitions).forEach(this::registerRemoteTransition);
212         if (mRecentTasksListener != null && mRecentTasks != null) {
213             registerRecentTasksListener(mRecentTasksListener);
214         }
215         if (mBackAnimation != null && mBackToLauncherCallback != null) {
216             setBackToLauncherCallback(mBackToLauncherCallback);
217         }
218         if (unfoldAnimation != null && mUnfoldAnimationListener != null) {
219             setUnfoldAnimationListener(mUnfoldAnimationListener);
220         }
221     }
222 
clearProxy()223     public void clearProxy() {
224         setProxy(null, null, null, null, null, null, null, null, null, null, null);
225     }
226 
227     // TODO(141886704): Find a way to remove this
setLastSystemUiStateFlags(int stateFlags)228     public void setLastSystemUiStateFlags(int stateFlags) {
229         mLastSystemUiStateFlags = stateFlags;
230     }
231 
232     // TODO(141886704): Find a way to remove this
getLastSystemUiStateFlags()233     public int getLastSystemUiStateFlags() {
234         return mLastSystemUiStateFlags;
235     }
236 
isActive()237     public boolean isActive() {
238         return mSystemUiProxy != null;
239     }
240 
linkToDeath()241     private void linkToDeath() {
242         if (mSystemUiProxy != null) {
243             try {
244                 mSystemUiProxy.asBinder().linkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
245             } catch (RemoteException e) {
246                 Log.e(TAG, "Failed to link sysui proxy death recipient");
247             }
248         }
249     }
250 
unlinkToDeath()251     private void unlinkToDeath() {
252         if (mSystemUiProxy != null) {
253             mSystemUiProxy.asBinder().unlinkToDeath(mSystemUiProxyDeathRecipient, 0 /* flags */);
254         }
255     }
256 
257     @Override
startScreenPinning(int taskId)258     public void startScreenPinning(int taskId) {
259         if (mSystemUiProxy != null) {
260             try {
261                 mSystemUiProxy.startScreenPinning(taskId);
262             } catch (RemoteException e) {
263                 Log.w(TAG, "Failed call startScreenPinning", e);
264             }
265         }
266     }
267 
268     @Override
onOverviewShown(boolean fromHome)269     public void onOverviewShown(boolean fromHome) {
270         onOverviewShown(fromHome, TAG);
271     }
272 
onOverviewShown(boolean fromHome, String tag)273     public void onOverviewShown(boolean fromHome, String tag) {
274         if (mSystemUiProxy != null) {
275             try {
276                 mSystemUiProxy.onOverviewShown(fromHome);
277             } catch (RemoteException e) {
278                 Log.w(tag, "Failed call onOverviewShown from: " + (fromHome ? "home" : "app"), e);
279             }
280         }
281     }
282 
283     @Override
onStatusBarMotionEvent(MotionEvent event)284     public void onStatusBarMotionEvent(MotionEvent event) {
285         if (mSystemUiProxy != null) {
286             try {
287                 mSystemUiProxy.onStatusBarMotionEvent(event);
288             } catch (RemoteException e) {
289                 Log.w(TAG, "Failed call onStatusBarMotionEvent", e);
290             }
291         }
292     }
293 
294     @Override
onAssistantProgress(float progress)295     public void onAssistantProgress(float progress) {
296         if (mSystemUiProxy != null) {
297             try {
298                 mSystemUiProxy.onAssistantProgress(progress);
299             } catch (RemoteException e) {
300                 Log.w(TAG, "Failed call onAssistantProgress with progress: " + progress, e);
301             }
302         }
303     }
304 
305     @Override
onAssistantGestureCompletion(float velocity)306     public void onAssistantGestureCompletion(float velocity) {
307         if (mSystemUiProxy != null) {
308             try {
309                 mSystemUiProxy.onAssistantGestureCompletion(velocity);
310             } catch (RemoteException e) {
311                 Log.w(TAG, "Failed call onAssistantGestureCompletion", e);
312             }
313         }
314     }
315 
316     @Override
startAssistant(Bundle args)317     public void startAssistant(Bundle args) {
318         if (mSystemUiProxy != null) {
319             try {
320                 mSystemUiProxy.startAssistant(args);
321             } catch (RemoteException e) {
322                 Log.w(TAG, "Failed call startAssistant", e);
323             }
324         }
325     }
326 
327     @Override
notifyAccessibilityButtonClicked(int displayId)328     public void notifyAccessibilityButtonClicked(int displayId) {
329         if (mSystemUiProxy != null) {
330             try {
331                 mSystemUiProxy.notifyAccessibilityButtonClicked(displayId);
332             } catch (RemoteException e) {
333                 Log.w(TAG, "Failed call notifyAccessibilityButtonClicked", e);
334             }
335         }
336     }
337 
338     @Override
notifyAccessibilityButtonLongClicked()339     public void notifyAccessibilityButtonLongClicked() {
340         if (mSystemUiProxy != null) {
341             try {
342                 mSystemUiProxy.notifyAccessibilityButtonLongClicked();
343             } catch (RemoteException e) {
344                 Log.w(TAG, "Failed call notifyAccessibilityButtonLongClicked", e);
345             }
346         }
347     }
348 
349     @Override
stopScreenPinning()350     public void stopScreenPinning() {
351         if (mSystemUiProxy != null) {
352             try {
353                 mSystemUiProxy.stopScreenPinning();
354             } catch (RemoteException e) {
355                 Log.w(TAG, "Failed call stopScreenPinning", e);
356             }
357         }
358     }
359 
360     @Override
notifyPrioritizedRotation(int rotation)361     public void notifyPrioritizedRotation(int rotation) {
362         if (mSystemUiProxy != null) {
363             try {
364                 mSystemUiProxy.notifyPrioritizedRotation(rotation);
365             } catch (RemoteException e) {
366                 Log.w(TAG, "Failed call notifyPrioritizedRotation with arg: " + rotation, e);
367             }
368         }
369     }
370 
371     @Override
notifyTaskbarStatus(boolean visible, boolean stashed)372     public void notifyTaskbarStatus(boolean visible, boolean stashed) {
373         if (mSystemUiProxy != null) {
374             try {
375                 mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
376             } catch (RemoteException e) {
377                 Log.w(TAG, "Failed call notifyTaskbarStatus with arg: " +
378                         visible + ", " + stashed, e);
379             }
380         }
381     }
382 
383     /**
384      * NOTE: If called to suspend, caller MUST call this method to also un-suspend
385      * @param suspend should be true to stop auto-hide, false to resume normal behavior
386      */
387     @Override
notifyTaskbarAutohideSuspend(boolean suspend)388     public void notifyTaskbarAutohideSuspend(boolean suspend) {
389         if (mSystemUiProxy != null) {
390             try {
391                 mSystemUiProxy.notifyTaskbarAutohideSuspend(suspend);
392             } catch (RemoteException e) {
393                 Log.w(TAG, "Failed call notifyTaskbarAutohideSuspend with arg: " +
394                         suspend, e);
395             }
396         }
397     }
398 
399     @Override
takeScreenshot(ScreenshotRequest request)400     public void takeScreenshot(ScreenshotRequest request) {
401         if (mSystemUiProxy != null) {
402             try {
403                 mSystemUiProxy.takeScreenshot(request);
404             } catch (RemoteException e) {
405                 Log.w(TAG, "Failed call takeScreenshot");
406             }
407         }
408     }
409 
410     @Override
expandNotificationPanel()411     public void expandNotificationPanel() {
412         if (mSystemUiProxy != null) {
413             try {
414                 mSystemUiProxy.expandNotificationPanel();
415             } catch (RemoteException e) {
416                 Log.w(TAG, "Failed call expandNotificationPanel", e);
417             }
418         }
419     }
420 
421     @Override
toggleNotificationPanel()422     public void toggleNotificationPanel() {
423         if (mSystemUiProxy != null) {
424             try {
425                 mSystemUiProxy.toggleNotificationPanel();
426             } catch (RemoteException e) {
427                 Log.w(TAG, "Failed call toggleNotificationPanel", e);
428             }
429         }
430     }
431 
432     //
433     // Pip
434     //
435 
436     /**
437      * Sets the shelf height.
438      */
setShelfHeight(boolean visible, int shelfHeight)439     public void setShelfHeight(boolean visible, int shelfHeight) {
440         Message.obtain(mAsyncHandler, MSG_SET_SHELF_HEIGHT,
441                 visible ? 1 : 0 , shelfHeight).sendToTarget();
442     }
443 
444     @WorkerThread
setShelfHeightAsync(int visibleInt, int shelfHeight)445     private void setShelfHeightAsync(int visibleInt, int shelfHeight) {
446         boolean visible = visibleInt != 0;
447         boolean changed = visible != mLastShelfVisible || shelfHeight != mLastShelfHeight;
448         IPip pip = mPip;
449         if (pip != null && changed) {
450             mLastShelfVisible = visible;
451             mLastShelfHeight = shelfHeight;
452             try {
453                 pip.setShelfHeight(visible, shelfHeight);
454             } catch (RemoteException e) {
455                 Log.w(TAG, "Failed call setShelfHeight visible: " + visible
456                         + " height: " + shelfHeight, e);
457             }
458         }
459     }
460 
461     /**
462      * Sets the height of the keep clear area that is going to be reported by
463      * the Launcher for the Hotseat.
464      */
setLauncherKeepClearAreaHeight(boolean visible, int height)465     public void setLauncherKeepClearAreaHeight(boolean visible, int height) {
466         Message.obtain(mAsyncHandler, MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT,
467                 visible ? 1 : 0 , height).sendToTarget();
468     }
469 
470     @WorkerThread
setLauncherKeepClearAreaHeight(int visibleInt, int height)471     private void setLauncherKeepClearAreaHeight(int visibleInt, int height) {
472         boolean visible = visibleInt != 0;
473         boolean changed = visible != mLastLauncherKeepClearAreaHeightVisible
474                 || height != mLastLauncherKeepClearAreaHeight;
475         IPip pip = mPip;
476         if (pip != null && changed) {
477             mLastLauncherKeepClearAreaHeightVisible = visible;
478             mLastLauncherKeepClearAreaHeight = height;
479             try {
480                 pip.setLauncherKeepClearAreaHeight(visible, height);
481             } catch (RemoteException e) {
482                 Log.w(TAG, "Failed call setLauncherKeepClearAreaHeight visible: " + visible
483                         + " height: " + height, e);
484             }
485         }
486     }
487 
488     /**
489      * Sets listener to get pip animation callbacks.
490      */
setPipAnimationListener(IPipAnimationListener listener)491     public void setPipAnimationListener(IPipAnimationListener listener) {
492         if (mPip != null) {
493             try {
494                 mPip.setPipAnimationListener(listener);
495             } catch (RemoteException e) {
496                 Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
497             }
498         }
499         mPipAnimationListener = listener;
500     }
501 
502     /**
503      * @return Destination bounds of auto-pip animation, {@code null} if the animation is not ready.
504      */
505     @Nullable
startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, PictureInPictureParams pictureInPictureParams, int launcherRotation, Rect hotseatKeepClearArea)506     public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
507             PictureInPictureParams pictureInPictureParams, int launcherRotation,
508             Rect hotseatKeepClearArea) {
509         if (mPip != null) {
510             try {
511                 return mPip.startSwipePipToHome(componentName, activityInfo,
512                         pictureInPictureParams, launcherRotation, hotseatKeepClearArea);
513             } catch (RemoteException e) {
514                 Log.w(TAG, "Failed call startSwipePipToHome", e);
515             }
516         }
517         return null;
518     }
519 
520     /**
521      * Notifies WM Shell that launcher has finished all the animation for swipe to home. WM Shell
522      * can choose to fade out the overlay when entering PIP is finished, and WM Shell should be
523      * responsible for cleaning up the overlay.
524      */
stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds, SurfaceControl overlay)525     public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
526             SurfaceControl overlay) {
527         if (mPip != null) {
528             try {
529                 mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
530             } catch (RemoteException e) {
531                 Log.w(TAG, "Failed call stopSwipePipToHome");
532             }
533         }
534     }
535 
536     /**
537      * Sets the next pip animation type to be the alpha animation.
538      */
setPipAnimationTypeToAlpha()539     public void setPipAnimationTypeToAlpha() {
540         if (mPip != null) {
541             try {
542                 mPip.setPipAnimationTypeToAlpha();
543             } catch (RemoteException e) {
544                 Log.w(TAG, "Failed call setPipAnimationTypeToAlpha", e);
545             }
546         }
547     }
548 
549     /**
550      * Sets the app icon size in pixel used by Launcher all apps.
551      */
setLauncherAppIconSize(int iconSizePx)552     public void setLauncherAppIconSize(int iconSizePx) {
553         if (mPip != null) {
554             try {
555                 mPip.setLauncherAppIconSize(iconSizePx);
556             } catch (RemoteException e) {
557                 Log.w(TAG, "Failed call setLauncherAppIconSize", e);
558             }
559         }
560     }
561 
562     //
563     // Splitscreen
564     //
565 
registerSplitScreenListener(ISplitScreenListener listener)566     public void registerSplitScreenListener(ISplitScreenListener listener) {
567         if (mSplitScreen != null) {
568             try {
569                 mSplitScreen.registerSplitScreenListener(listener);
570             } catch (RemoteException e) {
571                 Log.w(TAG, "Failed call registerSplitScreenListener");
572             }
573         }
574         mSplitScreenListener = listener;
575     }
576 
unregisterSplitScreenListener(ISplitScreenListener listener)577     public void unregisterSplitScreenListener(ISplitScreenListener listener) {
578         if (mSplitScreen != null) {
579             try {
580                 mSplitScreen.unregisterSplitScreenListener(listener);
581             } catch (RemoteException e) {
582                 Log.w(TAG, "Failed call unregisterSplitScreenListener");
583             }
584         }
585         mSplitScreenListener = null;
586     }
587 
588     /** Start multiple tasks in split-screen simultaneously. */
startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId)589     public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2,
590             @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
591             RemoteTransition remoteTransition, InstanceId instanceId) {
592         if (mSystemUiProxy != null) {
593             try {
594                 mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition,
595                         splitRatio, remoteTransition, instanceId);
596             } catch (RemoteException e) {
597                 Log.w(TAG, "Failed call startTasks");
598             }
599         }
600     }
601 
startIntentAndTask(PendingIntent pendingIntent, Bundle options1, int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId)602     public void startIntentAndTask(PendingIntent pendingIntent, Bundle options1, int taskId,
603             Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
604             float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
605         if (mSystemUiProxy != null) {
606             try {
607                 mSplitScreen.startIntentAndTask(pendingIntent, options1, taskId, options2,
608                         splitPosition, splitRatio, remoteTransition, instanceId);
609             } catch (RemoteException e) {
610                 Log.w(TAG, "Failed call startIntentAndTask");
611             }
612         }
613     }
614 
startIntents(PendingIntent pendingIntent1, Bundle options1, PendingIntent pendingIntent2, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId)615     public void startIntents(PendingIntent pendingIntent1, Bundle options1,
616             PendingIntent pendingIntent2, Bundle options2,
617             @SplitConfigurationOptions.StagePosition int splitPosition,
618             float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
619         if (mSystemUiProxy != null) {
620             try {
621                 mSplitScreen.startIntents(pendingIntent1, options1, pendingIntent2, options2,
622                         splitPosition, splitRatio, remoteTransition, instanceId);
623             } catch (RemoteException e) {
624                 Log.w(TAG, "Failed call startIntents");
625             }
626         }
627     }
628 
startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId)629     public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId,
630             Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
631             float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
632         if (mSystemUiProxy != null) {
633             try {
634                 mSplitScreen.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
635                         splitPosition, splitRatio, remoteTransition, instanceId);
636             } catch (RemoteException e) {
637                 Log.w(TAG, "Failed call startShortcutAndTask");
638             }
639         }
640     }
641 
642     /**
643      * Start multiple tasks in split-screen simultaneously.
644      */
startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId)645     public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
646             Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
647             float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
648         if (mSystemUiProxy != null) {
649             try {
650                 mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
651                         splitPosition, splitRatio, adapter, instanceId);
652             } catch (RemoteException e) {
653                 Log.w(TAG, "Failed call startTasksWithLegacyTransition");
654             }
655         }
656     }
657 
startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Bundle options1, int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId)658     public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
659             Bundle options1, int taskId, Bundle options2,
660             @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
661             RemoteAnimationAdapter adapter, InstanceId instanceId) {
662         if (mSystemUiProxy != null) {
663             try {
664                 mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, options1, taskId,
665                         options2, splitPosition, splitRatio, adapter, instanceId);
666             } catch (RemoteException e) {
667                 Log.w(TAG, "Failed call startIntentAndTaskWithLegacyTransition");
668             }
669         }
670     }
671 
startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1, int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId)672     public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1,
673             int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
674             float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
675         if (mSystemUiProxy != null) {
676             try {
677                 mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
678                         taskId, options2, splitPosition, splitRatio, adapter, instanceId);
679             } catch (RemoteException e) {
680                 Log.w(TAG, "Failed call startShortcutAndTaskWithLegacyTransition");
681             }
682         }
683     }
684 
685     /**
686      * Starts a pair of intents or shortcuts in split-screen using legacy transition. Passing a
687      * non-null shortcut info means to start the app as a shortcut.
688      */
startIntentsWithLegacyTransition(PendingIntent pendingIntent1, @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1, PendingIntent pendingIntent2, @Nullable ShortcutInfo shortcutInfo2, @Nullable Bundle options2, @SplitConfigurationOptions.StagePosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId)689     public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1,
690             @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
691             PendingIntent pendingIntent2, @Nullable ShortcutInfo shortcutInfo2,
692             @Nullable Bundle options2, @SplitConfigurationOptions.StagePosition int sidePosition,
693             float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
694         if (mSystemUiProxy != null) {
695             try {
696                 mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, shortcutInfo1,
697                         options1, pendingIntent2, shortcutInfo2, options2, sidePosition, splitRatio,
698                         adapter, instanceId);
699             } catch (RemoteException e) {
700                 Log.w(TAG, "Failed call startIntentsWithLegacyTransition");
701             }
702         }
703     }
704 
startShortcut(String packageName, String shortcutId, int position, Bundle options, UserHandle user, InstanceId instanceId)705     public void startShortcut(String packageName, String shortcutId, int position,
706             Bundle options, UserHandle user, InstanceId instanceId) {
707         if (mSplitScreen != null) {
708             try {
709                 mSplitScreen.startShortcut(packageName, shortcutId, position, options,
710                         user, instanceId);
711             } catch (RemoteException e) {
712                 Log.w(TAG, "Failed call startShortcut");
713             }
714         }
715     }
716 
startIntent(PendingIntent intent, Intent fillInIntent, int position, Bundle options, InstanceId instanceId)717     public void startIntent(PendingIntent intent, Intent fillInIntent, int position,
718             Bundle options, InstanceId instanceId) {
719         if (mSplitScreen != null) {
720             try {
721                 mSplitScreen.startIntent(intent, fillInIntent, position, options, instanceId);
722             } catch (RemoteException e) {
723                 Log.w(TAG, "Failed call startIntent");
724             }
725         }
726     }
727 
removeFromSideStage(int taskId)728     public void removeFromSideStage(int taskId) {
729         if (mSplitScreen != null) {
730             try {
731                 mSplitScreen.removeFromSideStage(taskId);
732             } catch (RemoteException e) {
733                 Log.w(TAG, "Failed call removeFromSideStage");
734             }
735         }
736     }
737 
738     /**
739      * Call this when going to recents so that shell can set-up and provide appropriate leashes
740      * for animation (eg. DividerBar).
741      *
742      * @return RemoteAnimationTargets of windows that need to animate but only exist in shell.
743      */
744     @Nullable
onGoingToRecentsLegacy(RemoteAnimationTarget[] apps)745     public RemoteAnimationTarget[] onGoingToRecentsLegacy(RemoteAnimationTarget[] apps) {
746         if (mSplitScreen != null) {
747             try {
748                 return mSplitScreen.onGoingToRecentsLegacy(apps);
749             } catch (RemoteException e) {
750                 Log.w(TAG, "Failed call onGoingToRecentsLegacy");
751             }
752         }
753         return null;
754     }
755 
756     @Nullable
onStartingSplitLegacy(RemoteAnimationTarget[] apps)757     public RemoteAnimationTarget[] onStartingSplitLegacy(RemoteAnimationTarget[] apps) {
758         if (mSplitScreen != null) {
759             try {
760                 return mSplitScreen.onStartingSplitLegacy(apps);
761             } catch (RemoteException e) {
762                 Log.w(TAG, "Failed call onStartingSplitLegacy");
763             }
764         }
765         return null;
766     }
767 
768     //
769     // One handed
770     //
771 
startOneHandedMode()772     public void startOneHandedMode() {
773         if (mOneHanded != null) {
774             try {
775                 mOneHanded.startOneHanded();
776             } catch (RemoteException e) {
777                 Log.w(TAG, "Failed call startOneHandedMode", e);
778             }
779         }
780     }
781 
stopOneHandedMode()782     public void stopOneHandedMode() {
783         if (mOneHanded != null) {
784             try {
785                 mOneHanded.stopOneHanded();
786             } catch (RemoteException e) {
787                 Log.w(TAG, "Failed call stopOneHandedMode", e);
788             }
789         }
790     }
791 
792     //
793     // Remote transitions
794     //
795 
registerRemoteTransition( RemoteTransition remoteTransition, TransitionFilter filter)796     public void registerRemoteTransition(
797             RemoteTransition remoteTransition, TransitionFilter filter) {
798         if (mShellTransitions != null) {
799             try {
800                 mShellTransitions.registerRemote(filter, remoteTransition);
801             } catch (RemoteException e) {
802                 Log.w(TAG, "Failed call registerRemoteTransition");
803             }
804         }
805         if (!mRemoteTransitions.containsKey(remoteTransition)) {
806             mRemoteTransitions.put(remoteTransition, filter);
807         }
808     }
809 
unregisterRemoteTransition(RemoteTransition remoteTransition)810     public void unregisterRemoteTransition(RemoteTransition remoteTransition) {
811         if (mShellTransitions != null) {
812             try {
813                 mShellTransitions.unregisterRemote(remoteTransition);
814             } catch (RemoteException e) {
815                 Log.w(TAG, "Failed call registerRemoteTransition");
816             }
817         }
818         mRemoteTransitions.remove(remoteTransition);
819     }
820 
821     //
822     // Starting window
823     //
824 
825     /**
826      * Sets listener to get callbacks when launching a task.
827      */
setStartingWindowListener(IStartingWindowListener listener)828     public void setStartingWindowListener(IStartingWindowListener listener) {
829         if (mStartingWindow != null) {
830             try {
831                 mStartingWindow.setStartingWindowListener(listener);
832             } catch (RemoteException e) {
833                 Log.w(TAG, "Failed call setStartingWindowListener", e);
834             }
835         }
836         mStartingWindowListener = listener;
837     }
838 
839     //
840     // SmartSpace transitions
841     //
842 
843     /**
844      * Sets the instance of {@link ILauncherUnlockAnimationController} that System UI should use to
845      * control the launcher side of the unlock animation. This will also cause us to dispatch the
846      * current state of the smartspace to System UI (this will subsequently happen if the state
847      * changes).
848      */
setLauncherUnlockAnimationController( ILauncherUnlockAnimationController controller)849     public void setLauncherUnlockAnimationController(
850             ILauncherUnlockAnimationController controller) {
851         if (mSysuiUnlockAnimationController != null) {
852             try {
853                 mSysuiUnlockAnimationController.setLauncherUnlockController(controller);
854 
855                 if (controller != null) {
856                     controller.dispatchSmartspaceStateToSysui();
857                 }
858             } catch (RemoteException e) {
859                 Log.w(TAG, "Failed call setLauncherUnlockAnimationController", e);
860             }
861         }
862 
863         mLauncherUnlockAnimationController = controller;
864     }
865 
866     /**
867      * Tells System UI that the Launcher's smartspace state has been updated, so that it can prepare
868      * the unlock animation accordingly.
869      */
notifySysuiSmartspaceStateUpdated(SmartspaceState state)870     public void notifySysuiSmartspaceStateUpdated(SmartspaceState state) {
871         if (mSysuiUnlockAnimationController != null) {
872             try {
873                 mSysuiUnlockAnimationController.onLauncherSmartspaceStateUpdated(state);
874             } catch (RemoteException e) {
875                 Log.w(TAG, "Failed call notifySysuiSmartspaceStateUpdated", e);
876                 e.printStackTrace();
877             }
878         }
879     }
880 
881     //
882     // Recents
883     //
884 
registerRecentTasksListener(IRecentTasksListener listener)885     public void registerRecentTasksListener(IRecentTasksListener listener) {
886         if (mRecentTasks != null) {
887             try {
888                 mRecentTasks.registerRecentTasksListener(listener);
889             } catch (RemoteException e) {
890                 Log.w(TAG, "Failed call registerRecentTasksListener", e);
891             }
892         }
893         mRecentTasksListener = listener;
894     }
895 
unregisterRecentTasksListener(IRecentTasksListener listener)896     public void unregisterRecentTasksListener(IRecentTasksListener listener) {
897         if (mRecentTasks != null) {
898             try {
899                 mRecentTasks.unregisterRecentTasksListener(listener);
900             } catch (RemoteException e) {
901                 Log.w(TAG, "Failed call unregisterRecentTasksListener");
902             }
903         }
904         mRecentTasksListener = null;
905     }
906 
907     //
908     // Back navigation transitions
909     //
910 
911     /** Sets the launcher {@link android.window.IOnBackInvokedCallback} to shell */
setBackToLauncherCallback(IOnBackInvokedCallback callback)912     public void setBackToLauncherCallback(IOnBackInvokedCallback callback) {
913         mBackToLauncherCallback = callback;
914         if (mBackAnimation == null) {
915             return;
916         }
917         try {
918             mBackAnimation.setBackToLauncherCallback(callback);
919         } catch (RemoteException e) {
920             Log.e(TAG, "Failed call setBackToLauncherCallback", e);
921         }
922     }
923 
924     /** Clears the previously registered {@link IOnBackInvokedCallback}.
925      *
926      * @param callback The previously registered callback instance.
927      */
clearBackToLauncherCallback(IOnBackInvokedCallback callback)928     public void clearBackToLauncherCallback(IOnBackInvokedCallback callback) {
929         if (mBackToLauncherCallback != callback) {
930             return;
931         }
932         mBackToLauncherCallback = null;
933         if (mBackAnimation == null) {
934             return;
935         }
936         try {
937             mBackAnimation.clearBackToLauncherCallback();
938         } catch (RemoteException e) {
939             Log.e(TAG, "Failed call clearBackToLauncherCallback", e);
940         }
941     }
942 
943     /**
944      * Notifies shell that all back to launcher animations have finished (including the transition
945      * that plays after the gesture is committed and before the app is closed.
946      */
onBackToLauncherAnimationFinished()947     public void onBackToLauncherAnimationFinished() {
948         if (mBackAnimation != null) {
949             try {
950                 mBackAnimation.onBackToLauncherAnimationFinished();
951             } catch (RemoteException e) {
952                 Log.w(TAG, "Failed call onBackAnimationFinished", e);
953             }
954         }
955     }
956 
getRecentTasks(int numTasks, int userId)957     public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
958         if (mRecentTasks != null) {
959             try {
960                 final GroupedRecentTaskInfo[] rawTasks = mRecentTasks.getRecentTasks(numTasks,
961                         RECENT_IGNORE_UNAVAILABLE, userId);
962                 if (rawTasks == null) {
963                     return new ArrayList<>();
964                 }
965                 return new ArrayList<>(Arrays.asList(rawTasks));
966             } catch (RemoteException e) {
967                 Log.w(TAG, "Failed call getRecentTasks", e);
968             }
969         }
970         return new ArrayList<>();
971     }
972 
973     /**
974      * Gets the set of running tasks.
975      */
getRunningTasks(int numTasks)976     public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
977         if (mRecentTasks != null
978                 && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
979             try {
980                 return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
981             } catch (RemoteException e) {
982                 Log.w(TAG, "Failed call getRunningTasks", e);
983             }
984         }
985         return new ArrayList<>();
986     }
987 
handleMessageAsync(Message msg)988     private boolean handleMessageAsync(Message msg) {
989         switch (msg.what) {
990             case MSG_SET_SHELF_HEIGHT:
991                 setShelfHeightAsync(msg.arg1, msg.arg2);
992                 return true;
993             case MSG_SET_LAUNCHER_KEEP_CLEAR_AREA_HEIGHT:
994                 setLauncherKeepClearAreaHeight(msg.arg1, msg.arg2);
995                 return true;
996         }
997 
998         return false;
999     }
1000 
1001     //
1002     // Desktop Mode
1003     //
1004 
1005     /** Call shell to show all apps active on the desktop */
showDesktopApps()1006     public void showDesktopApps() {
1007         if (mDesktopMode != null) {
1008             try {
1009                 mDesktopMode.showDesktopApps();
1010             } catch (RemoteException e) {
1011                 Log.w(TAG, "Failed call showDesktopApps", e);
1012             }
1013         }
1014     }
1015 
1016     /** Call shell to get number of visible freeform tasks */
getVisibleDesktopTaskCount()1017     public int getVisibleDesktopTaskCount() {
1018         if (mDesktopMode != null) {
1019             try {
1020                 return mDesktopMode.getVisibleTaskCount();
1021             } catch (RemoteException e) {
1022                 Log.w(TAG, "Failed call getVisibleDesktopTaskCount", e);
1023             }
1024         }
1025         return 0;
1026     }
1027 
1028     //
1029     // Unfold transition
1030     //
1031 
1032     /** Sets the unfold animation lister to sysui. */
setUnfoldAnimationListener(IUnfoldTransitionListener callback)1033     public void setUnfoldAnimationListener(IUnfoldTransitionListener callback) {
1034         mUnfoldAnimationListener = callback;
1035         if (mUnfoldAnimation == null) {
1036             return;
1037         }
1038         try {
1039             Log.d(TAG, "Registering unfold animation receiver");
1040             mUnfoldAnimation.setListener(callback);
1041         } catch (RemoteException e) {
1042             Log.e(TAG, "Failed call setUnfoldAnimationListener", e);
1043         }
1044     }
1045 }
1046