DimLayer.java revision b660b9d8cf6b951b85a35599d636c470795e9a1a
1// Copyright 2012 Google Inc. All Rights Reserved.
2
3package com.android.server.wm;
4
5import android.graphics.PixelFormat;
6import android.graphics.Rect;
7import android.os.SystemClock;
8import android.util.Slog;
9import android.view.DisplayInfo;
10import android.view.SurfaceControl;
11
12import java.io.PrintWriter;
13
14public class DimLayer {
15    private static final String TAG = "DimLayer";
16    private static final boolean DEBUG = false;
17
18    /** Reference to the owner of this object. */
19    final DisplayContent mDisplayContent;
20
21    /** Actual surface that dims */
22    SurfaceControl mDimSurface;
23
24    /** Last value passed to mDimSurface.setAlpha() */
25    float mAlpha = 0;
26
27    /** Last value passed to mDimSurface.setLayer() */
28    int mLayer = -1;
29
30    /** Next values to pass to mDimSurface.setPosition() and mDimSurface.setSize() */
31    Rect mBounds = new Rect();
32
33    /** Last values passed to mDimSurface.setPosition() and mDimSurface.setSize() */
34    Rect mLastBounds = new Rect();
35
36    /** True after mDimSurface.show() has been called, false after mDimSurface.hide(). */
37    private boolean mShowing = false;
38
39    /** Value of mAlpha when beginning transition to mTargetAlpha */
40    float mStartAlpha = 0;
41
42    /** Final value of mAlpha following transition */
43    float mTargetAlpha = 0;
44
45    /** Time in units of SystemClock.uptimeMillis() at which the current transition started */
46    long mStartTime;
47
48    /** Time in milliseconds to take to transition from mStartAlpha to mTargetAlpha */
49    long mDuration;
50
51    /** Owning stack */
52    final TaskStack mStack;
53
54    DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) {
55        mStack = stack;
56        mDisplayContent = displayContent;
57        final int displayId = mDisplayContent.getDisplayId();
58        if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
59        SurfaceControl.openTransaction();
60        try {
61            if (WindowManagerService.DEBUG_SURFACE_TRACE) {
62                mDimSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession,
63                    "DimSurface",
64                    16, 16, PixelFormat.OPAQUE,
65                    SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
66            } else {
67                mDimSurface = new SurfaceControl(service.mFxSession, TAG,
68                    16, 16, PixelFormat.OPAQUE,
69                    SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN);
70            }
71            if (WindowManagerService.SHOW_TRANSACTIONS ||
72                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(TAG,
73                            "  DIM " + mDimSurface + ": CREATE");
74            mDimSurface.setLayerStack(displayId);
75        } catch (Exception e) {
76            Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
77        } finally {
78            SurfaceControl.closeTransaction();
79        }
80    }
81
82    /** Return true if dim layer is showing */
83    boolean isDimming() {
84        return mTargetAlpha != 0;
85    }
86
87    /** Return true if in a transition period */
88    boolean isAnimating() {
89        return mTargetAlpha != mAlpha;
90    }
91
92    float getTargetAlpha() {
93        return mTargetAlpha;
94    }
95
96    void setLayer(int layer) {
97        if (mLayer != layer) {
98            mLayer = layer;
99            mDimSurface.setLayer(layer);
100        }
101    }
102
103    int getLayer() {
104        return mLayer;
105    }
106
107    private void setAlpha(float alpha) {
108        if (mAlpha != alpha) {
109            if (DEBUG) Slog.v(TAG, "setAlpha alpha=" + alpha);
110            try {
111                mDimSurface.setAlpha(alpha);
112                if (alpha == 0 && mShowing) {
113                    if (DEBUG) Slog.v(TAG, "setAlpha hiding");
114                    mDimSurface.hide();
115                    mShowing = false;
116                } else if (alpha > 0 && !mShowing) {
117                    if (DEBUG) Slog.v(TAG, "setAlpha showing");
118                    mDimSurface.show();
119                    mShowing = true;
120                }
121            } catch (RuntimeException e) {
122                Slog.w(TAG, "Failure setting alpha immediately", e);
123            }
124            mAlpha = alpha;
125        }
126    }
127
128    void setBounds(Rect bounds) {
129        mBounds.set(bounds);
130        if (isDimming() && !mLastBounds.equals(bounds)) {
131            // Clearing mAlpha forces show to redisplay with new size.
132            mAlpha = 0;
133            show();
134        }
135    }
136
137    /**
138     * @param duration The time to test.
139     * @return True if the duration would lead to an earlier end to the current animation.
140     */
141    private boolean durationEndsEarlier(long duration) {
142        return SystemClock.uptimeMillis() + duration < mStartTime + mDuration;
143    }
144
145    /** Jump to the end of the animation.
146     * NOTE: Must be called with Surface transaction open. */
147    void show() {
148        if (isAnimating()) {
149            if (DEBUG) Slog.v(TAG, "show: immediate");
150            show(mLayer, mTargetAlpha, 0);
151        }
152    }
153
154    /**
155     * Begin an animation to a new dim value.
156     * NOTE: Must be called with Surface transaction open.
157     *
158     * @param layer The layer to set the surface to.
159     * @param alpha The dim value to end at.
160     * @param duration How long to take to get there in milliseconds.
161     */
162    void show(int layer, float alpha, long duration) {
163        if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha
164                + " duration=" + duration);
165        if (mDimSurface == null) {
166            Slog.e(TAG, "show: no Surface");
167            // Make sure isAnimating() returns false.
168            mTargetAlpha = mAlpha = 0;
169            return;
170        }
171
172        final int dw, dh;
173        final float xPos, yPos;
174        if (!mStack.isFullscreen()) {
175            dw = mBounds.width();
176            dh = mBounds.height();
177            xPos = mBounds.left;
178            yPos = mBounds.top;
179        } else {
180            // Set surface size to screen size.
181            final DisplayInfo info = mDisplayContent.getDisplayInfo();
182            // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
183            // corner.
184            dw = (int) (info.logicalWidth * 1.5);
185            dh = (int) (info.logicalHeight * 1.5);
186            // back off position so 1/4 of Surface is before and 1/4 is after.
187            xPos = -1 * dw / 6;
188            yPos = -1 * dh / 6;
189        }
190
191        if (!mLastBounds.equals(mBounds) || mLayer != layer) {
192            try {
193                mDimSurface.setPosition(xPos, yPos);
194                mDimSurface.setSize(dw, dh);
195                mDimSurface.setLayer(layer);
196            } catch (RuntimeException e) {
197                Slog.w(TAG, "Failure setting size or layer", e);
198            }
199            mLastBounds.set(mBounds);
200            mLayer = layer;
201        }
202
203        long curTime = SystemClock.uptimeMillis();
204        final boolean animating = isAnimating();
205        if ((animating && (mTargetAlpha != alpha || durationEndsEarlier(duration)))
206                || (!animating && mAlpha != alpha)) {
207            if (duration <= 0) {
208                // No animation required, just set values.
209                setAlpha(alpha);
210            } else {
211                // Start or continue animation with new parameters.
212                mStartAlpha = mAlpha;
213                mStartTime = curTime;
214                mDuration = duration;
215            }
216        }
217        if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime);
218        mTargetAlpha = alpha;
219    }
220
221    /** Immediate hide.
222     * NOTE: Must be called with Surface transaction open. */
223    void hide() {
224        if (mShowing) {
225            if (DEBUG) Slog.v(TAG, "hide: immediate");
226            hide(0);
227        }
228    }
229
230    /**
231     * Gradually fade to transparent.
232     * NOTE: Must be called with Surface transaction open.
233     *
234     * @param duration Time to fade in milliseconds.
235     */
236    void hide(long duration) {
237        if (mShowing && (mTargetAlpha != 0 || durationEndsEarlier(duration))) {
238            if (DEBUG) Slog.v(TAG, "hide: duration=" + duration);
239            show(mLayer, 0, duration);
240        }
241    }
242
243    /**
244     * Advance the dimming per the last #show(int, float, long) call.
245     * NOTE: Must be called with Surface transaction open.
246     *
247     * @return True if animation is still required after this step.
248     */
249    boolean stepAnimation() {
250        if (mDimSurface == null) {
251            Slog.e(TAG, "stepAnimation: null Surface");
252            // Ensure that isAnimating() returns false;
253            mTargetAlpha = mAlpha = 0;
254            return false;
255        }
256
257        if (isAnimating()) {
258            final long curTime = SystemClock.uptimeMillis();
259            final float alphaDelta = mTargetAlpha - mStartAlpha;
260            float alpha = mStartAlpha + alphaDelta * (curTime - mStartTime) / mDuration;
261            if (alphaDelta > 0 && alpha > mTargetAlpha ||
262                    alphaDelta < 0 && alpha < mTargetAlpha) {
263                // Don't exceed limits.
264                alpha = mTargetAlpha;
265            }
266            if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha);
267            setAlpha(alpha);
268        }
269
270        return isAnimating();
271    }
272
273    /** Cleanup */
274    void destroySurface() {
275        if (DEBUG) Slog.v(TAG, "destroySurface.");
276        if (mDimSurface != null) {
277            mDimSurface.destroy();
278            mDimSurface = null;
279        }
280    }
281
282    public void printTo(String prefix, PrintWriter pw) {
283        pw.print(prefix); pw.print("mDimSurface="); pw.print(mDimSurface);
284                pw.print(" mLayer="); pw.print(mLayer);
285                pw.print(" mAlpha="); pw.println(mAlpha);
286        pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString());
287                pw.print(" mBounds="); pw.println(mBounds.toShortString());
288        pw.print(prefix); pw.print("Last animation: ");
289                pw.print(" mDuration="); pw.print(mDuration);
290                pw.print(" mStartTime="); pw.print(mStartTime);
291                pw.print(" curTime="); pw.println(SystemClock.uptimeMillis());
292        pw.print(prefix); pw.print(" mStartAlpha="); pw.print(mStartAlpha);
293                pw.print(" mTargetAlpha="); pw.println(mTargetAlpha);
294    }
295}
296