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