• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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