More work on rotation animation.

The black frame is now a separate animation element.  This allows us
to have it move through the aspect ratio change, without the old
and new screen elements doing weird aspect ratio scalings.  This
makes the animation generally look different (more like a reveal),
not sure if it is better or worse, but definitely has less artifacts
in things like the gallery.

Also tweaked the animation definitions a bit.

Change-Id: I94c274ba04bbc7a675946dc6c1778e19386e4a66
diff --git a/core/res/res/anim/screen_rotate_0_frame.xml b/core/res/res/anim/screen_rotate_0_frame.xml
new file mode 100644
index 0000000..5ea9bf8
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_0_frame.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <alpha android:fromAlpha="1.0" android:toAlpha="1.0"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml
index 470416b..688a8d5 100644
--- a/core/res/res/anim/screen_rotate_180_enter.xml
+++ b/core/res/res/anim/screen_rotate_180_enter.xml
@@ -25,4 +25,4 @@
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
             android:duration="@android:integer/config_mediumAnimTime" />
-</set>
\ No newline at end of file
+</set>
diff --git a/core/res/res/anim/screen_rotate_180_frame.xml b/core/res/res/anim/screen_rotate_180_frame.xml
new file mode 100644
index 0000000..19dade1
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_180_frame.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License. 
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <rotate android:fromDegrees="180" android:toDegrees="0"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_finish_enter.xml b/core/res/res/anim/screen_rotate_finish_enter.xml
index 849aa66..9d731e6 100644
--- a/core/res/res/anim/screen_rotate_finish_enter.xml
+++ b/core/res/res/anim/screen_rotate_finish_enter.xml
@@ -19,13 +19,14 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <scale android:fromXScale="1.0" android:toXScale="1.25"
-            android:fromYScale="1.0" android:toYScale="1.25"
+    <scale android:fromXScale="1.0" android:toXScale="1.1111111111111"
+            android:fromYScale="1.0" android:toYScale="1.1111111111111"
             android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
+            android:interpolator="@interpolator/accelerate_decelerate"
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_mediumAnimTime"/>
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <!--
     <scale android:fromXScale="100%p" android:toXScale="100%"
             android:fromYScale="100%p" android:toYScale="100%"
             android:pivotX="50%" android:pivotY="50%"
@@ -33,4 +34,5 @@
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
             android:duration="@android:integer/config_mediumAnimTime" />
+    -->
 </set>
diff --git a/core/res/res/anim/screen_rotate_finish_exit.xml b/core/res/res/anim/screen_rotate_finish_exit.xml
index 7f70dbc..60daa18 100644
--- a/core/res/res/anim/screen_rotate_finish_exit.xml
+++ b/core/res/res/anim/screen_rotate_finish_exit.xml
@@ -19,23 +19,21 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <scale android:fromXScale="1.0" android:toXScale="1.25"
-            android:fromYScale="1.0" android:toYScale="1.25"
+    <scale android:fromXScale="1.0" android:toXScale="1.0"
+            android:fromYScale="1.0" android:toYScale="1.0"
             android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
+            android:interpolator="@interpolator/accelerate_decelerate"
             android:fillEnabled="true"
             android:fillBefore="false" android:fillAfter="true"
-            android:duration="@android:integer/config_mediumAnimTime"/>
-    <!--
+            android:duration="@android:integer/config_shortAnimTime"/>
     <scale android:fromXScale="100%" android:toXScale="100%p"
             android:fromYScale="100%" android:toYScale="100%p"
             android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
+            android:interpolator="@interpolator/accelerate_decelerate"
             android:duration="@android:integer/config_mediumAnimTime" />
