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