Combine DimAnimator and DimSurface into DimLayer

Replace two classes that did similar things in a complicated manner
with one class that does it more simply.

Bug 7064755 fixed.

Change-Id: I8c415671f60d1d2ece9da5916421f4d24aed2d65
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
deleted file mode 100644
index 5874202..0000000
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.content.res.Resources;
-import android.graphics.PixelFormat;
-import android.util.Slog;
-import android.util.TypedValue;
-import android.view.Surface;
-import android.view.SurfaceSession;
-
-import java.io.PrintWriter;
-
-/**
- * DimAnimator class that controls the dim animation. This holds the surface and
- * all state used for dim animation.
- */
-class DimAnimator {
-    static final String TAG = "DimAnimator";
-
-    Surface mDimSurface;
-    boolean mDimShown = false;
-    float mDimCurrentAlpha;
-    float mDimTargetAlpha;
-    float mDimDeltaPerMs;
-    long mLastDimAnimTime;
-
-    int mLastDimWidth, mLastDimHeight;
-
-    DimAnimator (SurfaceSession session, final int layerStack) {
-        try {
-            if (WindowManagerService.DEBUG_SURFACE_TRACE) {
-                mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
-                    "DimAnimator",
-                    16, 16, PixelFormat.OPAQUE,
-                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-            } else {
-                mDimSurface = new Surface(session, "DimAnimator",
-                    16, 16, PixelFormat.OPAQUE,
-                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-            }
-            if (WindowManagerService.SHOW_TRANSACTIONS ||
-                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                            "  DIM " + mDimSurface + ": CREATE");
-            mDimSurface.setLayerStack(layerStack);
-            mDimSurface.setAlpha(0.0f);
-            mDimSurface.show();
-        } catch (Exception e) {
-            Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
-        }
-    }
-
-    /**
-     * Set's the dim surface's layer and update dim parameters that will be used in
-     * {@link #updateSurface} after all windows are examined.
-     */
-    void updateParameters(final Resources res, final Parameters params, final long currentTime) {
-        if (mDimSurface == null) {
-            Slog.e(TAG, "updateParameters: no Surface");
-            return;
-        }
-
-        // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
-        // corner.
-        final int dw = (int) (params.mDimWidth * 1.5);
-        final int dh = (int) (params.mDimHeight * 1.5);
-        final WindowStateAnimator winAnimator = params.mDimWinAnimator;
-        final float target = params.mDimTarget;
-        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;
-                // back off position so mDimXXX/4 is before and mDimXXX/4 is after
-                mDimSurface.setPosition(-1 * dw / 6, -1 * dh /6);
-                mDimSurface.setSize(dw, dh);
-                mDimSurface.show();
-            } catch (RuntimeException e) {
-                Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
-            }
-        } else if (mLastDimWidth != dw || mLastDimHeight != dh) {
-            mLastDimWidth = dw;
-            mLastDimHeight = dh;
-            mDimSurface.setSize(dw, dh);
-            // back off position so mDimXXX/4 is before and mDimXXX/4 is after
-            mDimSurface.setPosition(-1 * dw / 6, -1 * dh /6);
-        }
-
-        mDimSurface.setLayer(winAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
-
-        if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
-                + mDimSurface + ": layer=" + (winAnimator.mAnimLayer-1) + " target=" + target);
-        if (mDimTargetAlpha != target) {
-            // If the desired dim level has changed, then
-            // start an animation to it.
-            mLastDimAnimTime = currentTime;
-            long duration = (winAnimator.mAnimating && winAnimator.mAnimation != null)
-                    ? winAnimator.mAnimation.computeDurationHint()
-                    : WindowManagerService.DEFAULT_DIM_DURATION;
-            if (target > mDimTargetAlpha) {
-                TypedValue tv = new TypedValue();
-                res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration,
-                        tv, true);
-                if (tv.type == TypedValue.TYPE_FRACTION) {
-                    duration = (long)tv.getFraction(duration, duration);
-                } else if (tv.type >= TypedValue.TYPE_FIRST_INT
-                        && tv.type <= TypedValue.TYPE_LAST_INT) {
-                    duration = tv.data;
-                }
-            }
-            if (duration < 1) {
-                // Don't divide by zero
-                duration = 1;
-            }
-            mDimTargetAlpha = target;
-            mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
-        }
-    }
-
-    /**
-     * Updating the surface's alpha. Returns true if the animation continues, or returns
-     * false when the animation is finished and the dim surface is hidden.
-     */
-    boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
-        if (mDimSurface == null) {
-            Slog.e(TAG, "updateSurface: no Surface");
-            return false;
-        }
-
-        if (!dimming) {
-            if (mDimTargetAlpha != 0) {
-                mLastDimAnimTime = currentTime;
-                mDimTargetAlpha = 0;
-                mDimDeltaPerMs = (-mDimCurrentAlpha) / WindowManagerService.DEFAULT_DIM_DURATION;
-            }
-        }
-
-        boolean animating = mLastDimAnimTime != 0;
-        if (animating) {
-            mDimCurrentAlpha += mDimDeltaPerMs
-                    * (currentTime-mLastDimAnimTime);
-            if (displayFrozen) {
-                // If the display is frozen, there is no reason to animate.
-                animating = false;
-            } else if (mDimDeltaPerMs > 0) {
-                if (mDimCurrentAlpha > mDimTargetAlpha) {
-                    animating = false;
-                }
-            } else if (mDimDeltaPerMs < 0) {
-                if (mDimCurrentAlpha < mDimTargetAlpha) {
-                    animating = false;
-                }
-            } else {
-                animating = false;
-            }
-
-            // Do we need to continue animating?
-            if (animating) {
-                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
-                        + mDimSurface + ": alpha=" + mDimCurrentAlpha);
-                mLastDimAnimTime = currentTime;
-                mDimSurface.setAlpha(mDimCurrentAlpha);
-            } else {
-                mDimCurrentAlpha = mDimTargetAlpha;
-                mLastDimAnimTime = 0;
-                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
-                        + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
-                mDimSurface.setAlpha(mDimCurrentAlpha);
-                if (!dimming) {
-                    if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface
-                            + ": HIDE");
-                    try {
-                        mDimSurface.hide();
-                    } catch (RuntimeException e) {
-                        Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
-                    }
-                    mDimShown = false;
-                }
-            }
-        }
-        return animating;
-    }
-
-    public void kill() {
-        if (mDimSurface != null) {
-            mDimSurface.destroy();
-            mDimSurface = null;
-        }
-    }
-
-    public void printTo(String prefix, PrintWriter pw) {
-        pw.print(prefix);
-        pw.print("mDimSurface="); pw.print(mDimSurface);
-                pw.print(" "); pw.print(mLastDimWidth); pw.print(" x ");
-                pw.println(mLastDimHeight);
-        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);
-        pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
-    }
-
-    static class Parameters {
-        final WindowStateAnimator mDimWinAnimator;
-        final int mDimWidth;
-        final int mDimHeight;
-        final float mDimTarget;
-        Parameters(final WindowStateAnimator dimWinAnimator, final int dimWidth,
-                final int dimHeight, final float dimTarget) {
-            mDimWinAnimator = dimWinAnimator;
-            mDimWidth = dimWidth;
-            mDimHeight = dimHeight;
-            mDimTarget = dimTarget;
-        }
-
-        Parameters(Parameters o) {
-            mDimWinAnimator = o.mDimWinAnimator;
-            mDimWidth = o.mDimWidth;
-            mDimHeight = o.mDimHeight;
-            mDimTarget = o.mDimTarget;
-        }
-
-        public void printTo(String prefix, PrintWriter pw) {
-            pw.print(prefix);
-            pw.print("mDimWinAnimator="); pw.print(mDimWinAnimator.mWin.mAttrs.getTitle());
-                    pw.print(" "); pw.print(mDimWidth); pw.print(" x ");
-                    pw.print(mDimHeight);
-            pw.print(" mDimTarget="); pw.println(mDimTarget);
-        }
-    }
-}
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/java/com/android/server/wm/DimLayer.java
new file mode 100644
index 0000000..162caf5
--- /dev/null
+++ b/services/java/com/android/server/wm/DimLayer.java
@@ -0,0 +1,257 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.android.server.wm;
+
+import android.graphics.PixelFormat;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.Surface;
+
+import java.io.PrintWriter;
+
+public class DimLayer {
+    private static final String TAG = "DimLayer";
+    private static final boolean DEBUG = true;
+
+    /** Reference to the owner of this object. */
+    final DisplayContent mDisplayContent;
+
+    /** Actual surface that dims */
+    Surface mDimSurface;
+
+    /** Last value passed to mDimSurface.setAlpha() */
+    float mAlpha = 0;
+
+    /** Last value passed to mDimSurface.setLayer() */
+    int mLayer = -1;
+
+    /** Last values passed to mDimSurface.setSize() */
+    int mLastDimWidth, mLastDimHeight;
+
+    /** True after mDimSurface.show() has been called, false after mDimSurface.hide(). */
+    private boolean mShowing = false;
+
+    /** Value of mAlpha when beginning transition to mTargetAlpha */
+    float mStartAlpha = 0;
+
+    /** Final value of mAlpha following transition */
+    float mTargetAlpha = 0;
+
+    /** Time in units of SystemClock.uptimeMillis() at which the current transition started */
+    long mStartTime;
+
+    /** Time in milliseconds to take to transition from mStartAlpha to mTargetAlpha */
+    long mDuration;
+
+    DimLayer(WindowManagerService service, int displayId) {
+        if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
+        mDisplayContent = service.getDisplayContentLocked(displayId);
+        Surface.openTransaction();
+        try {
+            if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+                mDimSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession,
+                    "DimSurface",
+                    16, 16, PixelFormat.OPAQUE,
+                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+            } else {
+                mDimSurface = new Surface(service.mFxSession, TAG,
+                    16, 16, PixelFormat.OPAQUE,
+                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
+            }
+            if (WindowManagerService.SHOW_TRANSACTIONS ||
+                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(TAG,
+                            "  DIM " + mDimSurface + ": CREATE");
+            mDimSurface.setLayerStack(displayId);
+        } catch (Exception e) {
+            Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
+        } finally {
+            Surface.closeTransaction();
+        }
+    }
+
+    /** Return true if dim layer is showing */
+    boolean isDimming() {
+        return mTargetAlpha != 0;
+    }
+
+    /** Return true if in a transition period */
+    boolean isAnimating() {
+        return mTargetAlpha != mAlpha;
+    }
+
+    float getTargetAlpha() {
+        return mTargetAlpha;
+    }
+
+    private void setAlpha(float alpha) {
+        if (mAlpha != alpha) {
+            if (DEBUG) Slog.v(TAG, "setAlpha alpha=" + alpha);
+            try {
+                mDimSurface.setAlpha(alpha);
+                if (alpha == 0 && mShowing) {
+                    if (DEBUG) Slog.v(TAG, "setAlpha hiding");
+                    mDimSurface.hide();
+                    mShowing = false;
+                } else if (alpha > 0 && !mShowing) {
+                    if (DEBUG) Slog.v(TAG, "setAlpha showing");
+                    mDimSurface.show();
+                    mShowing = true;
+                }
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Failure setting alpha immediately", e);
+            }
+            mAlpha = alpha;
+        }
+    }
+
+    /**
+     * @param duration The time to test.
+     * @return True if the duration would lead to an earlier end to the current animation.
+     */
+    private boolean durationEndsEarlier(long duration) {
+        return SystemClock.uptimeMillis() + duration < mStartTime + mDuration;
+    }
+
+    /** Jump to the end of the animation.
+     * NOTE: Must be called with Surface transaction open. */
+    void show() {
+        if (isAnimating()) {
+            if (DEBUG) Slog.v(TAG, "show: immediate");
+            show(mLayer, mTargetAlpha, 0);
+        }
+    }
+
+    /**
+     * Begin an animation to a new dim value.
+     * NOTE: Must be called with Surface transaction open.
+     *
+     * @param layer The layer to set the surface to.
+     * @param alpha The dim value to end at.
+     * @param duration How long to take to get there in milliseconds.
+     */
+    void show(int layer, float alpha, long duration) {
+        if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha
+                + " duration=" + duration);
+        if (mDimSurface == null) {
+            Slog.e(TAG, "show: no Surface");
+            // Make sure isAnimating() returns false.
+            mTargetAlpha = mAlpha = 0;
+            return;
+        }
+
+        // Set surface size to screen size.
+        final DisplayInfo info = mDisplayContent.getDisplayInfo();
+        // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
+        // corner.
+        final int dw = (int) (info.logicalWidth * 1.5);
+        final int dh = (int) (info.logicalHeight * 1.5);
+        // back off position so 1/4 of Surface is before and 1/4 is after.
+        final float xPos = -1 * dw / 6;
+        final float yPos = -1 * dh / 6;
+
+        if (mLastDimWidth != dw || mLastDimHeight != dh || mLayer != layer) {
+            try {
+                mDimSurface.setPosition(xPos, yPos);
+                mDimSurface.setSize(dw, dh);
+                mDimSurface.setLayer(layer);
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Failure setting size or layer", e);
+            }
+            mLastDimWidth = dw;
+            mLastDimHeight = dh;
+            mLayer = layer;
+        }
+
+        long curTime = SystemClock.uptimeMillis();
+        final boolean animating = isAnimating();
+        if ((animating && (mTargetAlpha != alpha || durationEndsEarlier(duration)))
+                || (!animating && mAlpha != alpha)) {
+            if (duration <= 0) {
+                // No animation required, just set values.
+                setAlpha(alpha);
+            } else {
+                // Start or continue animation with new parameters.
+                mStartAlpha = mAlpha;
+                mStartTime = curTime;
+                mDuration = duration;
+            }
+        }
+        if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime);
+        mTargetAlpha = alpha;
+    }
+
+    /** Immediate hide.
+     * NOTE: Must be called with Surface transaction open. */
+    void hide() {
+        if (mShowing) {
+            if (DEBUG) Slog.v(TAG, "hide: immediate");
+            hide(0);
+        }
+    }
+
+    /**
+     * Gradually fade to transparent.
+     * NOTE: Must be called with Surface transaction open.
+     *
+     * @param duration Time to fade in milliseconds.
+     */
+    void hide(long duration) {
+        if (mShowing && (mTargetAlpha != 0 || durationEndsEarlier(duration))) {
+            if (DEBUG) Slog.v(TAG, "hide: duration=" + duration);
+            show(mLayer, 0, duration);
+        }
+    }
+
+    /**
+     * Advance the dimming per the last #show(int, float, long) call.
+     * NOTE: Must be called with Surface transaction open.
+     *
+     * @return True if animation is still required after this step.
+     */
+    boolean stepAnimation() {
+        if (mDimSurface == null) {
+            Slog.e(TAG, "stepAnimation: null Surface");
+            // Ensure that isAnimating() returns false;
+            mTargetAlpha = mAlpha = 0;
+            return false;
+        }
+
+        if (isAnimating()) {
+            final long curTime = SystemClock.uptimeMillis();
+            final float alphaDelta = mTargetAlpha - mStartAlpha;
+            float alpha = mStartAlpha + alphaDelta * (curTime - mStartTime) / mDuration;
+            if (alphaDelta > 0 && alpha > mTargetAlpha ||
+                    alphaDelta < 0 && alpha < mTargetAlpha) {
+                // Don't exceed limits.
+                alpha = mTargetAlpha;
+            }
+            if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha);
+            setAlpha(alpha);
+        }
+
+        return isAnimating();
+    }
+
+    /** Cleanup */
+    void destroySurface() {
+        if (DEBUG) Slog.v(TAG, "destroySurface.");
+        if (mDimSurface != null) {
+            mDimSurface.destroy();
+            mDimSurface = null;
+        }
+    }
+
+    public void printTo(String prefix, PrintWriter pw) {
+        pw.print(prefix); pw.print("mDimSurface="); pw.println(mDimSurface);
+        pw.print(prefix); pw.print(" mLayer="); pw.print(mLayer);
+                pw.print(" mAlpha="); pw.println(mAlpha);
+        pw.print(prefix); pw.print("mLastDimWidth="); pw.print(mLastDimWidth);
+                pw.print(" mLastDimWidth="); pw.println(mLastDimWidth);
+        pw.print(prefix); pw.print("Last animation: mStartTime="); pw.print(mStartTime);
+                pw.print(" mDuration="); pw.print(mDuration);
+                pw.print(" curTime="); pw.println(SystemClock.uptimeMillis());
+        pw.print(" mStartAlpha="); pw.println(mStartAlpha);
+                pw.print(" mTargetAlpha="); pw.print(mTargetAlpha);
+    }
+}
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
deleted file mode 100644
index 511d388..0000000
--- a/services/java/com/android/server/wm/DimSurface.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.DisplayInfo;
-import android.view.Surface;
-import android.view.SurfaceSession;
-
-import java.io.PrintWriter;
-
-class DimSurface {
-    static final String TAG = "DimSurface";
-
-    Surface mDimSurface;
-    boolean mDimShown = false;
-    int mDimColor = 0;
-    int mLayer = -1;
-    int mLastDimWidth, mLastDimHeight;
-    final DisplayContent mDisplayContent;
-
-    DimSurface(SurfaceSession session, DisplayContent displayContent) {
-        mDisplayContent = displayContent;
-        final int layerStack = displayContent.getDisplayId();
-        try {
-            if (WindowManagerService.DEBUG_SURFACE_TRACE) {
-                mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
-                    "DimSurface",
-                    16, 16, PixelFormat.OPAQUE,
-                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-            } else {
-                mDimSurface = new Surface(session, "DimSurface",
-                    16, 16, PixelFormat.OPAQUE,
-                    Surface.FX_SURFACE_DIM | Surface.HIDDEN);
-            }
-            if (WindowManagerService.SHOW_TRANSACTIONS ||
-                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
-                            "  DIM " + mDimSurface + ": CREATE");
-            mDimSurface.setLayerStack(layerStack);
-            mDimSurface.setAlpha(0.0f);
-            mDimSurface.show();
-        } catch (Exception e) {
-            Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
-        }
-    }
-
-    /**
-     * Show the dim surface.
-     */
-    void show(int layer, int color) {
-        final DisplayInfo info = mDisplayContent.getDisplayInfo();
-        final int dw = info.logicalWidth;
-        final int dh = info.logicalHeight;
-        if (mDimSurface == null) {
-            Slog.e(TAG, "show: no Surface");
-            return;
-        }
-
-        if (!mDimShown) {
-            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
-                    dw + "x" + dh + " layer=" + layer + ")");
-            mDimShown = true;
-            try {
-                mLastDimWidth = dw;
-                mLastDimHeight = dh;
-                mDimSurface.setPosition(0, 0);
-                mDimSurface.setSize(dw, dh);
-                mDimSurface.setLayer(layer);
-                mDimSurface.show();
-            } catch (RuntimeException e) {
-                Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
-            }
-        } else if (mLastDimWidth != dw || mLastDimHeight != dh || mDimColor != color
-                || mLayer != layer) {
-            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": pos=(0,0) (" +
-                    dw + "x" + dh + " layer=" + 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 (mDimSurface == null) {
-            Slog.e(TAG, "hide: no Surface");
-            return;
-        }
-
-        if (mDimShown) {
-            mDimShown = false;
-            try {
-                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  HIDE " + mDimSurface);
-                mDimSurface.hide();
-            } catch (RuntimeException e) {
-                Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
-            }
-        }
-    }
-
-    void kill() {
-        if (mDimSurface != null) {
-            mDimSurface.destroy();
-            mDimSurface = null;
-        }
-    }
-
-    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.print(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/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index a9f3c0f..d5144fb 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -19,6 +19,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
+import android.util.TypedValue;
 import android.view.Display;
 import android.view.Surface;
 import android.view.WindowManagerPolicy;
@@ -37,6 +38,10 @@
 public class WindowAnimator {
     private static final String TAG = "WindowAnimator";
 
+    /** Amount of time in milliseconds to animate the dim surface from one value to another,
+     * when no window animation is driving it. */
+    static final int DEFAULT_DIM_DURATION = 200;
+
     final WindowManagerService mService;
     final Context mContext;
     final WindowManagerPolicy mPolicy;
@@ -115,7 +120,7 @@
         final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
         if (displayAnimator != null) {
             if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
-                displayAnimator.mWindowAnimationBackgroundSurface.kill();
+                displayAnimator.mWindowAnimationBackgroundSurface.destroySurface();
                 displayAnimator.mWindowAnimationBackgroundSurface = null;
             }
             if (displayAnimator.mScreenRotationAnimation != null) {
@@ -123,7 +128,7 @@
                 displayAnimator.mScreenRotationAnimation = null;
             }
             if (displayAnimator.mDimAnimator != null) {
-                displayAnimator.mDimAnimator.kill();
+                displayAnimator.mDimAnimator.destroySurface();
                 displayAnimator.mDimAnimator = null;
             }
         }
@@ -359,8 +364,6 @@
         WindowStateAnimator windowAnimationBackground = null;
         int windowAnimationBackgroundColor = 0;
         WindowState detachedWallpaper = null;
-        final DimSurface windowAnimationBackgroundSurface =
-                displayAnimator.mWindowAnimationBackgroundSurface;
 
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
@@ -440,15 +443,11 @@
                 }
             }
 
