• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.WindowManager.TRANSIT_OLD_UNSET;
20 
21 import android.annotation.NonNull;
22 import android.content.Context;
23 import android.os.Handler;
24 import android.os.RemoteException;
25 import android.util.Log;
26 import android.view.IRemoteAnimationFinishedCallback;
27 import android.view.IRemoteAnimationRunner;
28 import android.view.RemoteAnimationTarget;
29 import android.view.SurfaceControl;
30 import android.window.IBackAnimationRunner;
31 import android.window.IOnBackInvokedCallback;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.jank.Cuj.CujType;
35 import com.android.internal.jank.InteractionJankMonitor;
36 import com.android.wm.shell.shared.annotations.ShellMainThread;
37 
38 import java.lang.ref.WeakReference;
39 
40 /**
41  * Used to register the animation callback and runner, it will trigger result if gesture was finish
42  * before it received IBackAnimationRunner#onAnimationStart, so the controller could continue
43  * trigger the real back behavior.
44  */
45 public class BackAnimationRunner {
46     private static final int NO_CUJ = -1;
47     private static final String TAG = "ShellBackPreview";
48 
49     private final IOnBackInvokedCallback mCallback;
50     private final IRemoteAnimationRunner mRunner;
51     private final @CujType int mCujType;
52     private final Context mContext;
53     @ShellMainThread
54     private final Handler mHandler;
55 
56     // Whether we are waiting to receive onAnimationStart
57     private boolean mWaitingAnimation;
58 
59     /** True when the back animation is cancelled */
60     private boolean mAnimationCancelled;
61 
BackAnimationRunner( @onNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner, @NonNull Context context, @CujType int cujType, @ShellMainThread Handler handler)62     public BackAnimationRunner(
63             @NonNull IOnBackInvokedCallback callback,
64             @NonNull IRemoteAnimationRunner runner,
65             @NonNull Context context,
66             @CujType int cujType,
67             @ShellMainThread Handler handler) {
68         mCallback = callback;
69         mRunner = runner;
70         mCujType = cujType;
71         mContext = context;
72         mHandler = handler;
73     }
74 
BackAnimationRunner( @onNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner, @NonNull Context context, @ShellMainThread Handler handler )75     public BackAnimationRunner(
76             @NonNull IOnBackInvokedCallback callback,
77             @NonNull IRemoteAnimationRunner runner,
78             @NonNull Context context,
79             @ShellMainThread Handler handler
80     ) {
81         this(callback, runner, context, NO_CUJ, handler);
82     }
83 
84     /**
85      * @deprecated Use {@link BackAnimationRunner} constructor providing an handler for the ui
86      * thread of the animation.
87      */
88     @Deprecated
BackAnimationRunner( @onNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner, @NonNull Context context )89     public BackAnimationRunner(
90             @NonNull IOnBackInvokedCallback callback,
91             @NonNull IRemoteAnimationRunner runner,
92             @NonNull Context context
93     ) {
94         this(callback, runner, context, NO_CUJ, context.getMainThreadHandler());
95     }
96 
97     /** Returns the registered animation runner */
getRunner()98     IRemoteAnimationRunner getRunner() {
99         return mRunner;
100     }
101 
102     /** Returns the registered animation callback */
getCallback()103     IOnBackInvokedCallback getCallback() {
104         return mCallback;
105     }
106 
107     private Runnable mFinishedCallback;
108     private RemoteAnimationTarget[] mApps;
109     private RemoteAnimationFinishedStub mRemoteCallback;
110 
111     private static class RemoteAnimationFinishedStub extends IRemoteAnimationFinishedCallback.Stub {
112         //the binder callback should not hold strong reference to it to avoid memory leak.
113         private final WeakReference<BackAnimationRunner> mRunnerRef;
114         private boolean mAbandoned;
115 
RemoteAnimationFinishedStub(BackAnimationRunner runner)116         private RemoteAnimationFinishedStub(BackAnimationRunner runner) {
117             mRunnerRef = new WeakReference<>(runner);
118         }
119 
120         @Override
onAnimationFinished()121         public void onAnimationFinished() {
122             synchronized (this) {
123                 if (mAbandoned) {
124                     return;
125                 }
126             }
127             final BackAnimationRunner runner = mRunnerRef.get();
128             if (runner == null) {
129                 return;
130             }
131             runner.onAnimationFinish(this);
132         }
133 
abandon()134         void abandon() {
135             synchronized (this) {
136                 mAbandoned = true;
137                 final BackAnimationRunner runner = mRunnerRef.get();
138                 if (runner == null) {
139                     return;
140                 }
141                 if (runner.shouldMonitorCUJ(runner.mApps)) {
142                     InteractionJankMonitor.getInstance().end(runner.mCujType);
143                 }
144             }
145         }
146     }
147 
148     /**
149      * Called from {@link IBackAnimationRunner}, it will deliver these
150      * {@link RemoteAnimationTarget}s to the corresponding runner.
151      */
startAnimation(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, Runnable finishedCallback)152     void startAnimation(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
153             RemoteAnimationTarget[] nonApps, Runnable finishedCallback) {
154         if (mRemoteCallback != null) {
155             mRemoteCallback.abandon();
156             mRemoteCallback = null;
157         }
158         mRemoteCallback = new RemoteAnimationFinishedStub(this);
159         mFinishedCallback = finishedCallback;
160         mApps = apps;
161         mWaitingAnimation = false;
162         if (shouldMonitorCUJ(apps)) {
163             InteractionJankMonitor.getInstance().begin(
164                     apps[0].leash, mContext, mHandler, mCujType);
165         }
166         try {
167             getRunner().onAnimationStart(TRANSIT_OLD_UNSET, apps, wallpapers,
168                     nonApps, mRemoteCallback);
169         } catch (RemoteException e) {
170             Log.w(TAG, "Failed call onAnimationStart", e);
171         }
172     }
173 
onAnimationFinish(RemoteAnimationFinishedStub finished)174     void onAnimationFinish(RemoteAnimationFinishedStub finished) {
175         mHandler.post(() -> {
176             if (mRemoteCallback != null && finished != mRemoteCallback) {
177                 return;
178             }
179             if (shouldMonitorCUJ(mApps)) {
180                 InteractionJankMonitor.getInstance().end(mCujType);
181             }
182 
183             mFinishedCallback.run();
184             for (int i = mApps.length - 1; i >= 0; --i) {
185                 final SurfaceControl sc = mApps[i].leash;
186                 if (sc != null && sc.isValid()) {
187                     sc.release();
188                 }
189             }
190             mApps = null;
191             mFinishedCallback = null;
192             mRemoteCallback = null;
193         });
194     }
195 
196     @VisibleForTesting
shouldMonitorCUJ(RemoteAnimationTarget[] apps)197     boolean shouldMonitorCUJ(RemoteAnimationTarget[] apps) {
198         return apps.length > 0 && mCujType != NO_CUJ;
199     }
200 
startGesture()201     void startGesture() {
202         mWaitingAnimation = true;
203         mAnimationCancelled = false;
204     }
205 
isWaitingAnimation()206     boolean isWaitingAnimation() {
207         return mWaitingAnimation;
208     }
209 
cancelAnimation()210     void cancelAnimation() {
211         mWaitingAnimation = false;
212         mAnimationCancelled = true;
213     }
214 
isAnimationCancelled()215     boolean isAnimationCancelled() {
216         return mAnimationCancelled;
217     }
218 
resetWaitingAnimation()219     void resetWaitingAnimation() {
220         mWaitingAnimation = false;
221     }
222 }
223