Move Surface operations out of WindowState.
Migrated the bulk of Surface operations from WindowState to
WindowStateAnimator. There remain a multitude of cross-referencing
between the two classes and most of the other classes in the wm
package.
Change-Id: I4bfdfb84be31341371f3ef311aca8fc6a4966692
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 73573d7..789e74b 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -2,10 +2,21 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.RemoteException;
import android.util.Slog;
+import android.view.Surface;
import android.view.WindowManager;
import android.view.WindowManagerPolicy;
+import android.view.WindowManager.LayoutParams;
import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import com.android.server.wm.WindowManagerService.H;
@@ -13,15 +24,27 @@
import java.io.PrintWriter;
/**
- * @author cmautner@google.com (Craig Mautner)
- *
- */
+ * Keep track of animations and surface operations for a single WindowState.
+ **/
class WindowStateAnimator {
+ static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY;
+ static final boolean DEBUG_ANIM = WindowManagerService.DEBUG_ANIM;
+ static final boolean DEBUG_LAYERS = WindowManagerService.DEBUG_LAYERS;
+ static final boolean DEBUG_STARTING_WINDOW = WindowManagerService.DEBUG_STARTING_WINDOW;
+ static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS;
+ static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
+ static final boolean SHOW_SURFACE_ALLOC = WindowManagerService.SHOW_SURFACE_ALLOC;
+ static final boolean localLOGV = WindowManagerService.localLOGV;
+
+ static final String TAG = "WindowStateAnimator";
final WindowManagerService mService;
final WindowState mWin;
final WindowState mAttachedWindow;
final WindowAnimator mAnimator;
+ final Session mSession;
+ final WindowManagerPolicy mPolicy;
+ final Context mContext;
// Currently running animation.
boolean mAnimating;
@@ -32,6 +55,48 @@
boolean mHasLocalTransformation;
final Transformation mTransformation = new Transformation();
boolean mWasAnimating; // Were we animating going into the most recent animation step?
+ int mAnimLayer;
+ int mLastLayer;
+
+ Surface mSurface;
+ Surface mPendingDestroySurface;
+ boolean mReportDestroySurface;
+ boolean mSurfacePendingDestroy;
+
+ /**
+ * Set when we have changed the size of the surface, to know that
+ * we must tell them application to resize (and thus redraw itself).
+ */
+ boolean mSurfaceResized;
+
+ /**
+ * Set if the client has asked that the destroy of its surface be delayed
+ * until it explicitly says it is okay.
+ */
+ boolean mSurfaceDestroyDeferred;
+
+ float mShownAlpha = 1;
+ float mAlpha = 1;
+ float mLastAlpha = 1;
+
+ // Used to save animation distances between the time they are calculated and when they are
+ // used.
+ int mAnimDw;
+ int mAnimDh;
+ float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
+ float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
+
+ boolean mHaveMatrix;
+
+ // For debugging, this is the last information given to the surface flinger.
+ boolean mSurfaceShown;
+ float mSurfaceX, mSurfaceY, mSurfaceW, mSurfaceH;
+ int mSurfaceLayer;
+ float mSurfaceAlpha;
+
+ // Set to true if, when the window gets displayed, it should perform
+ // an enter animation.
+ boolean mEnterAnimationPending;
public WindowStateAnimator(final WindowManagerService service, final WindowState win,
final WindowState attachedWindow) {
@@ -39,11 +104,14 @@
mWin = win;
mAttachedWindow = attachedWindow;
mAnimator = mService.mAnimator;
+ mSession = win.mSession;
+ mPolicy = mService.mPolicy;
+ mContext = mService.mContext;
}
public void setAnimation(Animation anim) {
- if (WindowManagerService.localLOGV) Slog.v(
- WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
+ if (localLOGV) Slog.v(
+ TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
mLocalAnimating = false;
mAnimation = anim;
@@ -80,14 +148,12 @@
return mAnimation != null;
}
- // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked()
- // for avoiding the code duplication.
void cancelExitAnimationForNextAnimationLocked() {
if (!mWin.mExiting) return;
if (mAnimation != null) {
mAnimation.cancel();
mAnimation = null;
- mWin.destroySurfaceLocked();
+ destroySurfaceLocked();
}
mWin.mExiting = false;
}
@@ -98,8 +164,8 @@
}
mTransformation.clear();
final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
- if (WindowManagerService.DEBUG_ANIM) Slog.v(
- WindowManagerService.TAG, "Stepped animation in " + this +
+ if (DEBUG_ANIM) Slog.v(
+ TAG, "Stepped animation in " + this +
": more=" + more + ", xform=" + mTransformation);
return more;
}
@@ -117,14 +183,14 @@
mHasTransformation = true;
mHasLocalTransformation = true;
if (!mLocalAnimating) {
- if (WindowManagerService.DEBUG_ANIM) Slog.v(
- WindowManagerService.TAG, "Starting animation in " + this +
+ if (DEBUG_ANIM) Slog.v(
+ TAG, "Starting animation in " + this +
" @ " + currentTime + ": ww=" + mWin.mFrame.width() +
" wh=" + mWin.mFrame.height() +
- " dw=" + mWin.mAnimDw + " dh=" + mWin.mAnimDh +
+ " dw=" + mAnimDw + " dh=" + mAnimDh +
" scale=" + mService.mWindowAnimationScale);
- mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mWin.mAnimDw,
- mWin.mAnimDh);
+ mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(),
+ mAnimDw, mAnimDh);
mAnimation.setStartTime(currentTime);
mLocalAnimating = true;
mAnimating = true;
@@ -134,8 +200,8 @@
return true;
}
}
- if (WindowManagerService.DEBUG_ANIM) Slog.v(
- WindowManagerService.TAG, "Finished animation in " + this +
+ if (DEBUG_ANIM) Slog.v(
+ TAG, "Finished animation in " + this +
" @ " + currentTime);
//WindowManagerService.this.dump();
}
@@ -173,8 +239,9 @@
return false;
}
- if (WindowManagerService.DEBUG_ANIM) Slog.v(
- WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
+ // Done animating, clean up.
+ if (DEBUG_ANIM) Slog.v(
+ TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
+ ", reportedVisible="
+ (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
@@ -187,19 +254,19 @@
if (mAnimator.mWindowDetachedWallpaper == mWin) {
mAnimator.mWindowDetachedWallpaper = null;
}
- mWin.mAnimLayer = mWin.mLayer;
+ mAnimLayer = mWin.mLayer;
if (mWin.mIsImWindow) {
- mWin.mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
+ mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
} else if (mWin.mIsWallpaper) {
- mWin.mAnimLayer += mService.mWallpaperAnimLayerAdjustment;
+ mAnimLayer += mService.mWallpaperAnimLayerAdjustment;
}
- if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this
- + " anim layer: " + mWin.mAnimLayer);
+ if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this
+ + " anim layer: " + mAnimLayer);
mHasTransformation = false;
mHasLocalTransformation = false;
if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) {
if (WindowState.DEBUG_VISIBILITY) {
- Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": "
+ Slog.v(TAG, "Policy visibility changing after anim in " + this + ": "
+ mWin.mPolicyVisibilityAfterAnim);
}
mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
@@ -220,7 +287,7 @@
&& mWin.mAppToken != null
&& mWin.mAppToken.firstWindowDrawn
&& mWin.mAppToken.startingData != null) {
- if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting "
+ if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Finish starting "
+ mWin.mToken + ": first real window done animating");
mService.mFinishedStarting.add(mWin.mAppToken);
mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
@@ -239,7 +306,7 @@
void finishExit() {
if (WindowManagerService.DEBUG_ANIM) Slog.v(
- WindowManagerService.TAG, "finishExit in " + this
+ TAG, "finishExit in " + this
+ ": exiting=" + mWin.mExiting
+ " remove=" + mWin.mRemoveOnExit
+ " windowAnimating=" + isWindowAnimating());
@@ -258,18 +325,18 @@
}
if (WindowManagerService.localLOGV) Slog.v(
- WindowManagerService.TAG, "Exit animation finished in " + this
+ TAG, "Exit animation finished in " + this
+ ": remove=" + mWin.mRemoveOnExit);
- if (mWin.mSurface != null) {
+ if (mSurface != null) {
mService.mDestroySurface.add(mWin);
mWin.mDestroying = true;
if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface(
mWin, "HIDE (finishExit)", null);
- mWin.mSurfaceShown = false;
+ mSurfaceShown = false;
try {
- mWin.mSurface.hide();
+ mSurface.hide();
} catch (RuntimeException e) {
- Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e);
+ Slog.w(TAG, "Error hiding surface in " + this, e);
}
mWin.mLastHidden = true;
}
@@ -280,6 +347,742 @@
}
}
+ Surface createSurfaceLocked() {
+ if (mSurface == null) {
+ mReportDestroySurface = false;
+ mSurfacePendingDestroy = false;
+ if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
+ "createSurface " + this + ": DRAW NOW PENDING");
+ mWin.mDrawPending = true;
+ mWin.mCommitDrawPending = false;
+ mWin.mReadyToShow = false;
+ if (mWin.mAppToken != null) {
+ mWin.mAppToken.allDrawn = false;
+ }
+
+ mService.makeWindowFreezingScreenIfNeededLocked(mWin);
+
+ int flags = 0;
+ final WindowManager.LayoutParams attrs = mWin.mAttrs;
+
+ if ((attrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
+ flags |= Surface.SECURE;
+ }
+ if (WindowState.DEBUG_VISIBILITY) Slog.v(
+ TAG, "Creating surface in session "
+ + mSession.mSurfaceSession + " window " + this
+ + " w=" + mWin.mCompatFrame.width()
+ + " h=" + mWin.mCompatFrame.height() + " format="
+ + attrs.format + " flags=" + flags);
+
+ int w = mWin.mCompatFrame.width();
+ int h = mWin.mCompatFrame.height();
+ if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) {
+ // for a scaled surface, we always want the requested
+ // size.
+ w = mWin.mRequestedWidth;
+ h = mWin.mRequestedHeight;
+ }
+
+ // Something is wrong and SurfaceFlinger will not like this,
+ // try to revert to sane values
+ if (w <= 0) w = 1;
+ if (h <= 0) h = 1;
+
+ mSurfaceShown = false;
+ mSurfaceLayer = 0;
+ mSurfaceAlpha = 1;
+ mSurfaceX = 0;
+ mSurfaceY = 0;
+ mSurfaceW = w;
+ mSurfaceH = h;
+ try {
+ final boolean isHwAccelerated = (attrs.flags &
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+ final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+ if (!PixelFormat.formatHasAlpha(attrs.format)) {
+ flags |= Surface.OPAQUE;
+ }
+ mSurface = new Surface(
+ mSession.mSurfaceSession, mSession.mPid,
+ attrs.getTitle().toString(),
+ 0, w, h, format, flags);
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG,
+ " CREATE SURFACE "
+ + mSurface + " IN SESSION "
+ + mSession.mSurfaceSession
+ + ": pid=" + mSession.mPid + " format="
+ + attrs.format + " flags=0x"
+ + Integer.toHexString(flags)
+ + " / " + this);
+ } catch (Surface.OutOfResourcesException e) {
+ Slog.w(TAG, "OutOfResourcesException creating surface");
+ mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
+ return null;
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception creating surface", e);
+ return null;
+ }
+
+ if (WindowManagerService.localLOGV) Slog.v(
+ TAG, "Got surface: " + mSurface
+ + ", set left=" + mWin.mFrame.left + " top=" + mWin.mFrame.top
+ + ", animLayer=" + mAnimLayer);
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
+ WindowManagerService.logSurface(mWin, "CREATE pos=("
+ + mWin.mFrame.left + "," + mWin.mFrame.top + ") ("
+ + mWin.mCompatFrame.width() + "x" + mWin.mCompatFrame.height()
+ + "), layer=" + mAnimLayer + " HIDE", null);
+ }
+ Surface.openTransaction();
+ try {
+ try {
+ mSurfaceX = mWin.mFrame.left + mWin.mXOffset;
+ mSurfaceY = mWin.mFrame.top + mWin.mYOffset;
+ mSurface.setPosition(mSurfaceX, mSurfaceY);
+ mSurfaceLayer = mAnimLayer;
+ mSurface.setLayer(mAnimLayer);
+ mSurfaceShown = false;
+ mSurface.hide();
+ if ((mWin.mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
+ if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "DITHER", null);
+ mSurface.setFlags(Surface.SURFACE_DITHER, Surface.SURFACE_DITHER);
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error creating surface in " + w, e);
+ mService.reclaimSomeSurfaceMemoryLocked(this, "create-init", true);
+ }
+ mWin.mLastHidden = true;
+ } finally {
+ Surface.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ "<<< CLOSE TRANSACTION createSurfaceLocked");
+ }
+ if (WindowManagerService.localLOGV) Slog.v(
+ TAG, "Created surface " + this);
+ }
+ return mSurface;
+ }
+
+ void destroySurfaceLocked() {
+ if (mWin.mAppToken != null && mWin == mWin.mAppToken.startingWindow) {
+ mWin.mAppToken.startingDisplayed = false;
+ }
+
+ if (mSurface != null) {
+ mWin.mDrawPending = false;
+ mWin.mCommitDrawPending = false;
+ mWin.mReadyToShow = false;
+
+ int i = mWin.mChildWindows.size();
+ while (i > 0) {
+ i--;
+ WindowState c = mWin.mChildWindows.get(i);
+ c.mAttachedHidden = true;
+ }
+
+ if (mReportDestroySurface) {
+ mReportDestroySurface = false;
+ mSurfacePendingDestroy = true;
+ try {
+ mWin.mClient.dispatchGetNewSurface();
+ // We'll really destroy on the next time around.
+ return;
+ } catch (RemoteException e) {
+ }
+ }
+
+ try {
+ if (DEBUG_VISIBILITY) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.w(TAG, "Window " + this + " destroying surface "
+ + mSurface + ", session " + mSession, e);
+ }
+ if (mSurfaceDestroyDeferred) {
+ if (mSurface != null && mPendingDestroySurface != mSurface) {
+ if (mPendingDestroySurface != null) {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
+ }
+ mPendingDestroySurface.destroy();
+ }
+ mPendingDestroySurface = mSurface;
+ }
+ } else {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ WindowManagerService.logSurface(mWin, "DESTROY", e);
+ }
+ mSurface.destroy();
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Exception thrown when destroying Window " + this
+ + " surface " + mSurface + " session " + mSession
+ + ": " + e.toString());
+ }
+
+ mSurfaceShown = false;
+ mSurface = null;
+ }
+ }
+
+ void destroyDeferredSurfaceLocked() {
+ try {
+ if (mPendingDestroySurface != null) {
+ if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
+ }
+ mPendingDestroySurface.destroy();
+ }
+ } catch (RuntimeException e) {
+ Slog.w(WindowManagerService.TAG, "Exception thrown when destroying Window "
+ + this + " surface " + mPendingDestroySurface
+ + " session " + mSession + ": " + e.toString());
+ }
+ mSurfaceDestroyDeferred = false;
+ mPendingDestroySurface = null;
+ }
+
+ void computeShownFrameLocked() {
+ final boolean selfTransformation = mHasLocalTransformation;
+ Transformation attachedTransformation =
+ (mAttachedWindow != null && mAttachedWindow.mWinAnimator.mHasLocalTransformation)
+ ? mAttachedWindow.mWinAnimator.mTransformation : null;
+ Transformation appTransformation =
+ (mWin.mAppToken != null && mWin.mAppToken.hasTransformation)
+ ? mWin.mAppToken.transformation : null;
+
+ // Wallpapers are animated based on the "real" window they
+ // are currently targeting.
+ if (mWin.mAttrs.type == TYPE_WALLPAPER && mService.mLowerWallpaperTarget == null
+ && mService.mWallpaperTarget != null) {
+ if (mService.mWallpaperTarget.mWinAnimator.mHasLocalTransformation &&
+ mService.mWallpaperTarget.mWinAnimator.mAnimation != null &&
+ !mService.mWallpaperTarget.mWinAnimator.mAnimation.getDetachWallpaper()) {
+ attachedTransformation = mService.mWallpaperTarget.mWinAnimator.mTransformation;
+ if (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) {
+ Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
+ }
+ }
+ if (mService.mWallpaperTarget.mAppToken != null &&
+ mService.mWallpaperTarget.mAppToken.hasTransformation &&
+ mService.mWallpaperTarget.mAppToken.animation != null &&
+ !mService.mWallpaperTarget.mAppToken.animation.getDetachWallpaper()) {
+ appTransformation = mService.mWallpaperTarget.mAppToken.transformation;
+ if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) {
+ Slog.v(TAG, "WP target app xform: " + appTransformation);
+ }
+ }
+ }
+
+ final boolean screenAnimation = mService.mAnimator.mScreenRotationAnimation != null
+ && mService.mAnimator.mScreenRotationAnimation.isAnimating();
+ if (selfTransformation || attachedTransformation != null
+ || appTransformation != null || screenAnimation) {
+ // cache often used attributes locally
+ final Rect frame = mWin.mFrame;
+ final float tmpFloats[] = mService.mTmpFloats;
+ final Matrix tmpMatrix = mWin.mTmpMatrix;
+
+ // Compute the desired transformation.
+ if (screenAnimation) {
+ // If we are doing a screen animation, the global rotation
+ // applied to windows can result in windows that are carefully
+ // aligned with each other to slightly separate, allowing you
+ // to see what is behind them. An unsightly mess. This...
+ // thing... magically makes it call good: scale each window
+ // slightly (two pixels larger in each dimension, from the
+ // window's center).
+ final float w = frame.width();
+ final float h = frame.height();
+ if (w>=1 && h>=1) {
+ tmpMatrix.setScale(1 + 2/w, 1 + 2/h, w/2, h/2);
+ } else {
+ tmpMatrix.reset();
+ }
+ } else {
+ tmpMatrix.reset();
+ }
+ tmpMatrix.postScale(mWin.mGlobalScale, mWin.mGlobalScale);
+ if (selfTransformation) {
+ tmpMatrix.postConcat(mTransformation.getMatrix());
+ }
+ tmpMatrix.postTranslate(frame.left + mWin.mXOffset, frame.top + mWin.mYOffset);
+ if (attachedTransformation != null) {
+ tmpMatrix.postConcat(attachedTransformation.getMatrix());
+ }
+ if (appTransformation != null) {
+ tmpMatrix.postConcat(appTransformation.getMatrix());
+ }
+ if (screenAnimation) {
+ tmpMatrix.postConcat(
+ mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix());
+ }
+
+ // "convert" it into SurfaceFlinger's format
+ // (a 2x2 matrix + an offset)
+ // Here we must not transform the position of the surface
+ // since it is already included in the transformation.
+ //Slog.i(TAG, "Transform: " + matrix);
+
+ mHaveMatrix = true;
+ tmpMatrix.getValues(tmpFloats);
+ mDsDx = tmpFloats[Matrix.MSCALE_X];
+ mDtDx = tmpFloats[Matrix.MSKEW_Y];
+ mDsDy = tmpFloats[Matrix.MSKEW_X];
+ mDtDy = tmpFloats[Matrix.MSCALE_Y];
+ float x = tmpFloats[Matrix.MTRANS_X];
+ float y = tmpFloats[Matrix.MTRANS_Y];
+ int w = frame.width();
+ int h = frame.height();
+ mWin.mShownFrame.set(x, y, x+w, y+h);
+
+ // Now set the alpha... but because our current hardware
+ // can't do alpha transformation on a non-opaque surface,
+ // turn it off if we are running an animation that is also
+ // transforming since it is more important to have that
+ // animation be smooth.
+ mShownAlpha = mAlpha;
+ if (!mService.mLimitedAlphaCompositing
+ || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
+ || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
+ && x == frame.left && y == frame.top))) {
+ //Slog.i(TAG, "Applying alpha transform");
+ if (selfTransformation) {
+ mShownAlpha *= mTransformation.getAlpha();
+ }
+ if (attachedTransformation != null) {
+ mShownAlpha *= attachedTransformation.getAlpha();
+ }
+ if (appTransformation != null) {
+ mShownAlpha *= appTransformation.getAlpha();
+ }
+ if (screenAnimation) {
+ mShownAlpha *=
+ mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha();
+ }
+ } else {
+ //Slog.i(TAG, "Not applying alpha transform");
+ }
+
+ if (WindowManagerService.localLOGV) Slog.v(
+ TAG, "computeShownFrameLocked: Animating " + this +
+ ": " + mWin.mShownFrame +
+ ", alpha=" + mTransformation.getAlpha() + ", mShownAlpha=" + mShownAlpha);
+ return;
+ }
+
+ if (WindowManagerService.localLOGV) Slog.v(
+ TAG, "computeShownFrameLocked: " + this +
+ " not attached, mAlpha=" + mAlpha);
+ mWin.mShownFrame.set(mWin.mFrame);
+ if (mWin.mXOffset != 0 || mWin.mYOffset != 0) {
+ mWin.mShownFrame.offset(mWin.mXOffset, mWin.mYOffset);
+ }
+ mShownAlpha = mAlpha;
+ mHaveMatrix = false;
+ mDsDx = mWin.mGlobalScale;
+ mDtDx = 0;
+ mDsDy = 0;
+ mDtDy = mWin.mGlobalScale;
+ }
+ public void prepareSurfaceLocked(final boolean recoveringMemory) {
+ final WindowState w = mWin;
+ if (mSurface == null) {
+ if (w.mOrientationChanging) {
+ if (WindowManagerService.DEBUG_ORIENTATION) {
+ Slog.v(TAG, "Orientation change skips hidden " + w);
+ }
+ w.mOrientationChanging = false;
+ }
+ return;
+ }
+
+ boolean displayed = false;
+
+ computeShownFrameLocked();
+
+ int width, height;
+ if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
+ // for a scaled surface, we just want to use
+ // the requested size.
+ width = w.mRequestedWidth;
+ height = w.mRequestedHeight;
+ } else {
+ width = w.mCompatFrame.width();
+ height = w.mCompatFrame.height();
+ }
+
+ if (width < 1) {
+ width = 1;
+ }
+ if (height < 1) {
+ height = 1;
+ }
+ final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height;
+ if (surfaceResized) {
+ mSurfaceW = width;
+ mSurfaceH = height;
+ }
+
+ if (mSurfaceX != w.mShownFrame.left
+ || mSurfaceY != w.mShownFrame.top) {
+ try {
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "POS " + w.mShownFrame.left
+ + ", " + w.mShownFrame.top, null);
+ mSurfaceX = w.mShownFrame.left;
+ mSurfaceY = w.mShownFrame.top;
+ mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error positioning surface of " + w
+ + " pos=(" + w.mShownFrame.left
+ + "," + w.mShownFrame.top + ")", e);
+ if (!recoveringMemory) {
+ mService.reclaimSomeSurfaceMemoryLocked(this, "position", true);
+ }
+ }
+ }
+
+ if (surfaceResized) {
+ try {
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "SIZE " + width + "x" + height, null);
+ mSurfaceResized = true;
+ mSurface.setSize(width, height);
+ } catch (RuntimeException e) {
+ // If something goes wrong with the surface (such
+ // as running out of memory), don't take down the
+ // entire system.
+ Slog.e(TAG, "Error resizing surface of " + w
+ + " size=(" + width + "x" + height + ")", e);
+ if (!recoveringMemory) {
+ mService.reclaimSomeSurfaceMemoryLocked(this, "size", true);
+ }
+ }
+ }
+
+ if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+ if (!w.mLastHidden) {
+ //dump();
+ w.mLastHidden = true;
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "HIDE (performLayout)", null);
+ if (mSurface != null) {
+ mSurfaceShown = false;
+ try {
+ mSurface.hide();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Exception hiding surface in " + w);
+ }
+ }
+ }
+ // If we are waiting for this window to handle an
+ // orientation change, well, it is hidden, so
+ // doesn't really matter. Note that this does
+ // introduce a potential glitch if the window
+ // becomes unhidden before it has drawn for the
+ // new orientation.
+ if (w.mOrientationChanging) {
+ w.mOrientationChanging = false;
+ if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+ "Orientation change skips hidden " + w);
+ }
+ } else if (mLastLayer != mAnimLayer
+ || mLastAlpha != mShownAlpha
+ || mLastDsDx != mDsDx
+ || mLastDtDx != mDtDx
+ || mLastDsDy != mDsDy
+ || mLastDtDy != mDtDy
+ || w.mLastHScale != w.mHScale
+ || w.mLastVScale != w.mVScale
+ || w.mLastHidden) {
+ displayed = true;
+ mLastAlpha = mShownAlpha;
+ mLastLayer = mAnimLayer;
+ mLastDsDx = mDsDx;
+ mLastDtDx = mDtDx;
+ mLastDsDy = mDsDy;
+ mLastDtDy = mDtDy;
+ w.mLastHScale = w.mHScale;
+ w.mLastVScale = w.mVScale;
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "alpha=" + mShownAlpha + " layer=" + mAnimLayer
+ + " matrix=[" + (mDsDx*w.mHScale)
+ + "," + (mDtDx*w.mVScale)
+ + "][" + (mDsDy*w.mHScale)
+ + "," + (mDtDy*w.mVScale) + "]", null);
+ if (mSurface != null) {
+ try {
+ mSurfaceAlpha = mShownAlpha;
+ mSurface.setAlpha(mShownAlpha);
+ mSurfaceLayer = w.mWinAnimator.mAnimLayer;
+ mSurface.setLayer(w.mWinAnimator.mAnimLayer);
+ mSurface.setMatrix(
+ mDsDx*w.mHScale, mDtDx*w.mVScale,
+ mDsDy*w.mHScale, mDtDy*w.mVScale);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error updating surface in " + w, e);
+ if (!recoveringMemory) {
+ mService.reclaimSomeSurfaceMemoryLocked(this, "update", true);
+ }
+ }
+ }
+
+ if (w.mLastHidden && w.isDrawnLw()
+ && !w.mReadyToShow) {
+ if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+ "SHOW (performLayout)", null);
+ if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
+ + " during relayout");
+ if (showSurfaceRobustlyLocked()) {
+ w.mHasDrawn = true;
+ w.mLastHidden = false;
+ } else {
+ w.mOrientationChanging = false;
+ }
+ }
+ if (mSurface != null) {
+ w.mToken.hasVisible = true;
+ }
+ } else {
+ displayed = true;
+ }
+
+ if (displayed) {
+ if (w.mOrientationChanging) {
+ if (!w.isDrawnLw()) {
+ mService.mInnerFields.mOrientationChangeComplete = false;
+ if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+ "Orientation continue waiting for draw in " + w);
+ } else {
+ w.mOrientationChanging = false;
+ if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+ "Orientation change complete in " + w);
+ }
+ }
+ w.mToken.hasVisible = true;
+ }
+ }
+
+ // This must be called while inside a transaction.
+ boolean performShowLocked() {
+ if (DEBUG_VISIBILITY) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.v(WindowManagerService.TAG, "performShow on " + this
+ + ": readyToShow=" + mWin.mReadyToShow + " readyForDisplay="
+ + mWin.isReadyForDisplay()
+ + " starting=" + (mWin.mAttrs.type == TYPE_APPLICATION_STARTING), e);
+ }
+ if (mWin.mReadyToShow && mWin.isReadyForDisplay()) {
+ if (SHOW_TRANSACTIONS || WindowManagerService.DEBUG_ORIENTATION)
+ WindowManagerService.logSurface(mWin, "SHOW (performShowLocked)", null);
+ if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Showing " + this
+ + " during animation: policyVis=" + mWin.mPolicyVisibility
+ + " attHidden=" + mWin.mAttachedHidden
+ + " tok.hiddenRequested="
+ + (mWin.mAppToken != null ? mWin.mAppToken.hiddenRequested : false)
+ + " tok.hidden="
+ + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
+ + " animating=" + mAnimating
+ + " tok animating="
+ + (mWin.mAppToken != null ? mWin.mAppToken.animating : false));
+ if (!showSurfaceRobustlyLocked()) {
+ return false;
+ }
+
+ mService.enableScreenIfNeededLocked();
+
+ applyEnterAnimationLocked();
+
+ mLastAlpha = -1;
+ mWin.mHasDrawn = true;
+ mWin.mLastHidden = false;
+ mWin.mReadyToShow = false;
+
+ int i = mWin.mChildWindows.size();
+ while (i > 0) {
+ i--;
+ WindowState c = mWin.mChildWindows.get(i);
+ if (c.mAttachedHidden) {
+ c.mAttachedHidden = false;
+ if (c.mWinAnimator.mSurface != null) {
+ c.mWinAnimator.performShowLocked();
+ // It hadn't been shown, which means layout not
+ // performed on it, so now we want to make sure to
+ // do a layout. If called from within the transaction
+ // loop, this will cause it to restart with a new
+ // layout.
+ mService.mLayoutNeeded = true;
+ }
+ }
+ }
+
+ if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING
+ && mWin.mAppToken != null) {
+ mWin.mAppToken.firstWindowDrawn = true;
+
+ if (mWin.mAppToken.startingData != null) {
+ if (WindowManagerService.DEBUG_STARTING_WINDOW ||
+ WindowManagerService.DEBUG_ANIM) Slog.v(WindowManagerService.TAG,
+ "Finish starting " + mWin.mToken
+ + ": first real window is shown, no animation");
+ // If this initial window is animating, stop it -- we
+ // will do an animation to reveal it from behind the
+ // starting window, so there is no need for it to also
+ // be doing its own stuff.
+ if (mAnimation != null) {
+ mAnimation.cancel();
+ mAnimation = null;
+ // Make sure we clean up the animation.
+ mAnimating = true;
+ }
+ mService.mFinishedStarting.add(mWin.mAppToken);
+ mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
+ }
+ mWin.mAppToken.updateReportedVisibilityLocked();
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Have the surface flinger show a surface, robustly dealing with
+ * error conditions. In particular, if there is not enough memory
+ * to show the surface, then we will try to get rid of other surfaces
+ * in order to succeed.
+ *
+ * @return Returns true if the surface was successfully shown.
+ */
+ boolean showSurfaceRobustlyLocked() {
+ try {
+ if (mSurface != null) {
+ mSurfaceShown = true;
+ mSurface.show();
+ if (mWin.mTurnOnScreen) {
+ if (DEBUG_VISIBILITY) Slog.v(TAG,
+ "Show surface turning screen on: " + mWin);
+ mWin.mTurnOnScreen = false;
+ mService.mTurnOnScreen = true;
+ }
+ }
+ return true;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure showing surface " + mSurface + " in " + mWin, e);
+ }
+
+ mService.reclaimSomeSurfaceMemoryLocked(this, "show", true);
+
+ return false;
+ }
+
+ void applyEnterAnimationLocked() {
+ final int transit;
+ if (mEnterAnimationPending) {
+ mEnterAnimationPending = false;
+ transit = WindowManagerPolicy.TRANSIT_ENTER;
+ } else {
+ transit = WindowManagerPolicy.TRANSIT_SHOW;
+ }
+
+ applyAnimationLocked(transit, true);
+ }
+
+ /**
+ * Choose the correct animation and set it to the passed WindowState.
+ * @param transit If WindowManagerPolicy.TRANSIT_PREVIEW_DONE and the app window has been drawn
+ * then the animation will be app_starting_exit. Any other value loads the animation from
+ * the switch statement below.
+ * @param isEntrance The animation type the last time this was called. Used to keep from
+ * loading the same animation twice.
+ * @return true if an animation has been loaded.
+ */
+ boolean applyAnimationLocked(int transit, boolean isEntrance) {
+ if (mLocalAnimating && mAnimationIsEntrance == isEntrance) {
+ // If we are trying to apply an animation, but already running
+ // an animation of the same type, then just leave that one alone.
+ return true;
+ }
+
+ // Only apply an animation if the display isn't frozen. If it is
+ // frozen, there is no reason to animate and it can cause strange
+ // artifacts when we unfreeze the display if some different animation
+ // is running.
+ if (mService.okToDisplay()) {
+ int anim = mPolicy.selectAnimationLw(mWin, transit);
+ int attr = -1;
+ Animation a = null;
+ if (anim != 0) {
+ a = AnimationUtils.loadAnimation(mContext, anim);
+ } else {
+ switch (transit) {
+ case WindowManagerPolicy.TRANSIT_ENTER:
+ attr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_EXIT:
+ attr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_SHOW:
+ attr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
+ break;
+ case WindowManagerPolicy.TRANSIT_HIDE:
+ attr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
+ break;
+ }
+ if (attr >= 0) {
+ a = mService.loadAnimation(mWin.mAttrs, attr);
+ }
+ }
+ if (WindowManagerService.DEBUG_ANIM) Slog.v(WindowManagerService.TAG,
+ "applyAnimation: win=" + this
+ + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
+ + " mAnimation=" + mAnimation
+ + " isEntrance=" + isEntrance);
+ if (a != null) {
+ if (WindowManagerService.DEBUG_ANIM) {
+ RuntimeException e = null;
+ if (!WindowManagerService.HIDE_STACK_CRAWLS) {
+ e = new RuntimeException();
+ e.fillInStackTrace();
+ }
+ Slog.v(WindowManagerService.TAG, "Loaded animation " + a + " for " + this, e);
+ }
+ setAnimation(a);
+ mAnimationIsEntrance = isEntrance;
+ }
+ } else {
+ clearAnimation();
+ }
+
+ return mAnimation != null;
+ }
+
public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
if (mAnimating || mLocalAnimating || mAnimationIsEntrance
|| mAnimation != null) {
@@ -295,6 +1098,38 @@
pw.print(" "); mTransformation.printShortString(pw);
pw.println();
}
+ if (mSurface != null) {
+ if (dumpAll) {
+ pw.print(prefix); pw.print("mSurface="); pw.println(mSurface);
+ }
+ pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown);
+ pw.print(" layer="); pw.print(mSurfaceLayer);
+ pw.print(" alpha="); pw.print(mSurfaceAlpha);
+ pw.print(" rect=("); pw.print(mSurfaceX);
+ pw.print(","); pw.print(mSurfaceY);
+ pw.print(") "); pw.print(mSurfaceW);
+ pw.print(" x "); pw.println(mSurfaceH);
+ }
+ if (mPendingDestroySurface != null) {
+ pw.print(prefix); pw.print("mPendingDestroySurface=");
+ pw.println(mPendingDestroySurface);
+ }
+ if (mSurfaceResized || mSurfaceDestroyDeferred) {
+ pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
+ pw.print(" mSurfaceDestroyDeferred="); pw.println(mSurfaceDestroyDeferred);
+ }
+ if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
+ pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
+ pw.print(" mAlpha="); pw.print(mAlpha);
+ pw.print(" mLastAlpha="); pw.println(mLastAlpha);
+ }
+ if (mHaveMatrix || mWin.mGlobalScale != 1) {
+ pw.print(prefix); pw.print("mGlobalScale="); pw.print(mWin.mGlobalScale);
+ pw.print(" mDsDx="); pw.print(mDsDx);
+ pw.print(" mDtDx="); pw.print(mDtDx);
+ pw.print(" mDsDy="); pw.print(mDsDy);
+ pw.print(" mDtDy="); pw.println(mDtDy);
+ }
}
}