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.RemoteException;
24 import android.util.Log;
25 import android.view.IRemoteAnimationFinishedCallback;
26 import android.view.IRemoteAnimationRunner;
27 import android.view.RemoteAnimationTarget;
28 import android.window.IBackAnimationRunner;
29 import android.window.IOnBackInvokedCallback;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 import com.android.internal.jank.Cuj.CujType;
33 import com.android.wm.shell.common.InteractionJankMonitorUtils;
34 
35 /**
36  * Used to register the animation callback and runner, it will trigger result if gesture was finish
37  * before it received IBackAnimationRunner#onAnimationStart, so the controller could continue
38  * trigger the real back behavior.
39  */
40 public class BackAnimationRunner {
41     private static final int NO_CUJ = -1;
42     private static final String TAG = "ShellBackPreview";
43 
44     private final IOnBackInvokedCallback mCallback;
45     private final IRemoteAnimationRunner mRunner;
46     private final @CujType int mCujType;
47     private final Context mContext;
48 
49     // Whether we are waiting to receive onAnimationStart
50     private boolean mWaitingAnimation;
51 
52     /** True when the back animation is cancelled */
53     private boolean mAnimationCancelled;
54 
BackAnimationRunner( @onNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner, @NonNull Context context, @CujType int cujType)55     public BackAnimationRunner(
56             @NonNull IOnBackInvokedCallback callback,
57             @NonNull IRemoteAnimationRunner runner,
58             @NonNull Context context,
59             @CujType int cujType) {
60         mCallback = callback;
61         mRunner = runner;
62         mCujType = cujType;
63         mContext = context;
64     }
65 
BackAnimationRunner( @onNull IOnBackInvokedCallback callback, @NonNull IRemoteAnimationRunner runner, @NonNull Context context)66     public BackAnimationRunner(
67             @NonNull IOnBackInvokedCallback callback,
68             @NonNull IRemoteAnimationRunner runner,
69             @NonNull Context context) {
70         this(callback, runner, context, NO_CUJ);
71     }
72 
73     /** Returns the registered animation runner */
getRunner()74     IRemoteAnimationRunner getRunner() {
75         return mRunner;
76     }
77 
78     /** Returns the registered animation callback */
getCallback()79     IOnBackInvokedCallback getCallback() {
80         return mCallback;
81     }
82 
83     /**
84      * Called from {@link IBackAnimationRunner}, it will deliver these
85      * {@link RemoteAnimationTarget}s to the corresponding runner.
86      */
startAnimation(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, Runnable finishedCallback)87     void startAnimation(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
88             RemoteAnimationTarget[] nonApps, Runnable finishedCallback) {
89         final IRemoteAnimationFinishedCallback callback =
90                 new IRemoteAnimationFinishedCallback.Stub() {
91                     @Override
92                     public void onAnimationFinished() {
93                         if (shouldMonitorCUJ(apps)) {
94                             InteractionJankMonitorUtils.endTracing(mCujType);
95                         }
96                         finishedCallback.run();
97                     }
98                 };
99         mWaitingAnimation = false;
100         if (shouldMonitorCUJ(apps)) {
101             InteractionJankMonitorUtils.beginTracing(
102                     mCujType, mContext, apps[0].leash, /* tag */ null);
103         }
104         try {
105             getRunner().onAnimationStart(TRANSIT_OLD_UNSET, apps, wallpapers,
106                     nonApps, callback);
107         } catch (RemoteException e) {
108             Log.w(TAG, "Failed call onAnimationStart", e);
109         }
110     }
111 
112     @VisibleForTesting
shouldMonitorCUJ(RemoteAnimationTarget[] apps)113     boolean shouldMonitorCUJ(RemoteAnimationTarget[] apps) {
114         return apps.length > 0 && mCujType != NO_CUJ;
115     }
116 
startGesture()117     void startGesture() {
118         mWaitingAnimation = true;
119         mAnimationCancelled = false;
120     }
121 
isWaitingAnimation()122     boolean isWaitingAnimation() {
123         return mWaitingAnimation;
124     }
125 
cancelAnimation()126     void cancelAnimation() {
127         mWaitingAnimation = false;
128         mAnimationCancelled = true;
129     }
130 
isAnimationCancelled()131     boolean isAnimationCancelled() {
132         return mAnimationCancelled;
133     }
134 
resetWaitingAnimation()135     void resetWaitingAnimation() {
136         mWaitingAnimation = false;
137     }
138 }
139