-            if (windowAnimationBackgroundSurface != null) {
-                windowAnimationBackgroundSurface.show(
-                        animLayer - WindowManagerService.LAYER_OFFSET_DIM,
-                        windowAnimationBackgroundColor);
-            }
+            displayAnimator.mWindowAnimationBackgroundSurface.show(
+                    animLayer - WindowManagerService.LAYER_OFFSET_DIM,
+                    ((windowAnimationBackgroundColor >> 24) & 0xff) / 255f, 0);
         } else {
-            if (windowAnimationBackgroundSurface != null) {
-                windowAnimationBackgroundSurface.hide();
-            }
+            displayAnimator.mWindowAnimationBackgroundSurface.hide();
         }
     }
 
@@ -499,8 +498,19 @@
         updateWallpaperLocked(displayId);
     }
 
-    // TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
-    /** Locked on mService.mWindowMap and this. */
+    private long getDimBehindFadeDuration(long duration) {
+        TypedValue tv = new TypedValue();
+        mContext.getResources().getValue(
+            com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
+        if (tv.type == TypedValue.TYPE_FRACTION) {
+            duration = (long)tv.getFraction(duration, duration);
+        } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
+            duration = tv.data;
+        }
+        return duration;
+    }
+
+    /** Locked on mService.mWindowMap. */
     private void animateLocked() {
         if (!mInitialized) {
             return;
@@ -561,15 +571,38 @@
                     screenRotationAnimation.updateSurfacesInTransaction();
                 }
 
-                final DimAnimator.Parameters dimParams = displayAnimator.mDimParams;
-                final DimAnimator dimAnimator = displayAnimator.mDimAnimator;
-                if (dimAnimator != null && dimParams != null) {
-                    dimAnimator.updateParameters(mContext.getResources(), dimParams, mCurrentTime);
+                final DimLayer dimAnimator = displayAnimator.mDimAnimator;
+                final WindowStateAnimator winAnimator = displayAnimator.mDimWinAnimator;
+                final float dimAmount;
+                if (winAnimator == null) {
+                    dimAmount = 0;
+                } else {
+                    dimAmount = winAnimator.mWin.mAttrs.dimAmount;
                 }
-                if (dimAnimator != null && dimAnimator.mDimShown) {
-                    mAnimating |= dimAnimator.updateSurface(isDimmingLocked(displayId),
-                            mCurrentTime, !mService.okToDisplay());
+                final float targetAlpha = dimAnimator.getTargetAlpha();
+                if (targetAlpha != dimAmount) {
+                    if (winAnimator == null) {
+                        dimAnimator.hide(DEFAULT_DIM_DURATION);
+                    } else {
+                        long duration = (winAnimator.mAnimating && winAnimator.mAnimation != null)
+                                ? winAnimator.mAnimation.computeDurationHint()
+                                : DEFAULT_DIM_DURATION;
+                        if (targetAlpha > dimAmount) {
+                            duration = getDimBehindFadeDuration(duration);
+                        }
+                        dimAnimator.show(winAnimator.mAnimLayer -
+                                WindowManagerService.LAYER_OFFSET_DIM, dimAmount, duration);
+                    }
                 }
+                if (dimAnimator.isAnimating()) {
+                    if (!mService.okToDisplay()) {
+                        // Jump to the end of the animation.
+                        dimAnimator.show();
+                    } else {
+                        mAnimating |= dimAnimator.stepAnimation();
+                    }
+                }
+
                 //TODO (multidisplay): Magnification is supported only for the default display.
                 if (mService.mDisplayMagnifier != null && displayId == Display.DEFAULT_DISPLAY) {
                     mService.mDisplayMagnifier.drawMagnifiedRegionBorderIfNeededLocked();
@@ -628,13 +661,18 @@
     }
 
     boolean isDimmingLocked(int displayId) {
-        return getDisplayContentsAnimatorLocked(displayId).mDimParams != null;
+        return getDisplayContentsAnimatorLocked(displayId).mDimAnimator.isDimming();
     }
 
     boolean isDimmingLocked(final WindowStateAnimator winAnimator) {
-        DimAnimator.Parameters dimParams =
-                getDisplayContentsAnimatorLocked(winAnimator.mWin.getDisplayId()).mDimParams;
-        return dimParams != null && dimParams.mDimWinAnimator == winAnimator;
+        final int displayId = winAnimator.mWin.getDisplayId();
+        DisplayContentsAnimator displayAnimator =
+                getDisplayContentsAnimatorLocked(displayId);
+        if (displayAnimator != null) {
+            return displayAnimator.mDimWinAnimator == winAnimator
+                    && displayAnimator.mDimAnimator.isDimming();
+        }
+        return false;
     }
 
     static String bulkUpdateParamsToString(int bulkUpdateParams) {
@@ -675,24 +713,16 @@
                         pw.print(": "); pw.println(wanim);
             }
             if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
-                if (dumpAll || displayAnimator.mWindowAnimationBackgroundSurface.mDimShown) {
+                if (dumpAll || displayAnimator.mWindowAnimationBackgroundSurface.isDimming()) {
                     pw.print(subPrefix); pw.println("mWindowAnimationBackgroundSurface:");
                     displayAnimator.mWindowAnimationBackgroundSurface.printTo(subSubPrefix, pw);
                 }
             }
-            if (displayAnimator.mDimAnimator != null) {
-                if (dumpAll || displayAnimator.mDimAnimator.mDimShown) {
-                    pw.print(subPrefix); pw.println("mDimAnimator:");
-                    displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
-                }
-            } else if (dumpAll) {
-                pw.print(subPrefix); pw.println("no DimAnimator ");
-            }
-            if (displayAnimator.mDimParams != null) {
-                pw.print(subPrefix); pw.println("mDimParams:");
-                displayAnimator.mDimParams.printTo(subSubPrefix, pw);
-            } else if (dumpAll) {
-                pw.print(subPrefix); pw.println("no DimParams ");
+            if (dumpAll || displayAnimator.mDimAnimator.isDimming()) {
+                pw.print(subPrefix); pw.println("mDimAnimator:");
+                displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
+                pw.print(subPrefix); pw.print("mDimWinAnimator=");
+                        pw.println(displayAnimator.mDimWinAnimator);
             }
             if (displayAnimator.mScreenRotationAnimation != null) {
                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
@@ -751,23 +781,18 @@
         }
     }
 
-    void setDimParamsLocked(int displayId, DimAnimator.Parameters dimParams) {
+    void setDimWinAnimatorLocked(int displayId, WindowStateAnimator newWinAnimator) {
         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
-        if (dimParams == null) {
-            displayAnimator.mDimParams = null;
+        if (newWinAnimator == null) {
+            displayAnimator.mDimWinAnimator = null;
         } else {
-            final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
-
             // Only set dim params on the highest dimmed layer.
-            final WindowStateAnimator existingDimWinAnimator =
-                    displayAnimator.mDimParams == null ?
-                            null : displayAnimator.mDimParams.mDimWinAnimator;
-            // Don't turn on for an unshown surface, or for any layer but the highest
-            // dimmed layer.
+            final WindowStateAnimator existingDimWinAnimator = displayAnimator.mDimWinAnimator;
+            // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
             if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
                     || !existingDimWinAnimator.mSurfaceShown
                     || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
-                displayAnimator.mDimParams = new DimAnimator.Parameters(dimParams);
+                displayAnimator.mDimWinAnimator = newWinAnimator;
             }
         }
     }
@@ -790,15 +815,14 @@
     }
 
     private class DisplayContentsAnimator {
-        DimAnimator mDimAnimator = null;
-        DimAnimator.Parameters mDimParams = null;
-        DimSurface mWindowAnimationBackgroundSurface = null;
+        DimLayer mDimAnimator = null;
+        WindowStateAnimator mDimWinAnimator = null;
+        DimLayer mWindowAnimationBackgroundSurface = null;
         ScreenRotationAnimation mScreenRotationAnimation = null;
 
         public DisplayContentsAnimator(int displayId) {
-            mDimAnimator = new DimAnimator(mService.mFxSession, displayId);
-            mWindowAnimationBackgroundSurface = new DimSurface(mService.mFxSession,
-                    mService.getDisplayContentLocked(displayId));
+            mDimAnimator = new DimLayer(mService, displayId);
+            mWindowAnimationBackgroundSurface = new DimLayer(mService, displayId);
         }
     }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index c67a465..220cfd3 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -250,11 +250,6 @@
      */
     static final int MAX_ANIMATION_DURATION = 10*1000;
 
-    /** Amount of time (in milliseconds) to animate the dim surface from one
-     * value to another, when no window animation is driving it.
-     */
-    static final int DEFAULT_DIM_DURATION = 200;
-
     /** Amount of time (in milliseconds) to animate the fade-in-out transition for
      * compatible windows.
      */
@@ -8219,18 +8214,8 @@
             mInnerFields.mDimming = true;
             final WindowStateAnimator winAnimator = w.mWinAnimator;
             if (!mAnimator.isDimmingLocked(winAnimator)) {
-                final int width, height;
-                if (attrs.type == TYPE_BOOT_PROGRESS) {
-                    final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
-                    width = displayInfo.logicalWidth;
-                    height = displayInfo.logicalHeight;
-                } else {
-                    width = innerDw;
-                    height = innerDh;
-                }
                 if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
-                startDimmingLocked(
-                        winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
+                startDimmingLocked(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount);
             }
         }
     }
@@ -8926,14 +8911,12 @@
         }
     }
 
-    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
-                      final int width, final int height) {
-        mAnimator.setDimParamsLocked(winAnimator.mWin.getDisplayId(),
-                new DimAnimator.Parameters(winAnimator, width, height, target));
+    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target) {
+        mAnimator.setDimWinAnimatorLocked(winAnimator.mWin.getDisplayId(), winAnimator);
     }
 
     void stopDimmingLocked(int displayId) {
-        mAnimator.setDimParamsLocked(displayId, null);
+        mAnimator.setDimWinAnimatorLocked(displayId, null);
     }
 
     private boolean needsLayout() {
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 5b7cb99..78b14602 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1183,9 +1183,7 @@
                 mAnimator.setPendingLayoutChanges(displayId,
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
-                    final DisplayInfo displayInfo = mWin.mDisplayContent.getDisplayInfo();
-                    mService.startDimmingLocked(this, w.mExiting ? 0 : w.mAttrs.dimAmount,
-                            displayInfo.appWidth, displayInfo.appHeight);
+                    mService.startDimmingLocked(this, w.mExiting ? 0 : w.mAttrs.dimAmount);
                 }
             } catch (RuntimeException e) {
                 // If something goes wrong with the surface (such