-    -->
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:interpolator="@interpolator/decelerate_quint"
+            android:interpolator="@interpolator/accelerate_decelerate"
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_mediumAnimTime" />
+            android:duration="@android:integer/config_shortAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_finish_frame.xml b/core/res/res/anim/screen_rotate_finish_frame.xml
new file mode 100644
index 0000000..06dfc5e
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_finish_frame.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <scale android:fromXScale="1.0" android:toXScale="1.1111111111111"
+            android:fromYScale="1.0" android:toYScale="1.1111111111111"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/accelerate_decelerate"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_shortAnimTime"/>
+    <scale android:fromXScale="100%" android:toXScale="100%p"
+            android:fromYScale="100%" android:toYScale="100%p"
+            android:pivotX="50%" android:pivotY="50%"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:interpolator="@interpolator/accelerate_decelerate"
+            android:duration="@android:integer/config_shortAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_frame.xml b/core/res/res/anim/screen_rotate_minus_90_frame.xml
new file mode 100644
index 0000000..874f2e9
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_minus_90_frame.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <rotate android:fromDegrees="0" android:toDegrees="90"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_frame.xml b/core/res/res/anim/screen_rotate_plus_90_frame.xml
new file mode 100644
index 0000000..03c6aa6
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_plus_90_frame.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <rotate android:fromDegrees="0" android:toDegrees="-90"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_start_enter.xml b/core/res/res/anim/screen_rotate_start_enter.xml
index e3f48e4d..162ae8c 100644
--- a/core/res/res/anim/screen_rotate_start_enter.xml
+++ b/core/res/res/anim/screen_rotate_start_enter.xml
@@ -19,8 +19,8 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <scale android:fromXScale="1.0" android:toXScale="0.8"
-            android:fromYScale="1.0" android:toYScale="0.8"
+    <scale android:fromXScale="1.0" android:toXScale="0.9"
+            android:fromYScale="1.0" android:toYScale="0.9"
             android:pivotX="50%" android:pivotY="50%"
             android:interpolator="@interpolator/decelerate_quint"
             android:fillEnabled="true"
diff --git a/core/res/res/anim/screen_rotate_start_exit.xml b/core/res/res/anim/screen_rotate_start_exit.xml
index e3f48e4d..162ae8c 100644
--- a/core/res/res/anim/screen_rotate_start_exit.xml
+++ b/core/res/res/anim/screen_rotate_start_exit.xml
@@ -19,8 +19,8 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <scale android:fromXScale="1.0" android:toXScale="0.8"
-            android:fromYScale="1.0" android:toYScale="0.8"
+    <scale android:fromXScale="1.0" android:toXScale="0.9"
+            android:fromYScale="1.0" android:toYScale="0.9"
             android:pivotX="50%" android:pivotY="50%"
             android:interpolator="@interpolator/decelerate_quint"
             android:fillEnabled="true"
diff --git a/core/res/res/anim/screen_rotate_start_frame.xml b/core/res/res/anim/screen_rotate_start_frame.xml
new file mode 100644
index 0000000..162ae8c
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_start_frame.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:shareInterpolator="false">
+    <scale android:fromXScale="1.0" android:toXScale="0.9"
+            android:fromYScale="1.0" android:toYScale="0.9"
+            android:pivotX="50%" android:pivotY="50%"
+            android:interpolator="@interpolator/decelerate_quint"
+            android:fillEnabled="true"
+            android:fillBefore="true" android:fillAfter="true"
+            android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2c80fb7..722559f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1281,16 +1281,22 @@
   <!-- From services -->
   <java-symbol type="anim" name="screen_rotate_0_enter" />
   <java-symbol type="anim" name="screen_rotate_0_exit" />
+  <java-symbol type="anim" name="screen_rotate_0_frame" />
   <java-symbol type="anim" name="screen_rotate_180_enter" />
   <java-symbol type="anim" name="screen_rotate_180_exit" />
+  <java-symbol type="anim" name="screen_rotate_180_frame" />
   <java-symbol type="anim" name="screen_rotate_finish_enter" />
   <java-symbol type="anim" name="screen_rotate_finish_exit" />
+  <java-symbol type="anim" name="screen_rotate_finish_frame" />
   <java-symbol type="anim" name="screen_rotate_minus_90_enter" />
   <java-symbol type="anim" name="screen_rotate_minus_90_exit" />
+  <java-symbol type="anim" name="screen_rotate_minus_90_frame" />
   <java-symbol type="anim" name="screen_rotate_plus_90_enter" />
   <java-symbol type="anim" name="screen_rotate_plus_90_exit" />
+  <java-symbol type="anim" name="screen_rotate_plus_90_frame" />
   <java-symbol type="anim" name="screen_rotate_start_enter" />
   <java-symbol type="anim" name="screen_rotate_start_exit" />
+  <java-symbol type="anim" name="screen_rotate_start_frame" />
   <java-symbol type="anim" name="window_move_from_decor" />
   <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
index 10e294b..26289c9 100644
--- a/services/java/com/android/server/wm/BlackFrame.java
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import java.io.PrintWriter;
+
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -72,14 +74,31 @@
         }
     }
 
