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