Merge "Fix issue #3400119: API to specify a black background behind a window transition"
diff --git a/api/current.xml b/api/current.xml
index f98edab..9993475 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -233470,6 +233470,17 @@
  visibility="protected"
 >
 </method>
+<method name="getBackgroundColor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getDetachWallpaper"
  return="boolean"
  abstract="false"
@@ -233755,6 +233766,19 @@
 <parameter name="listener" type="android.view.animation.Animation.AnimationListener">
 </parameter>
 </method>
+<method name="setBackgroundColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bg" type="int">
+</parameter>
+</method>
 <method name="setDetachWallpaper"
  return="void"
  abstract="false"
@@ -266669,7 +266693,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
 </parameter>
 </method>
 </interface>
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 13d0ec1..87c759c 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -181,6 +181,11 @@
     private int mZAdjustment;
 
     /**
+     * Desired background color behind animation.
+     */
+    private int mBackgroundColor;
+
+    /**
      * scalefactor to apply to pivot points, etc. during animation. Subclasses retrieve the
      * value via getScaleFactor().
      */
@@ -236,6 +241,8 @@
 
         setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
         
+        setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
+
         setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
         
         ensureInterpolator();
@@ -568,6 +575,16 @@
     }
     
     /**
+     * Set background behind animation.
+     *
+     * @param bg The background color.  If 0, no background.  Currently must
+     * be black, with any desired alpha level.
+     */
+    public void setBackgroundColor(int bg) {
+        mBackgroundColor = bg;
+    }
+
+    /**
      * The scale factor is set by the call to <code>getTransformation</code>. Overrides of 
      * {@link #getTransformation(long, Transformation, float)} will get this value
      * directly. Overrides of {@link #applyTransformation(float, Transformation)} can
@@ -690,6 +707,13 @@
     }
 
     /**
+     * Returns the background color behind the animation.
+     */
+    public int getBackgroundColor() {
+        return mBackgroundColor;
+    }
+
+    /**
      * Return value of {@link #setDetachWallpaper(boolean)}.
      * @attr ref android.R.styleable#Animation_detachWallpaper
      */
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index b479543..66d982f 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -18,7 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:detachWallpaper="true" android:shareInterpolator="false">
+        android:background="#ff000000" android:shareInterpolator="false">
     <scale 	android:fromXScale="1.0" android:toXScale="1.0"
             android:fromYScale="0.95" android:toYScale="1.0"
             android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index e561e97..312946b 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -18,7 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:detachWallpaper="true" android:shareInterpolator="false">
+        android:background="#ff000000" android:shareInterpolator="false">
     <scale android:fromXScale="1.0" android:toXScale="1.0"
             android:fromYScale="1.0" android:toYScale="0.0"
             android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index b3b3fd1..3dda797 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -18,7 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:detachWallpaper="true" android:shareInterpolator="false">
+        android:background="#ff000000" android:shareInterpolator="false">
     <scale android:fromXScale="1.0" android:toXScale="1.0"
             android:fromYScale=".9" android:toYScale="1.0"
             android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 763b581..e377c2a 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -18,7 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:detachWallpaper="true" android:shareInterpolator="false">
+        android:background="#ff000000" android:shareInterpolator="false">
     <scale android:fromXScale="1.0" android:toXScale="1.0"
             android:fromYScale="1.0" android:toYScale="0.0"
             android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3b225a4..d3b1062 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3596,6 +3596,10 @@
                  content for the duration of the animation. -->
             <enum name="bottom" value="-1" />
         </attr>
