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