• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 
3 package com.android.server.wm;
4 
5 import android.graphics.PixelFormat;
6 import android.graphics.Rect;
7 import android.os.SystemClock;
8 import android.util.Slog;
9 import android.view.DisplayInfo;
10 import android.view.SurfaceControl;
11 
12 import java.io.PrintWriter;
13 
14 public 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 
DimLayer(WindowManagerService service, TaskStack stack)54     DimLayer(WindowManagerService service, TaskStack stack) {
55         mStack = stack;
56         mDisplayContent = stack.getDisplayContent();
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 */
isDimming()83     boolean isDimming() {
84         return mTargetAlpha != 0;
85     }
86 
87     /** Return true if in a transition period */
isAnimating()88     boolean isAnimating() {
89         return mTargetAlpha != mAlpha;
90     }
91 
getTargetAlpha()92     float getTargetAlpha() {
93         return mTargetAlpha;
94     }
95 
setLayer(int layer)96     void setLayer(int layer) {
97         if (mLayer != layer) {
98             mLayer = layer;
99             mDimSurface.setLayer(layer);
100         }
101     }
102 
getLayer()103     int getLayer() {
104         return mLayer;
105     }
106 
setAlpha(float alpha)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 
setBounds(Rect bounds)128     void setBounds(Rect bounds) {
129         mBounds.set(bounds);
130     }
131 
132     /**
133      * @param duration The time to test.
134      * @return True if the duration would lead to an earlier end to the current animation.
135      */
durationEndsEarlier(long duration)136     private boolean durationEndsEarlier(long duration) {
137         return SystemClock.uptimeMillis() + duration < mStartTime + mDuration;
138     }
139 
140     /** Jump to the end of the animation.
141      * NOTE: Must be called with Surface transaction open. */
show()142     void show() {
143         if (isAnimating()) {
144             if (DEBUG) Slog.v(TAG, "show: immediate");
145             show(mLayer, mTargetAlpha, 0);
146         }
147     }
148 
149     /**
150      * Begin an animation to a new dim value.
151      * NOTE: Must be called with Surface transaction open.
152      *
153      * @param layer The layer to set the surface to.
154      * @param alpha The dim value to end at.
155      * @param duration How long to take to get there in milliseconds.
156      */
show(int layer, float alpha, long duration)157     void show(int layer, float alpha, long duration) {
158         if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha
159                 + " duration=" + duration);
160         if (mDimSurface == null) {
161             Slog.e(TAG, "show: no Surface");
162             // Make sure isAnimating() returns false.
163             mTargetAlpha = mAlpha = 0;
164             return;
165         }
166 
167         final int dw, dh;
168         final float xPos, yPos;
169         if (mStack.hasSibling()) {
170             dw = mBounds.width();
171             dh = mBounds.height();
172             xPos = mBounds.left;
173             yPos = mBounds.right;
174         } else {
175             // Set surface size to screen size.
176             final DisplayInfo info = mDisplayContent.getDisplayInfo();
177             // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
178             // corner.
179             dw = (int) (info.logicalWidth * 1.5);
180             dh = (int) (info.logicalHeight * 1.5);
181             // back off position so 1/4 of Surface is before and 1/4 is after.
182             xPos = -1 * dw / 6;
183             yPos = -1 * dh / 6;
184         }
185 
186         if (!mLastBounds.equals(mBounds) || mLayer != layer) {
187             try {
188                 mDimSurface.setPosition(xPos, yPos);
189                 mDimSurface.setSize(dw, dh);
190                 mDimSurface.setLayer(layer);
191             } catch (RuntimeException e) {
192                 Slog.w(TAG, "Failure setting size or layer", e);
193             }
194             mLastBounds.set(mBounds);
195             mLayer = layer;
196         }
197 
198         long curTime = SystemClock.uptimeMillis();
199         final boolean animating = isAnimating();
200         if ((animating && (mTargetAlpha != alpha || durationEndsEarlier(duration)))
201                 || (!animating && mAlpha != alpha)) {
202             if (duration <= 0) {
203                 // No animation required, just set values.
204                 setAlpha(alpha);
205             } else {
206                 // Start or continue animation with new parameters.
207                 mStartAlpha = mAlpha;
208                 mStartTime = curTime;
209                 mDuration = duration;
210             }
211         }
212         if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime);
213         mTargetAlpha = alpha;
214     }
215 
216     /** Immediate hide.
217      * NOTE: Must be called with Surface transaction open. */
hide()218     void hide() {
219         if (mShowing) {
220             if (DEBUG) Slog.v(TAG, "hide: immediate");
221             hide(0);
222         }
223     }
224 
225     /**
226      * Gradually fade to transparent.
227      * NOTE: Must be called with Surface transaction open.
228      *
229      * @param duration Time to fade in milliseconds.
230      */
hide(long duration)231     void hide(long duration) {
232         if (mShowing && (mTargetAlpha != 0 || durationEndsEarlier(duration))) {
233             if (DEBUG) Slog.v(TAG, "hide: duration=" + duration);
234             show(mLayer, 0, duration);
235         }
236     }
237 
238     /**
239      * Advance the dimming per the last #show(int, float, long) call.
240      * NOTE: Must be called with Surface transaction open.
241      *
242      * @return True if animation is still required after this step.
243      */
stepAnimation()244     boolean stepAnimation() {
245         if (mDimSurface == null) {
246             Slog.e(TAG, "stepAnimation: null Surface");
247             // Ensure that isAnimating() returns false;
248             mTargetAlpha = mAlpha = 0;
249             return false;
250         }
251 
252         if (isAnimating()) {
253             final long curTime = SystemClock.uptimeMillis();
254             final float alphaDelta = mTargetAlpha - mStartAlpha;
255             float alpha = mStartAlpha + alphaDelta * (curTime - mStartTime) / mDuration;
256             if (alphaDelta > 0 && alpha > mTargetAlpha ||
257                     alphaDelta < 0 && alpha < mTargetAlpha) {
258                 // Don't exceed limits.
259                 alpha = mTargetAlpha;
260             }
261             if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha);
262             setAlpha(alpha);
263         }
264 
265         return isAnimating();
266     }
267 
268     /** Cleanup */
destroySurface()269     void destroySurface() {
270         if (DEBUG) Slog.v(TAG, "destroySurface.");
271         if (mDimSurface != null) {
272             mDimSurface.destroy();
273             mDimSurface = null;
274         }
275     }
276 
printTo(String prefix, PrintWriter pw)277     public void printTo(String prefix, PrintWriter pw) {
278         pw.print(prefix); pw.print("mDimSurface="); pw.print(mDimSurface);
279                 pw.print(" mLayer="); pw.print(mLayer);
280                 pw.print(" mAlpha="); pw.println(mAlpha);
281         pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString());
282                 pw.print(" mBounds="); pw.println(mBounds.toShortString());
283         pw.print(prefix); pw.print("Last animation: ");
284                 pw.print(" mDuration="); pw.print(mDuration);
285                 pw.print(" mStartTime="); pw.print(mStartTime);
286                 pw.print(" curTime="); pw.println(SystemClock.uptimeMillis());
287         pw.print(prefix); pw.print(" mStartAlpha="); pw.print(mStartAlpha);
288                 pw.print(" mTargetAlpha="); pw.println(mTargetAlpha);
289     }
290 }
291