+    final Rect mOuterRect;
+    final Rect mInnerRect;
     final Matrix mTmpMatrix = new Matrix();
     final float[] mTmpFloats = new float[9];
     final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
 
+    public void printTo(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("Outer: "); mOuterRect.printShortString(pw);
+                pw.print(" / Inner: "); mInnerRect.printShortString(pw);
+                pw.println();
+        for (int i=0; i<mBlackSurfaces.length; i++) {
+            BlackSurface bs = mBlackSurfaces[i];
+            pw.print(prefix); pw.print("#"); pw.print(i);
+                    pw.print(": "); pw.print(bs.surface);
+                    pw.print(" left="); pw.print(bs.left);
+                    pw.print(" top="); pw.println(bs.top);
+        }
+    }
+
     public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
             int layer) throws Surface.OutOfResourcesException {
         boolean success = false;
 
+        mOuterRect = new Rect(outer);
+        mInnerRect = new Rect(inner);
         try {
             if (outer.top < inner.top) {
                 mBlackSurfaces[0] = new BlackSurface(session, layer,
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 1335a44..0554306 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -59,6 +59,8 @@
     final Transformation mStartExitTransformation = new Transformation();
     Animation mStartEnterAnimation;
     final Transformation mStartEnterTransformation = new Transformation();
+    Animation mStartFrameAnimation;
+    final Transformation mStartFrameTransformation = new Transformation();
 
     // The finishing animation for the exiting and entering elements.  This
     // animation needs to undo the transformation of the starting animation.
@@ -68,6 +70,8 @@
     final Transformation mFinishExitTransformation = new Transformation();
     Animation mFinishEnterAnimation;
     final Transformation mFinishEnterTransformation = new Transformation();
+    Animation mFinishFrameAnimation;
+    final Transformation mFinishFrameTransformation = new Transformation();
 
     // The current active animation to move from the old to the new rotated
     // state.  Which animation is run here will depend on the old and new
@@ -76,6 +80,8 @@
     final Transformation mRotateExitTransformation = new Transformation();
     Animation mRotateEnterAnimation;
     final Transformation mRotateEnterTransformation = new Transformation();
+    Animation mRotateFrameAnimation;
+    final Transformation mRotateFrameTransformation = new Transformation();
 
     // A previously running rotate animation.  This will be used if we need
     // to switch to a new rotation before finishing the previous one.
@@ -83,32 +89,42 @@
     final Transformation mLastRotateExitTransformation = new Transformation();
     Animation mLastRotateEnterAnimation;
     final Transformation mLastRotateEnterTransformation = new Transformation();
+    Animation mLastRotateFrameAnimation;
+    final Transformation mLastRotateFrameTransformation = new Transformation();
 
     // Complete transformations being applied.
     final Transformation mExitTransformation = new Transformation();
     final Transformation mEnterTransformation = new Transformation();
+    final Transformation mFrameTransformation = new Transformation();
 
     boolean mStarted;
     boolean mAnimRunning;
     boolean mFinishAnimReady;
     long mFinishAnimStartTime;
 
+    final Matrix mFrameInitialMatrix = new Matrix();
     final Matrix mSnapshotInitialMatrix = new Matrix();
     final Matrix mSnapshotFinalMatrix = new Matrix();
     final Matrix mTmpMatrix = new Matrix();
     final float[] mTmpFloats = new float[9];
     private boolean mMoreRotateEnter;
     private boolean mMoreRotateExit;
+    private boolean mMoreRotateFrame;
     private boolean mMoreFinishEnter;
     private boolean mMoreFinishExit;
+    private boolean mMoreFinishFrame;
     private boolean mMoreStartEnter;
     private boolean mMoreStartExit;
+    private boolean mMoreStartFrame;
 
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
                 pw.print(" mWidth="); pw.print(mWidth);
                 pw.print(" mHeight="); pw.println(mHeight);
         pw.print(prefix); pw.print("mBlackFrame="); pw.println(mBlackFrame);
+        if (mBlackFrame != null) {
+            mBlackFrame.printTo(prefix + "  ", pw);
+        }
         pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation);
                 pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation);
                 pw.print(" mCurRotation="); pw.println(mCurRotation);
@@ -123,21 +139,29 @@
                 pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation);
                 pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mStartFrameAnimation="); pw.print(mStartFrameAnimation);
+                pw.print(" "); mStartFrameTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation);
                 pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation);
                 pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFinishFrameAnimation="); pw.print(mFinishFrameAnimation);
