1 /* 2 * Copyright (C) 2021 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 17 package com.android.wm.shell.back; 18 19 import static android.view.RemoteAnimationTarget.MODE_CLOSING; 20 import static android.view.RemoteAnimationTarget.MODE_OPENING; 21 22 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; 23 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; 24 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION; 25 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.app.ActivityTaskManager; 29 import android.app.IActivityTaskManager; 30 import android.app.WindowConfiguration; 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.database.ContentObserver; 34 import android.hardware.HardwareBuffer; 35 import android.hardware.input.InputManager; 36 import android.net.Uri; 37 import android.os.Handler; 38 import android.os.IBinder; 39 import android.os.RemoteException; 40 import android.os.SystemClock; 41 import android.os.SystemProperties; 42 import android.os.UserHandle; 43 import android.provider.Settings.Global; 44 import android.util.Log; 45 import android.view.IWindowFocusObserver; 46 import android.view.InputDevice; 47 import android.view.KeyCharacterMap; 48 import android.view.KeyEvent; 49 import android.view.MotionEvent; 50 import android.view.RemoteAnimationTarget; 51 import android.view.SurfaceControl; 52 import android.window.BackAnimationAdaptor; 53 import android.window.BackEvent; 54 import android.window.BackMotionEvent; 55 import android.window.BackNavigationInfo; 56 import android.window.IBackAnimationRunner; 57 import android.window.IBackNaviAnimationController; 58 import android.window.IOnBackInvokedCallback; 59 60 import com.android.internal.annotations.VisibleForTesting; 61 import com.android.internal.protolog.common.ProtoLog; 62 import com.android.wm.shell.common.ExternalInterfaceBinder; 63 import com.android.wm.shell.common.RemoteCallable; 64 import com.android.wm.shell.common.ShellExecutor; 65 import com.android.wm.shell.common.annotations.ShellBackgroundThread; 66 import com.android.wm.shell.common.annotations.ShellMainThread; 67 import com.android.wm.shell.sysui.ShellController; 68 import com.android.wm.shell.sysui.ShellInit; 69 70 import java.util.concurrent.atomic.AtomicBoolean; 71 72 /** 73 * Controls the window animation run when a user initiates a back gesture. 74 */ 75 public class BackAnimationController implements RemoteCallable<BackAnimationController> { 76 private static final String TAG = "BackAnimationController"; 77 private static final int SETTING_VALUE_OFF = 0; 78 private static final int SETTING_VALUE_ON = 1; 79 public static final boolean IS_ENABLED = 80 SystemProperties.getInt("persist.wm.debug.predictive_back", 81 SETTING_VALUE_ON) == SETTING_VALUE_ON; 82 /** Flag for U animation features */ 83 public static boolean IS_U_ANIMATION_ENABLED = 84 SystemProperties.getInt("persist.wm.debug.predictive_back_anim", 85 SETTING_VALUE_ON) == SETTING_VALUE_ON; 86 /** Predictive back animation developer option */ 87 private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false); 88 // TODO (b/241808055) Find a appropriate time to remove during refactor 89 private static final boolean USE_TRANSITION = 90 SystemProperties.getInt("persist.wm.debug.predictive_back_ani_trans", 1) != 0; 91 /** 92 * Max duration to wait for a transition to finish before accepting another gesture start 93 * request. 94 */ 95 private static final long MAX_TRANSITION_DURATION = 2000; 96 97 /** True when a back gesture is ongoing */ 98 private boolean mBackGestureStarted = false; 99 100 /** Tracks if an uninterruptible transition is in progress */ 101 private boolean mTransitionInProgress = false; 102 /** Tracks if we should start the back gesture on the next motion move event */ 103 private boolean mShouldStartOnNextMoveEvent = false; 104 /** @see #setTriggerBack(boolean) */ 105 private boolean mTriggerBack; 106 107 @Nullable 108 private BackNavigationInfo mBackNavigationInfo; 109 private final SurfaceControl.Transaction mTransaction; 110 private final IActivityTaskManager mActivityTaskManager; 111 private final Context mContext; 112 private final ContentResolver mContentResolver; 113 private final ShellController mShellController; 114 private final ShellExecutor mShellExecutor; 115 private final Handler mBgHandler; 116 @Nullable 117 private IOnBackInvokedCallback mBackToLauncherCallback; 118 private float mTriggerThreshold; 119 private final Runnable mResetTransitionRunnable = () -> { 120 finishAnimation(); 121 mTransitionInProgress = false; 122 }; 123 124 private RemoteAnimationTarget mAnimationTarget; 125 IBackAnimationRunner mIBackAnimationRunner; 126 private IBackNaviAnimationController mBackAnimationController; 127 private BackAnimationAdaptor mBackAnimationAdaptor; 128 129 private final TouchTracker mTouchTracker = new TouchTracker(); 130 private final CachingBackDispatcher mCachingBackDispatcher = new CachingBackDispatcher(); 131 132 @VisibleForTesting 133 final IWindowFocusObserver mFocusObserver = new IWindowFocusObserver.Stub() { 134 @Override 135 public void focusGained(IBinder inputToken) { } 136 @Override 137 public void focusLost(IBinder inputToken) { 138 mShellExecutor.execute(() -> { 139 if (!mBackGestureStarted || mTransitionInProgress) { 140 // If an uninterruptible transition is already in progress, we should ignore 141 // this due to the transition may cause focus lost. (alpha = 0) 142 return; 143 } 144 setTriggerBack(false); 145 onGestureFinished(false); 146 }); 147 } 148 }; 149 150 /** 151 * Cache the temporary callback and trigger result if gesture was finish before received 152 * BackAnimationRunner#onAnimationStart/cancel, so there can continue play the animation. 153 */ 154 private class CachingBackDispatcher { 155 private IOnBackInvokedCallback mOnBackCallback; 156 private boolean mTriggerBack; 157 // Whether we are waiting to receive onAnimationStart 158 private boolean mWaitingAnimation; 159 startWaitingAnimation()160 void startWaitingAnimation() { 161 mWaitingAnimation = true; 162 } 163 set(IOnBackInvokedCallback callback, boolean triggerBack)164 boolean set(IOnBackInvokedCallback callback, boolean triggerBack) { 165 if (mWaitingAnimation) { 166 mOnBackCallback = callback; 167 mTriggerBack = triggerBack; 168 return true; 169 } 170 return false; 171 } 172 consume()173 boolean consume() { 174 boolean consumed = false; 175 if (mWaitingAnimation && mOnBackCallback != null) { 176 if (mTriggerBack) { 177 final BackMotionEvent backFinish = mTouchTracker.createProgressEvent(1); 178 dispatchOnBackProgressed(mBackToLauncherCallback, backFinish); 179 dispatchOnBackInvoked(mOnBackCallback); 180 } else { 181 final BackMotionEvent backFinish = mTouchTracker.createProgressEvent(0); 182 dispatchOnBackProgressed(mBackToLauncherCallback, backFinish); 183 dispatchOnBackCancelled(mOnBackCallback); 184 } 185 startTransition(); 186 consumed = true; 187 } 188 mOnBackCallback = null; 189 mWaitingAnimation = false; 190 return consumed; 191 } 192 } 193 BackAnimationController( @onNull ShellInit shellInit, @NonNull ShellController shellController, @NonNull @ShellMainThread ShellExecutor shellExecutor, @NonNull @ShellBackgroundThread Handler backgroundHandler, Context context)194 public BackAnimationController( 195 @NonNull ShellInit shellInit, 196 @NonNull ShellController shellController, 197 @NonNull @ShellMainThread ShellExecutor shellExecutor, 198 @NonNull @ShellBackgroundThread Handler backgroundHandler, 199 Context context) { 200 this(shellInit, shellController, shellExecutor, backgroundHandler, 201 new SurfaceControl.Transaction(), ActivityTaskManager.getService(), 202 context, context.getContentResolver()); 203 } 204 205 @VisibleForTesting BackAnimationController( @onNull ShellInit shellInit, @NonNull ShellController shellController, @NonNull @ShellMainThread ShellExecutor shellExecutor, @NonNull @ShellBackgroundThread Handler bgHandler, @NonNull SurfaceControl.Transaction transaction, @NonNull IActivityTaskManager activityTaskManager, Context context, ContentResolver contentResolver)206 BackAnimationController( 207 @NonNull ShellInit shellInit, 208 @NonNull ShellController shellController, 209 @NonNull @ShellMainThread ShellExecutor shellExecutor, 210 @NonNull @ShellBackgroundThread Handler bgHandler, 211 @NonNull SurfaceControl.Transaction transaction, 212 @NonNull IActivityTaskManager activityTaskManager, 213 Context context, ContentResolver contentResolver) { 214 mShellController = shellController; 215 mShellExecutor = shellExecutor; 216 mTransaction = transaction; 217 mActivityTaskManager = activityTaskManager; 218 mContext = context; 219 mContentResolver = contentResolver; 220 mBgHandler = bgHandler; 221 shellInit.addInitCallback(this::onInit, this); 222 } 223 224 @VisibleForTesting setEnableUAnimation(boolean enable)225 void setEnableUAnimation(boolean enable) { 226 IS_U_ANIMATION_ENABLED = enable; 227 } 228 onInit()229 private void onInit() { 230 setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler); 231 mShellController.addExternalInterface(KEY_EXTRA_SHELL_BACK_ANIMATION, 232 this::createExternalInterface, this); 233 } 234 setupAnimationDeveloperSettingsObserver( @onNull ContentResolver contentResolver, @NonNull @ShellBackgroundThread final Handler backgroundHandler)235 private void setupAnimationDeveloperSettingsObserver( 236 @NonNull ContentResolver contentResolver, 237 @NonNull @ShellBackgroundThread final Handler backgroundHandler) { 238 ContentObserver settingsObserver = new ContentObserver(backgroundHandler) { 239 @Override 240 public void onChange(boolean selfChange, Uri uri) { 241 updateEnableAnimationFromSetting(); 242 } 243 }; 244 contentResolver.registerContentObserver( 245 Global.getUriFor(Global.ENABLE_BACK_ANIMATION), 246 false, settingsObserver, UserHandle.USER_SYSTEM 247 ); 248 updateEnableAnimationFromSetting(); 249 } 250 251 @ShellBackgroundThread updateEnableAnimationFromSetting()252 private void updateEnableAnimationFromSetting() { 253 int settingValue = Global.getInt(mContext.getContentResolver(), 254 Global.ENABLE_BACK_ANIMATION, SETTING_VALUE_OFF); 255 boolean isEnabled = settingValue == SETTING_VALUE_ON; 256 mEnableAnimations.set(isEnabled); 257 ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Back animation enabled=%s", 258 isEnabled); 259 } 260 getBackAnimationImpl()261 public BackAnimation getBackAnimationImpl() { 262 return mBackAnimation; 263 } 264 createExternalInterface()265 private ExternalInterfaceBinder createExternalInterface() { 266 return new IBackAnimationImpl(this); 267 } 268 269 private final BackAnimationImpl mBackAnimation = new BackAnimationImpl(); 270 271 @Override getContext()272 public Context getContext() { 273 return mContext; 274 } 275 276 @Override getRemoteCallExecutor()277 public ShellExecutor getRemoteCallExecutor() { 278 return mShellExecutor; 279 } 280 281 private class BackAnimationImpl implements BackAnimation { 282 @Override onBackMotion( float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge)283 public void onBackMotion( 284 float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge) { 285 mShellExecutor.execute(() -> onMotionEvent(touchX, touchY, keyAction, swipeEdge)); 286 } 287 288 @Override setTriggerBack(boolean triggerBack)289 public void setTriggerBack(boolean triggerBack) { 290 mShellExecutor.execute(() -> BackAnimationController.this.setTriggerBack(triggerBack)); 291 } 292 293 @Override setSwipeThresholds(float triggerThreshold, float progressThreshold)294 public void setSwipeThresholds(float triggerThreshold, float progressThreshold) { 295 mShellExecutor.execute(() -> BackAnimationController.this.setSwipeThresholds( 296 triggerThreshold, progressThreshold)); 297 } 298 } 299 300 private static class IBackAnimationImpl extends IBackAnimation.Stub 301 implements ExternalInterfaceBinder { 302 private BackAnimationController mController; 303 IBackAnimationImpl(BackAnimationController controller)304 IBackAnimationImpl(BackAnimationController controller) { 305 mController = controller; 306 } 307 308 @Override setBackToLauncherCallback(IOnBackInvokedCallback callback)309 public void setBackToLauncherCallback(IOnBackInvokedCallback callback) { 310 executeRemoteCallWithTaskPermission(mController, "setBackToLauncherCallback", 311 (controller) -> controller.setBackToLauncherCallback(callback)); 312 } 313 314 @Override clearBackToLauncherCallback()315 public void clearBackToLauncherCallback() { 316 executeRemoteCallWithTaskPermission(mController, "clearBackToLauncherCallback", 317 (controller) -> controller.clearBackToLauncherCallback()); 318 } 319 320 @Override onBackToLauncherAnimationFinished()321 public void onBackToLauncherAnimationFinished() { 322 executeRemoteCallWithTaskPermission(mController, "onBackToLauncherAnimationFinished", 323 (controller) -> controller.onBackToLauncherAnimationFinished()); 324 } 325 326 @Override invalidate()327 public void invalidate() { 328 mController = null; 329 } 330 } 331 332 @VisibleForTesting setBackToLauncherCallback(IOnBackInvokedCallback callback)333 void setBackToLauncherCallback(IOnBackInvokedCallback callback) { 334 mBackToLauncherCallback = callback; 335 if (USE_TRANSITION) { 336 createAdaptor(); 337 } 338 } 339 clearBackToLauncherCallback()340 private void clearBackToLauncherCallback() { 341 mBackToLauncherCallback = null; 342 } 343 344 @VisibleForTesting onBackToLauncherAnimationFinished()345 void onBackToLauncherAnimationFinished() { 346 final boolean triggerBack = mTriggerBack; 347 IOnBackInvokedCallback callback = mBackNavigationInfo != null 348 ? mBackNavigationInfo.getOnBackInvokedCallback() : null; 349 // Make sure the notification sequence should be controller > client. 350 finishAnimation(); 351 if (callback != null) { 352 if (triggerBack) { 353 dispatchOnBackInvoked(callback); 354 } else { 355 dispatchOnBackCancelled(callback); 356 } 357 } 358 } 359 360 /** 361 * Called when a new motion event needs to be transferred to this 362 * {@link BackAnimationController} 363 */ onMotionEvent(float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge)364 public void onMotionEvent(float touchX, float touchY, int keyAction, 365 @BackEvent.SwipeEdge int swipeEdge) { 366 if (mTransitionInProgress) { 367 return; 368 } 369 370 mTouchTracker.update(touchX, touchY); 371 if (keyAction == MotionEvent.ACTION_DOWN) { 372 if (!mBackGestureStarted) { 373 mShouldStartOnNextMoveEvent = true; 374 } 375 } else if (keyAction == MotionEvent.ACTION_MOVE) { 376 if (!mBackGestureStarted && mShouldStartOnNextMoveEvent) { 377 // Let the animation initialized here to make sure the onPointerDownOutsideFocus 378 // could be happened when ACTION_DOWN, it may change the current focus that we 379 // would access it when startBackNavigation. 380 onGestureStarted(touchX, touchY, swipeEdge); 381 mShouldStartOnNextMoveEvent = false; 382 } 383 onMove(touchX, touchY, swipeEdge); 384 } else if (keyAction == MotionEvent.ACTION_UP || keyAction == MotionEvent.ACTION_CANCEL) { 385 ProtoLog.d(WM_SHELL_BACK_PREVIEW, 386 "Finishing gesture with event action: %d", keyAction); 387 if (keyAction == MotionEvent.ACTION_CANCEL) { 388 mTriggerBack = false; 389 } 390 onGestureFinished(true); 391 } 392 } 393 onGestureStarted(float touchX, float touchY, @BackEvent.SwipeEdge int swipeEdge)394 private void onGestureStarted(float touchX, float touchY, @BackEvent.SwipeEdge int swipeEdge) { 395 ProtoLog.d(WM_SHELL_BACK_PREVIEW, "initAnimation mMotionStarted=%b", mBackGestureStarted); 396 if (mBackGestureStarted || mBackNavigationInfo != null) { 397 Log.e(TAG, "Animation is being initialized but is already started."); 398 finishAnimation(); 399 } 400 401 mTouchTracker.setGestureStartLocation(touchX, touchY, swipeEdge); 402 mBackGestureStarted = true; 403 404 try { 405 boolean requestAnimation = mEnableAnimations.get(); 406 mBackNavigationInfo = mActivityTaskManager.startBackNavigation(requestAnimation, 407 mFocusObserver, mBackAnimationAdaptor); 408 onBackNavigationInfoReceived(mBackNavigationInfo); 409 } catch (RemoteException remoteException) { 410 Log.e(TAG, "Failed to initAnimation", remoteException); 411 finishAnimation(); 412 } 413 } 414 onBackNavigationInfoReceived(@ullable BackNavigationInfo backNavigationInfo)415 private void onBackNavigationInfoReceived(@Nullable BackNavigationInfo backNavigationInfo) { 416 ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo); 417 if (backNavigationInfo == null) { 418 Log.e(TAG, "Received BackNavigationInfo is null."); 419 return; 420 } 421 int backType = backNavigationInfo.getType(); 422 IOnBackInvokedCallback targetCallback = null; 423 final boolean dispatchToLauncher = shouldDispatchToLauncher(backType); 424 if (backType == BackNavigationInfo.TYPE_CROSS_ACTIVITY) { 425 HardwareBuffer hardwareBuffer = backNavigationInfo.getScreenshotHardwareBuffer(); 426 if (hardwareBuffer != null) { 427 displayTargetScreenshot(hardwareBuffer, 428 backNavigationInfo.getTaskWindowConfiguration()); 429 } 430 targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); 431 mTransaction.apply(); 432 } else if (dispatchToLauncher) { 433 targetCallback = mBackToLauncherCallback; 434 if (USE_TRANSITION) { 435 mCachingBackDispatcher.startWaitingAnimation(); 436 } 437 } else if (backType == BackNavigationInfo.TYPE_CALLBACK) { 438 targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); 439 } 440 if (!USE_TRANSITION || !dispatchToLauncher) { 441 dispatchOnBackStarted( 442 targetCallback, 443 mTouchTracker.createStartEvent( 444 mBackNavigationInfo.getDepartingAnimationTarget())); 445 } 446 } 447 448 /** 449 * Display the screenshot of the activity beneath. 450 * 451 * @param hardwareBuffer The buffer containing the screenshot. 452 */ displayTargetScreenshot(@onNull HardwareBuffer hardwareBuffer, WindowConfiguration taskWindowConfiguration)453 private void displayTargetScreenshot(@NonNull HardwareBuffer hardwareBuffer, 454 WindowConfiguration taskWindowConfiguration) { 455 SurfaceControl screenshotSurface = 456 mBackNavigationInfo == null ? null : mBackNavigationInfo.getScreenshotSurface(); 457 if (screenshotSurface == null) { 458 Log.e(TAG, "BackNavigationInfo doesn't contain a surface for the screenshot. "); 459 return; 460 } 461 462 // Scale the buffer to fill the whole Task 463 float sx = 1; 464 float sy = 1; 465 float w = taskWindowConfiguration.getBounds().width(); 466 float h = taskWindowConfiguration.getBounds().height(); 467 468 if (w != hardwareBuffer.getWidth()) { 469 sx = w / hardwareBuffer.getWidth(); 470 } 471 472 if (h != hardwareBuffer.getHeight()) { 473 sy = h / hardwareBuffer.getHeight(); 474 } 475 mTransaction.setScale(screenshotSurface, sx, sy); 476 mTransaction.setBuffer(screenshotSurface, hardwareBuffer); 477 mTransaction.setVisibility(screenshotSurface, true); 478 } 479 onMove(float touchX, float touchY, @BackEvent.SwipeEdge int swipeEdge)480 private void onMove(float touchX, float touchY, @BackEvent.SwipeEdge int swipeEdge) { 481 if (!mBackGestureStarted || mBackNavigationInfo == null) { 482 return; 483 } 484 final BackMotionEvent backEvent = mTouchTracker.createProgressEvent(); 485 if (USE_TRANSITION && mBackAnimationController != null && mAnimationTarget != null) { 486 dispatchOnBackProgressed(mBackToLauncherCallback, backEvent); 487 } else if (mEnableAnimations.get()) { 488 int backType = mBackNavigationInfo.getType(); 489 IOnBackInvokedCallback targetCallback; 490 if (shouldDispatchToLauncher(backType)) { 491 targetCallback = mBackToLauncherCallback; 492 } else { 493 targetCallback = mBackNavigationInfo.getOnBackInvokedCallback(); 494 } 495 dispatchOnBackProgressed(targetCallback, backEvent); 496 } 497 } 498 injectBackKey()499 private void injectBackKey() { 500 sendBackEvent(KeyEvent.ACTION_DOWN); 501 sendBackEvent(KeyEvent.ACTION_UP); 502 } 503 sendBackEvent(int action)504 private void sendBackEvent(int action) { 505 final long when = SystemClock.uptimeMillis(); 506 final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK, 0 /* repeat */, 507 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */, 508 KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, 509 InputDevice.SOURCE_KEYBOARD); 510 511 ev.setDisplayId(mContext.getDisplay().getDisplayId()); 512 if (!InputManager.getInstance() 513 .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) { 514 Log.e(TAG, "Inject input event fail"); 515 } 516 } 517 onGestureFinished(boolean fromTouch)518 private void onGestureFinished(boolean fromTouch) { 519 ProtoLog.d(WM_SHELL_BACK_PREVIEW, "onGestureFinished() mTriggerBack == %s", mTriggerBack); 520 if (!mBackGestureStarted) { 521 finishAnimation(); 522 return; 523 } 524 525 if (fromTouch) { 526 // Let touch reset the flag otherwise it will start a new back navigation and refresh 527 // the info when received a new move event. 528 mBackGestureStarted = false; 529 } 530 531 if (mTransitionInProgress) { 532 return; 533 } 534 535 if (mBackNavigationInfo == null) { 536 // No focus window found or core are running recents animation, inject back key as 537 // legacy behavior. 538 if (mTriggerBack) { 539 injectBackKey(); 540 } 541 finishAnimation(); 542 return; 543 } 544 545 int backType = mBackNavigationInfo.getType(); 546 boolean shouldDispatchToLauncher = shouldDispatchToLauncher(backType); 547 IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher 548 ? mBackToLauncherCallback 549 : mBackNavigationInfo.getOnBackInvokedCallback(); 550 if (mCachingBackDispatcher.set(targetCallback, mTriggerBack)) { 551 return; 552 } 553 if (shouldDispatchToLauncher) { 554 startTransition(); 555 } 556 if (mTriggerBack) { 557 dispatchOnBackInvoked(targetCallback); 558 } else { 559 dispatchOnBackCancelled(targetCallback); 560 } 561 if (backType != BackNavigationInfo.TYPE_RETURN_TO_HOME || !shouldDispatchToLauncher) { 562 // Launcher callback missing. Simply finish animation. 563 finishAnimation(); 564 } 565 } 566 shouldDispatchToLauncher(int backType)567 private boolean shouldDispatchToLauncher(int backType) { 568 return backType == BackNavigationInfo.TYPE_RETURN_TO_HOME 569 && mBackToLauncherCallback != null 570 && mEnableAnimations.get() 571 && mBackNavigationInfo != null 572 && ((USE_TRANSITION && mBackNavigationInfo.isPrepareRemoteAnimation()) 573 || mBackNavigationInfo.getDepartingAnimationTarget() != null); 574 } 575 dispatchOnBackStarted(IOnBackInvokedCallback callback, BackMotionEvent backEvent)576 private void dispatchOnBackStarted(IOnBackInvokedCallback callback, 577 BackMotionEvent backEvent) { 578 if (callback == null) { 579 return; 580 } 581 try { 582 if (shouldDispatchAnimation(callback)) { 583 callback.onBackStarted(backEvent); 584 } 585 } catch (RemoteException e) { 586 Log.e(TAG, "dispatchOnBackStarted error: ", e); 587 } 588 } 589 dispatchOnBackInvoked(IOnBackInvokedCallback callback)590 private void dispatchOnBackInvoked(IOnBackInvokedCallback callback) { 591 if (callback == null) { 592 return; 593 } 594 try { 595 callback.onBackInvoked(); 596 } catch (RemoteException e) { 597 Log.e(TAG, "dispatchOnBackInvoked error: ", e); 598 } 599 } 600 dispatchOnBackCancelled(IOnBackInvokedCallback callback)601 private void dispatchOnBackCancelled(IOnBackInvokedCallback callback) { 602 if (callback == null) { 603 return; 604 } 605 try { 606 if (shouldDispatchAnimation(callback)) { 607 callback.onBackCancelled(); 608 } 609 } catch (RemoteException e) { 610 Log.e(TAG, "dispatchOnBackCancelled error: ", e); 611 } 612 } 613 dispatchOnBackProgressed(IOnBackInvokedCallback callback, BackMotionEvent backEvent)614 private void dispatchOnBackProgressed(IOnBackInvokedCallback callback, 615 BackMotionEvent backEvent) { 616 if (callback == null) { 617 return; 618 } 619 try { 620 if (shouldDispatchAnimation(callback)) { 621 callback.onBackProgressed(backEvent); 622 } 623 } catch (RemoteException e) { 624 Log.e(TAG, "dispatchOnBackProgressed error: ", e); 625 } 626 } 627 shouldDispatchAnimation(IOnBackInvokedCallback callback)628 private boolean shouldDispatchAnimation(IOnBackInvokedCallback callback) { 629 return (IS_U_ANIMATION_ENABLED || callback == mBackToLauncherCallback) 630 && mEnableAnimations.get(); 631 } 632 633 /** 634 * Sets to true when the back gesture has passed the triggering threshold, false otherwise. 635 */ setTriggerBack(boolean triggerBack)636 public void setTriggerBack(boolean triggerBack) { 637 if (mTransitionInProgress) { 638 return; 639 } 640 mTriggerBack = triggerBack; 641 mTouchTracker.setTriggerBack(triggerBack); 642 } 643 setSwipeThresholds(float triggerThreshold, float progressThreshold)644 private void setSwipeThresholds(float triggerThreshold, float progressThreshold) { 645 mTouchTracker.setProgressThreshold(progressThreshold); 646 mTriggerThreshold = triggerThreshold; 647 } 648 finishAnimation()649 private void finishAnimation() { 650 ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: finishAnimation()"); 651 mTouchTracker.reset(); 652 BackNavigationInfo backNavigationInfo = mBackNavigationInfo; 653 boolean triggerBack = mTriggerBack; 654 mBackNavigationInfo = null; 655 mAnimationTarget = null; 656 mTriggerBack = false; 657 mShouldStartOnNextMoveEvent = false; 658 if (backNavigationInfo == null) { 659 return; 660 } 661 662 if (!USE_TRANSITION) { 663 RemoteAnimationTarget animationTarget = backNavigationInfo 664 .getDepartingAnimationTarget(); 665 if (animationTarget != null) { 666 if (animationTarget.leash != null && animationTarget.leash.isValid()) { 667 mTransaction.remove(animationTarget.leash); 668 } 669 } 670 SurfaceControl screenshotSurface = backNavigationInfo.getScreenshotSurface(); 671 if (screenshotSurface != null && screenshotSurface.isValid()) { 672 mTransaction.remove(screenshotSurface); 673 } 674 mTransaction.apply(); 675 } 676 stopTransition(); 677 backNavigationInfo.onBackNavigationFinished(triggerBack); 678 if (USE_TRANSITION) { 679 final IBackNaviAnimationController controller = mBackAnimationController; 680 if (controller != null) { 681 try { 682 controller.finish(triggerBack); 683 } catch (RemoteException r) { 684 // Oh no! 685 } 686 } 687 mBackAnimationController = null; 688 } 689 } 690 startTransition()691 private void startTransition() { 692 if (mTransitionInProgress) { 693 return; 694 } 695 mTransitionInProgress = true; 696 mShellExecutor.executeDelayed(mResetTransitionRunnable, MAX_TRANSITION_DURATION); 697 } 698 stopTransition()699 private void stopTransition() { 700 if (!mTransitionInProgress) { 701 return; 702 } 703 mShellExecutor.removeCallbacks(mResetTransitionRunnable); 704 mTransitionInProgress = false; 705 } 706 createAdaptor()707 private void createAdaptor() { 708 mIBackAnimationRunner = new IBackAnimationRunner.Stub() { 709 @Override 710 public void onAnimationCancelled() { 711 // no op for now 712 } 713 @Override // Binder interface 714 public void onAnimationStart(IBackNaviAnimationController controller, int type, 715 RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, 716 RemoteAnimationTarget[] nonApps) { 717 mShellExecutor.execute(() -> { 718 mBackAnimationController = controller; 719 for (int i = 0; i < apps.length; i++) { 720 final RemoteAnimationTarget target = apps[i]; 721 if (MODE_CLOSING == target.mode) { 722 mAnimationTarget = target; 723 } else if (MODE_OPENING == target.mode) { 724 // TODO Home activity should handle the visibility for itself 725 // once it finish relayout for orientation change 726 SurfaceControl.Transaction tx = 727 new SurfaceControl.Transaction(); 728 tx.setAlpha(target.leash, 1); 729 tx.apply(); 730 } 731 } 732 dispatchOnBackStarted(mBackToLauncherCallback, 733 mTouchTracker.createStartEvent(mAnimationTarget)); 734 final BackMotionEvent backInit = mTouchTracker.createProgressEvent(); 735 if (!mCachingBackDispatcher.consume()) { 736 dispatchOnBackProgressed(mBackToLauncherCallback, backInit); 737 } 738 }); 739 } 740 }; 741 mBackAnimationAdaptor = new BackAnimationAdaptor(mIBackAnimationRunner, 742 BackNavigationInfo.TYPE_RETURN_TO_HOME); 743 } 744 } 745