ScreenRotationAnimation.java revision bc68a59c024bdb745dac8e2ec7408a9f30595f1a
1/* 2 * Copyright (C) 2010 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 android.content.Context; 20import android.graphics.Bitmap; 21import android.graphics.Canvas; 22import android.graphics.Matrix; 23import android.graphics.Paint; 24import android.graphics.PixelFormat; 25import android.graphics.PorterDuff; 26import android.graphics.PorterDuffXfermode; 27import android.graphics.Rect; 28import android.util.Slog; 29import android.view.Surface; 30import android.view.SurfaceSession; 31import android.view.animation.Animation; 32import android.view.animation.AnimationUtils; 33import android.view.animation.Transformation; 34 35class ScreenRotationAnimation { 36 static final String TAG = "ScreenRotationAnimation"; 37 static final boolean DEBUG = false; 38 39 static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200; 40 41 final Context mContext; 42 Surface mSurface; 43 BlackFrame mBlackFrame; 44 int mWidth, mHeight; 45 46 int mSnapshotRotation; 47 int mSnapshotDeltaRotation; 48 int mOriginalRotation; 49 int mOriginalWidth, mOriginalHeight; 50 int mCurRotation; 51 52 Animation mExitAnimation; 53 final Transformation mExitTransformation = new Transformation(); 54 Animation mEnterAnimation; 55 final Transformation mEnterTransformation = new Transformation(); 56 boolean mStarted; 57 58 final Matrix mSnapshotInitialMatrix = new Matrix(); 59 final Matrix mSnapshotFinalMatrix = new Matrix(); 60 final Matrix mTmpMatrix = new Matrix(); 61 final float[] mTmpFloats = new float[9]; 62 63 public ScreenRotationAnimation(Context context, SurfaceSession session, 64 boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) { 65 mContext = context; 66 67 Bitmap screenshot = Surface.screenshot(0, 0); 68 69 if (screenshot == null) { 70 // Device is not capable of screenshots... we can't do an animation. 71 return; 72 } 73 74 // Screenshot does NOT include rotation! 75 mSnapshotRotation = 0; 76 mWidth = screenshot.getWidth(); 77 mHeight = screenshot.getHeight(); 78 79 mOriginalRotation = originalRotation; 80 mOriginalWidth = originalWidth; 81 mOriginalHeight = originalHeight; 82 83 if (!inTransaction) { 84 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, 85 ">>> OPEN TRANSACTION ScreenRotationAnimation"); 86 Surface.openTransaction(); 87 } 88 89 try { 90 try { 91 mSurface = new Surface(session, 0, "FreezeSurface", 92 -1, mWidth, mHeight, PixelFormat.OPAQUE, 0); 93 mSurface.setLayer(FREEZE_LAYER + 1); 94 } catch (Surface.OutOfResourcesException e) { 95 Slog.w(TAG, "Unable to allocate freeze surface", e); 96 } 97 98 if (WindowManagerService.SHOW_TRANSACTIONS || 99 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, 100 " FREEZE " + mSurface + ": CREATE"); 101 102 setRotation(originalRotation); 103 104 if (mSurface != null) { 105 Rect dirty = new Rect(0, 0, mWidth, mHeight); 106 Canvas c = null; 107 try { 108 c = mSurface.lockCanvas(dirty); 109 } catch (IllegalArgumentException e) { 110 Slog.w(TAG, "Unable to lock surface", e); 111 } catch (Surface.OutOfResourcesException e) { 112 Slog.w(TAG, "Unable to lock surface", e); 113 } 114 if (c == null) { 115 Slog.w(TAG, "Null surface canvas"); 116 mSurface.destroy(); 117 mSurface = null; 118 return; 119 } 120 121 Paint paint = new Paint(0); 122 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); 123 c.drawBitmap(screenshot, 0, 0, paint); 124 125 mSurface.unlockCanvasAndPost(c); 126 } 127 } finally { 128 if (!inTransaction) { 129 Surface.closeTransaction(); 130 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, 131 "<<< CLOSE TRANSACTION ScreenRotationAnimation"); 132 } 133 134 screenshot.recycle(); 135 } 136 } 137 138 boolean hasScreenshot() { 139 return mSurface != null; 140 } 141 142 static int deltaRotation(int oldRotation, int newRotation) { 143 int delta = newRotation - oldRotation; 144 if (delta < 0) delta += 4; 145 return delta; 146 } 147 148 void setSnapshotTransform(Matrix matrix, float alpha) { 149 if (mSurface != null) { 150 matrix.getValues(mTmpFloats); 151 mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X], 152 (int)mTmpFloats[Matrix.MTRANS_Y]); 153 mSurface.setMatrix( 154 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], 155 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); 156 mSurface.setAlpha(alpha); 157 if (DEBUG) { 158 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight }; 159 float[] dstPnts = new float[4]; 160 matrix.mapPoints(dstPnts, srcPnts); 161 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1] 162 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")"); 163 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1] 164 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")"); 165 } 166 } 167 } 168 169 public static void createRotationMatrix(int rotation, int width, int height, 170 Matrix outMatrix) { 171 switch (rotation) { 172 case Surface.ROTATION_0: 173 outMatrix.reset(); 174 break; 175 case Surface.ROTATION_90: 176 outMatrix.setRotate(90, 0, 0); 177 outMatrix.postTranslate(height, 0); 178 break; 179 case Surface.ROTATION_180: 180 outMatrix.setRotate(180, 0, 0); 181 outMatrix.postTranslate(width, height); 182 break; 183 case Surface.ROTATION_270: 184 outMatrix.setRotate(270, 0, 0); 185 outMatrix.postTranslate(0, width); 186 break; 187 } 188 } 189 190 // Must be called while in a transaction. 191 public void setRotation(int rotation) { 192 mCurRotation = rotation; 193 194 // Compute the transformation matrix that must be applied 195 // to the snapshot to make it stay in the same original position 196 // with the current screen rotation. 197 int delta = deltaRotation(rotation, mSnapshotRotation); 198 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); 199 200 if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta); 201 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f); 202 } 203 204 /** 205 * Returns true if animating. 206 */ 207 public boolean dismiss(SurfaceSession session, long maxAnimationDuration, 208 float animationScale, int finalWidth, int finalHeight) { 209 if (mSurface == null) { 210 // Can't do animation. 211 return false; 212 } 213 214 // Figure out how the screen has moved from the original rotation. 215 int delta = deltaRotation(mCurRotation, mOriginalRotation); 216 217 switch (delta) { 218 case Surface.ROTATION_0: 219 mExitAnimation = AnimationUtils.loadAnimation(mContext, 220 com.android.internal.R.anim.screen_rotate_0_exit); 221 mEnterAnimation = AnimationUtils.loadAnimation(mContext, 222 com.android.internal.R.anim.screen_rotate_0_enter); 223 break; 224 case Surface.ROTATION_90: 225 mExitAnimation = AnimationUtils.loadAnimation(mContext, 226 com.android.internal.R.anim.screen_rotate_plus_90_exit); 227 mEnterAnimation = AnimationUtils.loadAnimation(mContext, 228 com.android.internal.R.anim.screen_rotate_plus_90_enter); 229 break; 230 case Surface.ROTATION_180: 231 mExitAnimation = AnimationUtils.loadAnimation(mContext, 232 com.android.internal.R.anim.screen_rotate_180_exit); 233 mEnterAnimation = AnimationUtils.loadAnimation(mContext, 234 com.android.internal.R.anim.screen_rotate_180_enter); 235 break; 236 case Surface.ROTATION_270: 237 mExitAnimation = AnimationUtils.loadAnimation(mContext, 238 com.android.internal.R.anim.screen_rotate_minus_90_exit); 239 mEnterAnimation = AnimationUtils.loadAnimation(mContext, 240 com.android.internal.R.anim.screen_rotate_minus_90_enter); 241 break; 242 } 243 244 // Initialize the animations. This is a hack, redefining what "parent" 245 // means to allow supplying the last and next size. In this definition 246 // "%p" is the original (let's call it "previous") size, and "%" is the 247 // screen's current/new size. 248 mEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); 249 mExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); 250 mStarted = false; 251 252 mExitAnimation.restrictDuration(maxAnimationDuration); 253 mExitAnimation.scaleCurrentDuration(animationScale); 254 mEnterAnimation.restrictDuration(maxAnimationDuration); 255 mEnterAnimation.scaleCurrentDuration(animationScale); 256 257 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, 258 ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss"); 259 Surface.openTransaction(); 260 261 try { 262 Rect outer = new Rect(-finalWidth, -finalHeight, finalWidth * 2, finalHeight * 2); 263 Rect inner = new Rect(0, 0, finalWidth, finalHeight); 264 mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER); 265 } catch (Surface.OutOfResourcesException e) { 266 Slog.w(TAG, "Unable to allocate black surface", e); 267 } finally { 268 Surface.closeTransaction(); 269 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, 270 "<<< CLOSE TRANSACTION ScreenRotationAnimation.dismiss"); 271 } 272 273 return true; 274 } 275 276 public void kill() { 277 if (mSurface != null) { 278 if (WindowManagerService.SHOW_TRANSACTIONS || 279 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, 280 " FREEZE " + mSurface + ": DESTROY"); 281 mSurface.destroy(); 282 mSurface = null; 283 } 284 if (mBlackFrame != null) { 285 mBlackFrame.kill(); 286 } 287 if (mExitAnimation != null) { 288 mExitAnimation.cancel(); 289 mExitAnimation = null; 290 } 291 if (mEnterAnimation != null) { 292 mEnterAnimation.cancel(); 293 mEnterAnimation = null; 294 } 295 } 296 297 public boolean isAnimating() { 298 return mEnterAnimation != null || mExitAnimation != null; 299 } 300 301 public boolean stepAnimation(long now) { 302 if (mEnterAnimation == null && mExitAnimation == null) { 303 return false; 304 } 305 306 if (!mStarted) { 307 mEnterAnimation.setStartTime(now); 308 mExitAnimation.setStartTime(now); 309 mStarted = true; 310 } 311 312 mExitTransformation.clear(); 313 boolean moreExit = false; 314 if (mExitAnimation != null) { 315 moreExit = mExitAnimation.getTransformation(now, mExitTransformation); 316 if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation); 317 if (!moreExit) { 318 if (DEBUG) Slog.v(TAG, "Exit animation done!"); 319 mExitAnimation.cancel(); 320 mExitAnimation = null; 321 mExitTransformation.clear(); 322 if (mSurface != null) { 323 mSurface.hide(); 324 } 325 } 326 } 327 328 mEnterTransformation.clear(); 329 boolean moreEnter = false; 330 if (mEnterAnimation != null) { 331 moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation); 332 if (!moreEnter) { 333 mEnterAnimation.cancel(); 334 mEnterAnimation = null; 335 mEnterTransformation.clear(); 336 if (mBlackFrame != null) { 337 mBlackFrame.hide(); 338 } 339 } else { 340 if (mBlackFrame != null) { 341 mBlackFrame.setMatrix(mEnterTransformation.getMatrix()); 342 } 343 } 344 } 345 346 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); 347 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); 348 349 return moreEnter || moreExit; 350 } 351 352 public Transformation getEnterTransformation() { 353 return mEnterTransformation; 354 } 355} 356