RemoteAnimationController.java revision 9f8518e532e41ba57916afc49bba72bc23ad3eda
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 mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS); 92 try { 93 mRemoteAnimationAdapter.getRunner().onAnimationStart(createAnimations(), 94 mFinishedCallback); 95 } catch (RemoteException e) { 96 Slog.e(TAG, "Failed to start remote animation", e); 97 onAnimationFinished(); 98 } 99 } 100 101 private RemoteAnimationTarget[] createAnimations() { 102 final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>(); 103 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 104 final RemoteAnimationTarget target = 105 mPendingAnimations.get(i).createRemoteAppAnimation(); 106 if (target != null) { 107 targets.add(target); 108 } 109 } 110 return targets.toArray(new RemoteAnimationTarget[targets.size()]); 111 } 112 113 private void onAnimationFinished() { 114 mHandler.removeCallbacks(mTimeoutRunnable); 115 synchronized (mService.mWindowMap) { 116 mService.openSurfaceTransaction(); 117 try { 118 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) { 119 final RemoteAnimationAdapterWrapper adapter = mPendingAnimations.get(i); 120 adapter.mCapturedFinishCallback.onAnimationFinished(adapter); 121 } 122 } finally { 123 mService.closeSurfaceTransaction("RemoteAnimationController#finished"); 124 } 125 } 126 } 127 128 private void invokeAnimationCancelled() { 129 try { 130 mRemoteAnimationAdapter.getRunner().onAnimationCancelled(); 131 } catch (RemoteException e) { 132 Slog.e(TAG, "Failed to notify cancel", e); 133 } 134 } 135 136 private class RemoteAnimationAdapterWrapper implements AnimationAdapter { 137 138 private final AppWindowToken mAppWindowToken; 139 private SurfaceControl mCapturedLeash; 140 private OnAnimationFinishedCallback mCapturedFinishCallback; 141 private final Point mPosition = new Point(); 142 private final Rect mStackBounds = new Rect(); 143 144 RemoteAnimationAdapterWrapper(AppWindowToken appWindowToken, Point position, 145 Rect stackBounds) { 146 mAppWindowToken = appWindowToken; 147 mPosition.set(position.x, position.y); 148 mStackBounds.set(stackBounds); 149 } 150 151 RemoteAnimationTarget createRemoteAppAnimation() { 152 final Task task = mAppWindowToken.getTask(); 153 final WindowState mainWindow = mAppWindowToken.findMainWindow(); 154 if (task == null) { 155 return null; 156 } 157 if (mainWindow == null) { 158 return null; 159 } 160 return new RemoteAnimationTarget(task.mTaskId, getMode(), 161 mCapturedLeash, !mAppWindowToken.fillsParent(), 162 mainWindow.mWinAnimator.mLastClipRect, 163 mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds); 164 } 165 166 private int getMode() { 167 if (mService.mOpeningApps.contains(mAppWindowToken)) { 168 return RemoteAnimationTarget.MODE_OPENING; 169 } else { 170 return RemoteAnimationTarget.MODE_CLOSING; 171 } 172 } 173 174 @Override 175 public boolean getDetachWallpaper() { 176 return false; 177 } 178 179 @Override 180 public int getBackgroundColor() { 181 return 0; 182 } 183 184 @Override 185 public void startAnimation(SurfaceControl animationLeash, Transaction t, 186 OnAnimationFinishedCallback finishCallback) { 187 188 // Restore z-layering, position and stack crop until client has a chance to modify it. 189 t.setLayer(animationLeash, mAppWindowToken.getPrefixOrderIndex()); 190 t.setPosition(animationLeash, mPosition.x, mPosition.y); 191 mTmpRect.set(mStackBounds); 192 mTmpRect.offsetTo(0, 0); 193 t.setWindowCrop(animationLeash, mTmpRect); 194 mCapturedLeash = animationLeash; 195 mCapturedFinishCallback = finishCallback; 196 } 197 198 @Override 199 public void onAnimationCancelled(SurfaceControl animationLeash) { 200 mPendingAnimations.remove(this); 201 if (mPendingAnimations.isEmpty()) { 202 mHandler.removeCallbacks(mTimeoutRunnable); 203 invokeAnimationCancelled(); 204 } 205 } 206 207 @Override 208 public long getDurationHint() { 209 return mRemoteAnimationAdapter.getDuration(); 210 } 211 212 @Override 213 public long getStatusBarTransitionsStartTime() { 214 return SystemClock.uptimeMillis() 215 + mRemoteAnimationAdapter.getStatusBarTransitionDelay(); 216 } 217 } 218} 219