+                pw.print(" "); mFinishFrameTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
                 pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
                 pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
-        pw.print(prefix); pw.print("mLastRotateExitAnimation=");
-                pw.print(mLastRotateExitAnimation);
-                pw.print(" "); mLastRotateExitTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mRotateFrameAnimation="); pw.print(mRotateFrameAnimation);
+                pw.print(" "); mRotateFrameTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mExitTransformation=");
                 mExitTransformation.printShortString(pw); pw.println();
         pw.print(prefix); pw.print("mEnterTransformation=");
                 mEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFrameTransformation=");
+                mEnterTransformation.printShortString(pw); pw.println();
+        pw.print(prefix); pw.print("mFrameInitialMatrix=");
+                mFrameInitialMatrix.printShortString(pw);
+                pw.println();
         pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
                 mSnapshotInitialMatrix.printShortString(pw);
                 pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
@@ -178,7 +202,7 @@
                     mSurface = null;
                     return;
                 }
-                mSurface.setLayer(FREEZE_LAYER + 1);
+                mSurface.setLayer(FREEZE_LAYER);
                 mSurface.show();
             } catch (Surface.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate freeze surface", e);
@@ -299,10 +323,14 @@
                     com.android.internal.R.anim.screen_rotate_start_exit);
             mStartEnterAnimation = AnimationUtils.loadAnimation(mContext,
                     com.android.internal.R.anim.screen_rotate_start_enter);
+            mStartFrameAnimation = AnimationUtils.loadAnimation(mContext,
+                    com.android.internal.R.anim.screen_rotate_start_frame);
             mFinishExitAnimation = AnimationUtils.loadAnimation(mContext,
                     com.android.internal.R.anim.screen_rotate_finish_exit);
             mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext,
                     com.android.internal.R.anim.screen_rotate_finish_enter);
+            mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext,
+                    com.android.internal.R.anim.screen_rotate_finish_frame);
         }
 
         if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth="
@@ -315,24 +343,32 @@
                         com.android.internal.R.anim.screen_rotate_0_exit);
                 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_0_enter);
+                mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
+                        com.android.internal.R.anim.screen_rotate_0_frame);
                 break;
             case Surface.ROTATION_90:
                 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_plus_90_exit);
                 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_plus_90_enter);
+                mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
+                        com.android.internal.R.anim.screen_rotate_plus_90_frame);
                 break;
             case Surface.ROTATION_180:
                 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_180_exit);
                 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_180_enter);
+                mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
+                        com.android.internal.R.anim.screen_rotate_180_frame);
                 break;
             case Surface.ROTATION_270:
                 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_minus_90_exit);
                 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                         com.android.internal.R.anim.screen_rotate_minus_90_enter);
+                mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
+                        com.android.internal.R.anim.screen_rotate_minus_90_frame);
                 break;
         }
 
@@ -346,13 +382,18 @@
                     mOriginalWidth, mOriginalHeight);
             mStartExitAnimation.initialize(finalWidth, finalHeight,
                     mOriginalWidth, mOriginalHeight);
+            mStartFrameAnimation.initialize(finalWidth, finalHeight,
+                    mOriginalWidth, mOriginalHeight);
             mFinishEnterAnimation.initialize(finalWidth, finalHeight,
                     mOriginalWidth, mOriginalHeight);
             mFinishExitAnimation.initialize(finalWidth, finalHeight,
                     mOriginalWidth, mOriginalHeight);
+            mFinishFrameAnimation.initialize(finalWidth, finalHeight,
+                    mOriginalWidth, mOriginalHeight);
         }
         mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
         mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+        mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
         mAnimRunning = false;
         mFinishAnimReady = false;
         mFinishAnimStartTime = -1;
@@ -362,15 +403,21 @@
             mStartExitAnimation.scaleCurrentDuration(animationScale);
             mStartEnterAnimation.restrictDuration(maxAnimationDuration);
             mStartEnterAnimation.scaleCurrentDuration(animationScale);
