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