Fix issue #3400119: API to specify a black background behind a window transition
There is now an API, which is used for task switching.
Also improved how we handle rotation animation when we can't take a
screen shot, to cleanly revert to the old freeze behavior. This removes
the need to special case the emulator.
Change-Id: I7227432a2309370437ec6ac78db02c6f1e7eedd5
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 e3218c8..0920d07 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);
}
@@ -8588,6 +8632,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);
@@ -8596,7 +8644,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 ");
}