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 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 */ 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 } 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 */ 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. */ 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 */ 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. */ 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 */ 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 */ 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 */ 269 void destroySurface() { 270 if (DEBUG) Slog.v(TAG, "destroySurface."); 271 if (mDimSurface != null) { 272 mDimSurface.destroy(); 273 mDimSurface = null; 274 } 275 } 276 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