+            mStartFrameAnimation.restrictDuration(maxAnimationDuration);
+            mStartFrameAnimation.scaleCurrentDuration(animationScale);
             mFinishExitAnimation.restrictDuration(maxAnimationDuration);
             mFinishExitAnimation.scaleCurrentDuration(animationScale);
             mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
             mFinishEnterAnimation.scaleCurrentDuration(animationScale);
+            mFinishFrameAnimation.restrictDuration(maxAnimationDuration);
+            mFinishFrameAnimation.scaleCurrentDuration(animationScale);
         }
         mRotateExitAnimation.restrictDuration(maxAnimationDuration);
         mRotateExitAnimation.scaleCurrentDuration(animationScale);
         mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
         mRotateEnterAnimation.scaleCurrentDuration(animationScale);
+        mRotateFrameAnimation.restrictDuration(maxAnimationDuration);
+        mRotateFrameAnimation.scaleCurrentDuration(animationScale);
 
         if (mBlackFrame == null) {
             if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
@@ -378,10 +425,20 @@
                     ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
             Surface.openTransaction();
 
+            // Compute the transformation matrix that must be applied
+            // the the black frame to make it stay in the initial position
+            // before the new screen rotation.  This is different than the
+            // snapshot transformation because the snapshot is always based
+            // of the native orientation of the screen, not the orientation
+            // we were last in.
+            createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
+
             try {
-                Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2);
-                Rect inner = new Rect(0, 0, finalWidth, finalHeight);
-                mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
+                Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
+                        mOriginalWidth*2, mOriginalHeight*2);
+                Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
+                mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 1);
+                mBlackFrame.setMatrix(mFrameInitialMatrix);
             } catch (Surface.OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             } finally {
@@ -438,13 +495,21 @@
             mStartEnterAnimation.cancel();
             mStartEnterAnimation = null;
         }
+        if (mStartFrameAnimation != null) {
+            mStartFrameAnimation.cancel();
+            mStartFrameAnimation = null;
+        }
         if (mFinishExitAnimation != null) {
             mFinishExitAnimation.cancel();
             mFinishExitAnimation = null;
         }
-        if (mStartEnterAnimation != null) {
-            mStartEnterAnimation.cancel();
-            mStartEnterAnimation = null;
+        if (mFinishEnterAnimation != null) {
+            mFinishEnterAnimation.cancel();
+            mFinishEnterAnimation = null;
+        }
+        if (mFinishFrameAnimation != null) {
+            mFinishFrameAnimation.cancel();
+            mFinishFrameAnimation = null;
         }
         if (mRotateExitAnimation != null) {
             mRotateExitAnimation.cancel();
@@ -454,12 +519,19 @@
             mRotateEnterAnimation.cancel();
             mRotateEnterAnimation = null;
         }
+        if (mRotateFrameAnimation != null) {
+            mRotateFrameAnimation.cancel();
+            mRotateFrameAnimation = null;
+        }
     }
 
     public boolean isAnimating() {
         return mStartEnterAnimation != null || mStartExitAnimation != null
-                && mFinishEnterAnimation != null || mFinishExitAnimation != null
-                && mRotateEnterAnimation != null || mRotateExitAnimation != null;
+                || mStartFrameAnimation != null
+                || mFinishEnterAnimation != null || mFinishExitAnimation != null
+                || mFinishFrameAnimation != null
+                || mRotateEnterAnimation != null || mRotateExitAnimation != null
+                || mRotateFrameAnimation != null;
     }
 
     @Override
@@ -497,6 +569,18 @@
             }
         }
 
+        mMoreStartFrame = false;
+        if (mStartFrameAnimation != null) {
+            mStartFrameTransformation.clear();
+            mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
+            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
+            if (!mMoreStartFrame) {
+                if (DEBUG_STATE) Slog.v(TAG, "Start frame animation done!");
+                mStartFrameAnimation.cancel();
+                mStartFrameAnimation = null;
+            }
+        }
+
         long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
         if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
 
@@ -528,18 +612,31 @@
             }
         }
 