+        <!-- Special background behind animation.  Only for use with window
+             animations.  Can only be a color, and only black.  If 0, the
+             default, there is no background. -->
+        <attr name="background" />
         <!-- Special option for window animations: if this window is on top
              of a wallpaper, don't animate the wallpaper with it. -->
         <attr name="detachWallpaper" format="boolean" />
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 1fcb869..a266d70 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -45,7 +45,7 @@
                     + mDimSurface + ": CREATE");
             try {
                 mDimSurface = new Surface(session, 0,
-                        "DimSurface",
+                        "DimAnimator",
                         -1, 16, 16, PixelFormat.OPAQUE,
                         Surface.FX_SURFACE_DIM);
                 mDimSurface.setAlpha(0.0f);
@@ -84,7 +84,7 @@
      * {@link updateSurface} after all windows are examined.
      */
     void updateParameters(Resources res, WindowState w, long currentTime) {
-        mDimSurface.setLayer(w.mAnimLayer-1);
+        mDimSurface.setLayer(w.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
 
         final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
         if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface
@@ -177,8 +177,11 @@
         return animating;
     }
 
-    public void printTo(PrintWriter pw) {
-        pw.print("  mDimShown="); pw.print(mDimShown);
+    public void printTo(String prefix, PrintWriter pw) {
+        pw.print(prefix);
+        pw.print("mDimSurface="); pw.println(mDimSurface);
+        pw.print(prefix);
+        pw.print("mDimShown="); pw.print(mDimShown);
         pw.print(" current="); pw.print(mDimCurrentAlpha);
         pw.print(" target="); pw.print(mDimTargetAlpha);
         pw.print(" delta="); pw.print(mDimDeltaPerMs);
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
new file mode 100644
index 0000000..084ac6f
--- /dev/null
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+package com.android.server.wm;
+
+import android.graphics.PixelFormat;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.SurfaceSession;
+
+import java.io.PrintWriter;
+
+class DimSurface {
+    Surface mDimSurface;
+    boolean mDimShown = false;
+    int mDimColor = 0;
+    int mLayer = -1;
+    int mLastDimWidth, mLastDimHeight;
+
+    DimSurface(SurfaceSession session) {
+        if (mDimSurface == null) {
+            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
+                    + mDimSurface + ": CREATE");
+            try {
+                mDimSurface = new Surface(session, 0,
+                        "DimSurface",
+                        -1, 16, 16, PixelFormat.OPAQUE,
+                        Surface.FX_SURFACE_DIM);
+                mDimSurface.setAlpha(0.0f);
+            } catch (Exception e) {
+                Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
+            }
+        }
+    }
+
+    /**
+     * Show the dim surface.
+     */
+    void show(int dw, int dh, int layer, int color) {
+        if (!mDimShown) {
+            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
+                    dw + "x" + dh + ")");
+            mDimShown = true;
+            try {
+                mLastDimWidth = dw;
+                mLastDimHeight = dh;
+                mDimSurface.setPosition(0, 0);
+                mDimSurface.setSize(dw, dh);
+                mDimSurface.show();
+            } catch (RuntimeException e) {
+                Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
+            }
+        } else if (mLastDimWidth != dw || mLastDimHeight != dh || mDimColor != color
+                || mLayer != layer) {
+            mLastDimWidth = dw;
+            mLastDimHeight = dh;
+            mLayer = layer;
+            mDimColor = color;
+            mDimSurface.setSize(dw, dh);
+            mDimSurface.setLayer(layer);
+            mDimSurface.setAlpha(((color>>24)&0xff)/255.0f);
+        }
+    }
+
+    void hide() {
+        if (mDimShown) {
+            mDimShown = false;
+            try {
+                mDimSurface.hide();
+            } catch (RuntimeException e) {
+                Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
+            }
+        }
+    }
+
+    public void printTo(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mDimSurface="); pw.println(mDimSurface);
+        pw.print(prefix); pw.print("mDimShown="); pw.print(mDimShown);
+                pw.print(" mLayer="); pw.println(mLayer);
+                pw.print(" mDimColor=0x"); pw.println(Integer.toHexString(mDimColor));
+        pw.print(prefix); pw.print("mLastDimWidth="); pw.print(mLastDimWidth);
+                pw.print(" mLastDimWidth="); pw.println(mLastDimWidth);
+    }
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 4356ce5..fbf1ec3 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -110,18 +110,16 @@
 
         Bitmap screenshot = Surface.screenshot(0, 0);
 
-        if (screenshot != null) {
-            // Screenshot does NOT include rotation!
-            mSnapshotRotation = 0;
-            mWidth = screenshot.getWidth();
-            mHeight = screenshot.getHeight();
-        } else {
-            // Just in case.
-            mSnapshotRotation = display.getRotation();
-            mWidth = mDisplayMetrics.widthPixels;
-            mHeight = mDisplayMetrics.heightPixels;
+        if (screenshot == null) {
+            // Device is not capable of screenshots...  we can't do an animation.
+            return;
         }
 
+        // Screenshot does NOT include rotation!
+        mSnapshotRotation = 0;
+        mWidth = screenshot.getWidth();
+        mHeight = screenshot.getHeight();
+
         mOriginalRotation = display.getRotation();
         mOriginalWidth = mDisplayMetrics.widthPixels;
         mOriginalHeight = mDisplayMetrics.heightPixels;
@@ -150,23 +148,19 @@
                     c = mSurface.lockCanvas(dirty);
                 } catch (IllegalArgumentException e) {
                     Slog.w(TAG, "Unable to lock surface", e);
-                    return;
                 } catch (Surface.OutOfResourcesException e) {
                     Slog.w(TAG, "Unable to lock surface", e);
-                    return;
                 }
                 if (c == null) {
-                    Slog.w(TAG, "Null surface");
+                    Slog.w(TAG, "Null surface canvas");
+                    mSurface.destroy();
+                    mSurface = null;
                     return;
                 }
         
-                if (screenshot != null) {
-                    Paint paint = new Paint(0);
-                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-                    c.drawBitmap(screenshot, 0, 0, paint);
-                } else {
-                    c.drawColor(Color.BLACK, PorterDuff.Mode.SRC);
-                }
+                Paint paint = new Paint(0);
+                paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+                c.drawBitmap(screenshot, 0, 0, paint);
 
                 mSurface.unlockCanvasAndPost(c);
             }
@@ -177,12 +171,14 @@
                         "<<< CLOSE TRANSACTION ScreenRotationAnimation");
             }
     
