RemoteAnimationController.java revision ab09e6472fc175077561cd55f2c1aa1d57683c9e
1/* 2 * Copyright (C) 2018 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 17package com.android.server.wm; 18 19import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 21 22import android.graphics.Point; 23import android.graphics.Rect; 24import android.os.Handler; 25import android.os.RemoteException; 26import android.os.SystemClock; 27import android.util.Slog; 28import android.view.IRemoteAnimationFinishedCallback; 29import android.view.IRemoteAnimationFinishedCallback.Stub; 30import android.view.RemoteAnimationAdapter; 31import android.view.RemoteAnimationTarget; 32import android.view.SurfaceControl; 33import android.view.SurfaceControl.Transaction; 34 35import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; 36 37import java.util.ArrayList; 38 39/** 40 * Helper class to run app animations in a remote process. 41 */ 42class RemoteAnimationController { 43 private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM; 44 private static final long TIMEOUT_MS = 2000; 45 46 private final WindowManagerService mService; 47 private final RemoteAnimationAdapter mRemoteAnimationAdapter; 48 private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>(); 49 private final Rect mTmpRect = new Rect(); 50 private final Handler mHandler; 51 52 private final IRemoteAnimationFinishedCallback mFinishedCallback = new Stub() { 53 @Override 54 public void onAnimationFinished() throws RemoteException { 55 RemoteAnimationController.this.onAnimationFinished(); 56 } 57 }; 58 59 private final Runnable mTimeoutRunnable = () -> { 60 onAnimationFinished(); 61 invokeAnimationCancelled(); 62 }; 63 64 RemoteAnimationController(WindowManagerService service, 65 RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) { 66 mService = service; 67 mRemoteAnimationAdapter = remoteAnimationAdapter; 68 mHandler = handler; 69 } 70 71 /** 72 * Creates an animation for each individual {@link AppWindowToken}. 73 * 74 * @param appWindowToken The app to animate. 75 * @param position The position app bounds, in screen coordinates. 76 * @param stackBounds The stack bounds of the app. 77 * @return The adapter to be run on the app. 78 */ 79 AnimationAdapter createAnimationAdapter(AppWindowToken appWindowToken, Point position, 80 Rect stackBounds) { 81 final RemoteAnimationAdapterWrapper adapter = new RemoteAnimationAdapterWrapper( 82 appWindowToken, position, stackBounds); 83 mPendingAnimations.add(adapter); 84 return adapter; 85 } 86 87 /** 88 * Called when the transition is ready to be started, and all leashes have been set up. 89 */ 90 void goodToGo() { 91 if (mPendingAnimations.isEmpty()) { 92 onAnimationFinished(); 93 return; 94 } 95 96 // Scale the timeout with the animator scale the controlling app is using. 97 mHandler.postDelayed(mTimeoutRunnable, 98 (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale())); 99 100 final RemoteAnimationTarget[] animations = createAnimations(); 101 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> { 102 try { 103 mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, 104 mFinishedCallback); 105 } catch (RemoteException e) { 106 Slog.e(TAG, "Failed to start remote animation", e); 107 onAnimationFinished(); 108 } 109 }); 110 } 111 112 private RemoteAnimationTarget[] createAnimations() { 113 final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); 114 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 115 final RemoteAnimationTarget target = 116 mPendingAnimations.get(i).createRemoteAppAnimation(); 117 if (target != null) { 118 targets.add(target); 119 } 120 } 121 return targets.toArray(new RemoteAnimationTarget[targets.size()]); 122 } 123 124 private void onAnimationFinished() { 125 mHandler.removeCallbacks(mTimeoutRunnable); 126 synchronized (mService.mWindowMap) { 127 mService.openSurfaceTransaction(); 128 try { 129 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 130 final RemoteAnimationAdapterWrapper adapter = mPendingAnimations.get(i); 131 adapter.mCapturedFinishCallback.onAnimationFinished(adapter); 132 } 133 } finally { 134 mService.closeSurfaceTransaction("RemoteAnimationController#finished"); 135 } 136 } 137 } 138 139 private void invokeAnimationCancelled() { 140 try { 141 mRemoteAnimationAdapter.getRunner().onAnimationCancelled(); 142 } catch (RemoteException e) { 143 Slog.e(TAG, "Failed to notify cancel", e); 144 } 145 } 146 147 private class RemoteAnimationAdapterWrapper implements AnimationAdapter { 148 149 private final AppWindowToken mAppWindowToken; 150 private SurfaceControl mCapturedLeash; 151 private OnAnimationFinishedCallback mCapturedFinishCallback; 152 private final Point mPosition = new Point(); 153 private final Rect mStackBounds = new Rect(); 154 155 RemoteAnimationAdapterWrapper(AppWindowToken appWindowToken, Point position, 156 Rect stackBounds) { 157 mAppWindowToken = appWindowToken; 158 mPosition.set(position.x, position.y); 159 mStackBounds.set(stackBounds); 160 } 161 162 RemoteAnimationTarget createRemoteAppAnimation() { 163 final Task task = mAppWindowToken.getTask(); 164 final WindowState mainWindow = mAppWindowToken.findMainWindow(); 165 if (task == null) { 166 return null; 167 } 168 if (mainWindow == null) { 169 return null; 170 } 171 return new RemoteAnimationTarget(task.mTaskId, getMode(), 172 mCapturedLeash, !mAppWindowToken.fillsParent(), 173 mainWindow.mWinAnimator.mLastClipRect, 174 mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds, 175 task.getWindowConfiguration()); 176 } 177 178 private int getMode() { 179 if (mService.mOpeningApps.contains(mAppWindowToken)) { 180 return RemoteAnimationTarget.MODE_OPENING; 181 } else { 182 return RemoteAnimationTarget.MODE_CLOSING; 183 } 184 } 185 186 @Override 187 public boolean getDetachWallpaper() { 188 return false; 189 } 190 191 @Override 192 public int getBackgroundColor() { 193 return 0; 194 } 195 196 @Override 197 public void startAnimation(SurfaceControl animationLeash, Transaction t, 198 OnAnimationFinishedCallback finishCallback) { 199 200 // Restore z-layering, position and stack crop until client has a chance to modify it. 201 t.setLayer(animationLeash, mAppWindowToken.getPrefixOrderIndex()); 202 t.setPosition(animationLeash, mPosition.x, mPosition.y); 203 mTmpRect.set(mStackBounds); 204 mTmpRect.offsetTo(0, 0); 205 t.setWindowCrop(animationLeash, mTmpRect); 206 mCapturedLeash = animationLeash; 207 mCapturedFinishCallback = finishCallback; 208 } 209 210 @Override 211 public void onAnimationCancelled(SurfaceControl animationLeash) { 212 mPendingAnimations.remove(this); 213 if (mPendingAnimations.isEmpty()) { 214 mHandler.removeCallbacks(mTimeoutRunnable); 215 invokeAnimationCancelled(); 216 } 217 } 218 219 @Override 220 public long getDurationHint() { 221 return mRemoteAnimationAdapter.getDuration(); 222 } 223 224 @Override 225 public long getStatusBarTransitionsStartTime() { 226 return SystemClock.uptimeMillis() 227 + mRemoteAnimationAdapter.getStatusBarTransitionDelay(); 228 } 229 } 230} 231