+        mFinishFrameTransformation.clear();
+        mMoreFinishFrame = false;
+        if (mFinishFrameAnimation != null) {
+            mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
+            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
+            if (!mMoreStartFrame && !mMoreFinishFrame) {
+                if (DEBUG_STATE) Slog.v(TAG, "Finish frame animation done, clearing start/finish anims!");
+                mStartFrameTransformation.clear();
+                mFinishFrameAnimation.cancel();
+                mFinishFrameAnimation = null;
+                mFinishFrameTransformation.clear();
+            }
+        }
+
         mRotateExitTransformation.clear();
         mMoreRotateExit = false;
         if (mRotateExitAnimation != null) {
             mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
             if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
-        }
-
-        if (!mMoreFinishExit && !mMoreRotateExit) {
-            if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!");
-            mRotateExitAnimation.cancel();
-            mRotateExitAnimation = null;
-            mRotateExitTransformation.clear();
+            if (!mMoreFinishExit && !mMoreRotateExit) {
+                if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!");
+                mRotateExitAnimation.cancel();
+                mRotateExitAnimation = null;
+                mRotateExitTransformation.clear();
+            }
         }
 
         mRotateEnterTransformation.clear();
@@ -547,13 +644,25 @@
         if (mRotateEnterAnimation != null) {
             mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
             if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
+            if (!mMoreFinishEnter && !mMoreRotateEnter) {
+                if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!");
+                mRotateEnterAnimation.cancel();
+                mRotateEnterAnimation = null;
+                mRotateEnterTransformation.clear();
+            }
         }
 
-        if (!mMoreFinishEnter && !mMoreRotateEnter) {
-            if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!");
-            mRotateEnterAnimation.cancel();
-            mRotateEnterAnimation = null;
-            mRotateEnterTransformation.clear();
+        mRotateFrameTransformation.clear();
+        mMoreRotateFrame = false;
+        if (mRotateFrameAnimation != null) {
+            mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
+            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
+            if (!mMoreFinishFrame && !mMoreRotateFrame) {
+                if (DEBUG_STATE) Slog.v(TAG, "Rotate frame animation done!");
+                mRotateFrameAnimation.cancel();
+                mRotateFrameAnimation = null;
+                mRotateFrameTransformation.clear();
+            }
         }
 
         mExitTransformation.set(mRotateExitTransformation);
@@ -564,11 +673,22 @@
         mEnterTransformation.compose(mStartEnterTransformation);
         mEnterTransformation.compose(mFinishEnterTransformation);
 
+        //mFrameTransformation.set(mRotateExitTransformation);
+        //mFrameTransformation.compose(mStartExitTransformation);
+        //mFrameTransformation.compose(mFinishExitTransformation);
+        mFrameTransformation.set(mRotateFrameTransformation);
+        mFrameTransformation.compose(mStartFrameTransformation);
+        mFrameTransformation.compose(mFinishFrameTransformation);
+        mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix);
+
         if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
         if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
+        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
 
-        final boolean more = mMoreStartEnter || mMoreStartExit || mMoreFinishEnter
-                || mMoreFinishExit || mMoreRotateEnter || mMoreRotateExit || !mFinishAnimReady;
+        final boolean more = mMoreStartEnter || mMoreStartExit || mMoreStartFrame
+                || mMoreFinishEnter || mMoreFinishExit || mMoreFinishFrame
+                || mMoreRotateEnter || mMoreRotateExit || mMoreRotateFrame
+                || !mFinishAnimReady;
 
         mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
 
@@ -585,14 +705,14 @@
             }
         }
 
-        if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
+        if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) {
             if (mBlackFrame != null) {
-                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame");
+                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame");
                 mBlackFrame.hide();
             }
         } else {
             if (mBlackFrame != null) {
-                mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
+                mBlackFrame.setMatrix(mFrameTransformation.getMatrix());
             }
         }
 
@@ -613,18 +733,27 @@
             if (mStartExitAnimation != null) {
                 mStartExitAnimation.setStartTime(now);
             }
+            if (mStartFrameAnimation != null) {
+                mStartFrameAnimation.setStartTime(now);
+            }
             if (mFinishEnterAnimation != null) {
                 mFinishEnterAnimation.setStartTime(0);
             }
             if (mFinishExitAnimation != null) {
                 mFinishExitAnimation.setStartTime(0);
             }
+            if (mFinishFrameAnimation != null) {
+                mFinishFrameAnimation.setStartTime(0);
+            }
             if (mRotateEnterAnimation != null) {
                 mRotateEnterAnimation.setStartTime(now);
             }
             if (mRotateExitAnimation != null) {
                 mRotateExitAnimation.setStartTime(now);
             }
+            if (mRotateFrameAnimation != null) {
+                mRotateFrameAnimation.setStartTime(now);
+            }
             mAnimRunning = true;
         }