-            if (screenshot != null) {
-                screenshot.recycle();
-            }
+            screenshot.recycle();
         }
     }
 
+    boolean hasScreenshot() {
+        return mSurface != null;
+    }
+
     static int deltaRotation(int oldRotation, int newRotation) {
         int delta = newRotation - oldRotation;
         if (delta < 0) delta += 4;
@@ -250,17 +246,14 @@
      */
     public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
             float animationScale) {
-        // Figure out how the screen has moved from the original rotation.
-        int delta = deltaRotation(mCurRotation, mOriginalRotation);
-        if (false && delta == 0) {
-            // Nothing changed, just remove the snapshot.
-            if (mSurface != null) {
-                mSurface.destroy();
-                mSurface = null;
-            }
+        if (mSurface == null) {
+            // Can't do animation.
             return false;
         }
 
+        // Figure out how the screen has moved from the original rotation.
+        int delta = deltaRotation(mCurRotation, mOriginalRotation);
+
         switch (delta) {
             case Surface.ROTATION_0:
                 mExitAnimation = AnimationUtils.loadAnimation(mContext,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 15269dc..b5d84e8 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -180,6 +180,16 @@
      */
     static final int WINDOW_LAYER_MULTIPLIER = 5;
 
+    /**
+     * Dim surface layer is immediately below target window.
+     */
+    static final int LAYER_OFFSET_DIM = 1;
+
+    /**
+     * Blur surface layer is immediately below dim layer.
+     */
+    static final int LAYER_OFFSET_BLUR = 2;
+
     /** The maximum length we will accept for a loaded animation duration:
      * this is 10 seconds.
      */
@@ -276,8 +286,6 @@
 
     final IBatteryStats mBatteryStats;
 
-    private static final boolean mInEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
-
     /**
      * All currently active sessions with clients.
      */
@@ -468,6 +476,7 @@
     // visible behind it in case it animates in a way that would allow it to be
     // seen.
     WindowState mWindowDetachedWallpaper = null;
+    DimSurface mWindowAnimationBackgroundSurface = null;
     int mWallpaperAnimLayerAdjustment;
     float mLastWallpaperX = -1;
     float mLastWallpaperY = -1;
@@ -4940,7 +4949,8 @@
             if (mDisplayEnabled) {
                 // NOTE: We disable the rotation in the emulator because
                 //       it doesn't support hardware OpenGL emulation yet.
-                if (CUSTOM_SCREEN_ROTATION && !mInEmulator) {
+                if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
+                        && mScreenRotationAnimation.hasScreenshot()) {
                     Surface.freezeDisplay(0);
                     if (!inTransaction) {
                         if (SHOW_TRANSACTIONS) Slog.i(TAG,
@@ -6802,6 +6812,8 @@
                 boolean wallpaperMayChange = false;
                 boolean forceHiding = false;
                 WindowState windowDetachedWallpaper = null;
+                WindowState windowAnimationBackground = null;
+                int windowAnimationBackgroundColor = 0;
 
                 mPolicy.beginAnimationLw(dw, dh);
 
@@ -6851,8 +6863,15 @@
                         // an animating window and take care of a request to run
                         // a detached wallpaper animation.
                         if (nowAnimating) {
-                            if (w.mAnimation != null && w.mAnimation.getDetachWallpaper()) {
-                                windowDetachedWallpaper = w;
+                            if (w.mAnimation != null) {
+                                if (w.mAnimation.getDetachWallpaper()) {
+                                    windowDetachedWallpaper = w;
+                                }
+                                if (w.mAnimation.getBackgroundColor() != 0) {
+                                    windowAnimationBackground = w;
+                                    windowAnimationBackgroundColor =
+                                            w.mAnimation.getBackgroundColor();
+                                }
                             }
                             animating = true;
                         }
@@ -6860,9 +6879,15 @@
                         // If this window's app token is running a detached wallpaper
                         // animation, make a note so we can ensure the wallpaper is
                         // displayed behind it.
-                        if (w.mAppToken != null && w.mAppToken.animation != null
-                                && w.mAppToken.animation.getDetachWallpaper()) {
-                            windowDetachedWallpaper = w;
+                        if (w.mAppToken != null && w.mAppToken.animation != null) {
+                            if (w.mAppToken.animation.getDetachWallpaper()) {
+                                windowDetachedWallpaper = w;
+                            }
+                            if (w.mAppToken.animation.getBackgroundColor() != 0) {
+                                windowAnimationBackground = w;
+                                windowAnimationBackgroundColor =
+                                        w.mAppToken.animation.getBackgroundColor();
+                            }
                         }
 
                         if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
@@ -7301,6 +7326,17 @@
                     wallpaperMayChange = true;
                 }
 
+                if (windowAnimationBackgroundColor != 0) {
+                    if (mWindowAnimationBackgroundSurface == null) {
+                        mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
+                    }
+                    mWindowAnimationBackgroundSurface.show(dw, dh,
+                            windowAnimationBackground.mAnimLayer - LAYER_OFFSET_DIM,
+                            windowAnimationBackgroundColor);
+                } else if (mWindowAnimationBackgroundSurface != null) {
+                    mWindowAnimationBackgroundSurface.hide();
+                }
+
                 if (wallpaperMayChange) {
                     if (DEBUG_WALLPAPER) Slog.v(TAG,
                             "Wallpaper may change!  Adjusting");
@@ -7730,7 +7766,7 @@
                                             dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
                                     mBlurSurface.setPosition(0, 0);
                                     mBlurSurface.setSize(dw, dh);
-                                    mBlurSurface.setLayer(w.mAnimLayer-2);
+                                    mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
                                     if (!mBlurShown) {
                                         try {
                                             if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
@@ -7779,7 +7815,8 @@
                     // Using the same layer as Dim because they will never be shown at the
                     // same time.  NOTE: we do NOT use mAnimLayer, because we don't
                     // want this surface dragged up in front of stuff that is animating.
-                    mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer - 1);
+                    mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer
+                            - LAYER_OFFSET_DIM);
                     mBackgroundFillerSurface.show();
                 } catch (RuntimeException e) {
                     Slog.e(TAG, "Exception showing filler surface");
@@ -8294,6 +8331,9 @@
                 mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
                         mDisplay, mFxSession, inTransaction);
             }
+            if (!mScreenRotationAnimation.hasScreenshot()) {
+                Surface.freezeDisplay(0);
+            }
         } else {
             Surface.freezeDisplay(0);
         }
@@ -8316,17 +8356,21 @@
 
         boolean updateRotation = false;
         
-        if (CUSTOM_SCREEN_ROTATION) {
-            if (mScreenRotationAnimation != null) {
-                if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
-                        mTransitionAnimationScale)) {
-                    requestAnimationLocked(0);
-                } else {
-                    mScreenRotationAnimation = null;
-                    updateRotation = true;
-                }
+        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
+                && mScreenRotationAnimation.hasScreenshot()) {
+            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
+                    mTransitionAnimationScale)) {
+                requestAnimationLocked(0);
+            } else {
+                mScreenRotationAnimation = null;
+                updateRotation = true;
             }
         } else {
+            if (mScreenRotationAnimation != null) {
+                mScreenRotationAnimation.kill();
+                mScreenRotationAnimation = null;
+            }
+            updateRotation = true;
             Surface.unfreezeDisplay(0);
         }
 
@@ -8589,6 +8633,10 @@
             if (mWindowDetachedWallpaper != null) {
                 pw.print("  mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
             }
+            if (mWindowAnimationBackgroundSurface != null) {
+                pw.println("  mWindowAnimationBackgroundSurface:");
+                mWindowAnimationBackgroundSurface.printTo("    ", pw);
+            }
             pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
             pw.print("  mInTouchMode="); pw.print(mInTouchMode);
                     pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
@@ -8597,7 +8645,8 @@
             pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
                     pw.print(" mBlurShown="); pw.println(mBlurShown);
             if (mDimAnimator != null) {
-                mDimAnimator.printTo(pw);
+                pw.println("  mDimAnimator:");
+                mDimAnimator.printTo("    ", pw);
             } else {
                 pw.println( "  no DimAnimator ");
             }