Merge "More work on rotation animation."
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 39c6a18..2d8a394 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1282,16 +1282,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 932e456..7ac67b6 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());
             }
         }
 
@@ -614,18 +734,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;
         }