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