DimLayer.java revision 902945d1518a8a3b987dd2afdae790cf942b20ec
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 /** 129 * @param layer The new layer value. 130 * @param inTransaction Whether the call is made within a surface transaction. 131 */ 132 void adjustSurface(int layer, boolean inTransaction) { 133 final int dw, dh; 134 final float xPos, yPos; 135 if (!mStack.isFullscreen()) { 136 dw = mBounds.width(); 137 dh = mBounds.height(); 138 xPos = mBounds.left; 139 yPos = mBounds.top; 140 } else { 141 // Set surface size to screen size. 142 final DisplayInfo info = mDisplayContent.getDisplayInfo(); 143 // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose 144 // a corner. 145 dw = (int) (info.logicalWidth * 1.5); 146 dh = (int) (info.logicalHeight * 1.5); 147 // back off position so 1/4 of Surface is before and 1/4 is after. 148 xPos = -1 * dw / 6; 149 yPos = -1 * dh / 6; 150 } 151 152 try { 153 if (!inTransaction) { 154 SurfaceControl.openTransaction(); 155 } 156 mDimSurface.setPosition(xPos, yPos); 157 mDimSurface.setSize(dw, dh); 158 mDimSurface.setLayer(layer); 159 } catch (RuntimeException e) { 160 Slog.w(TAG, "Failure setting size or layer", e); 161 } finally { 162 if (!inTransaction) { 163 SurfaceControl.closeTransaction(); 164 } 165 } 166 mLastBounds.set(mBounds); 167 mLayer = layer; 168 } 169 170 // Assumes that surface transactions are currently closed. 171 void setBounds(Rect bounds) { 172 mBounds.set(bounds); 173 if (isDimming() && !mLastBounds.equals(bounds)) { 174 adjustSurface(mLayer, false); 175 } 176 } 177 178 /** 179 * @param duration The time to test. 180 * @return True if the duration would lead to an earlier end to the current animation. 181 */ 182 private boolean durationEndsEarlier(long duration) { 183 return SystemClock.uptimeMillis() + duration < mStartTime + mDuration; 184 } 185 186 /** Jump to the end of the animation. 187 * NOTE: Must be called with Surface transaction open. */ 188 void show() { 189 if (isAnimating()) { 190 if (DEBUG) Slog.v(TAG, "show: immediate"); 191 show(mLayer, mTargetAlpha, 0); 192 } 193 } 194 195 /** 196 * Begin an animation to a new dim value. 197 * NOTE: Must be called with Surface transaction open. 198 * 199 * @param layer The layer to set the surface to. 200 * @param alpha The dim value to end at. 201 * @param duration How long to take to get there in milliseconds. 202 */ 203 void show(int layer, float alpha, long duration) { 204 if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha 205 + " duration=" + duration); 206 if (mDimSurface == null) { 207 Slog.e(TAG, "show: no Surface"); 208 // Make sure isAnimating() returns false. 209 mTargetAlpha = mAlpha = 0; 210 return; 211 } 212 213 if (!mLastBounds.equals(mBounds) || mLayer != layer) { 214 adjustSurface(layer, true); 215 } 216 217 long curTime = SystemClock.uptimeMillis(); 218 final boolean animating = isAnimating(); 219 if ((animating && (mTargetAlpha != alpha || durationEndsEarlier(duration))) 220 || (!animating && mAlpha != alpha)) { 221 if (duration <= 0) { 222 // No animation required, just set values. 223 setAlpha(alpha); 224 } else { 225 // Start or continue animation with new parameters. 226 mStartAlpha = mAlpha; 227 mStartTime = curTime; 228 mDuration = duration; 229 } 230 } 231 if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime); 232 mTargetAlpha = alpha; 233 } 234 235 /** Immediate hide. 236 * NOTE: Must be called with Surface transaction open. */ 237 void hide() { 238 if (mShowing) { 239 if (DEBUG) Slog.v(TAG, "hide: immediate"); 240 hide(0); 241 } 242 } 243 244 /** 245 * Gradually fade to transparent. 246 * NOTE: Must be called with Surface transaction open. 247 * 248 * @param duration Time to fade in milliseconds. 249 */ 250 void hide(long duration) { 251 if (mShowing && (mTargetAlpha != 0 || durationEndsEarlier(duration))) { 252 if (DEBUG) Slog.v(TAG, "hide: duration=" + duration); 253 show(mLayer, 0, duration); 254 } 255 } 256 257 /** 258 * Advance the dimming per the last #show(int, float, long) call. 259 * NOTE: Must be called with Surface transaction open. 260 * 261 * @return True if animation is still required after this step. 262 */ 263 boolean stepAnimation() { 264 if (mDimSurface == null) { 265 Slog.e(TAG, "stepAnimation: null Surface"); 266 // Ensure that isAnimating() returns false; 267 mTargetAlpha = mAlpha = 0; 268 return false; 269 } 270 271 if (isAnimating()) { 272 final long curTime = SystemClock.uptimeMillis(); 273 final float alphaDelta = mTargetAlpha - mStartAlpha; 274 float alpha = mStartAlpha + alphaDelta * (curTime - mStartTime) / mDuration; 275 if (alphaDelta > 0 && alpha > mTargetAlpha || 276 alphaDelta < 0 && alpha < mTargetAlpha) { 277 // Don't exceed limits. 278 alpha = mTargetAlpha; 279 } 280 if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha); 281 setAlpha(alpha); 282 } 283 284 return isAnimating(); 285 } 286 287 /** Cleanup */ 288 void destroySurface() { 289 if (DEBUG) Slog.v(TAG, "destroySurface."); 290 if (mDimSurface != null) { 291 mDimSurface.destroy(); 292 mDimSurface = null; 293 } 294 } 295 296 public void printTo(String prefix, PrintWriter pw) { 297 pw.print(prefix); pw.print("mDimSurface="); pw.print(mDimSurface); 298 pw.print(" mLayer="); pw.print(mLayer); 299 pw.print(" mAlpha="); pw.println(mAlpha); 300 pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString()); 301 pw.print(" mBounds="); pw.println(mBounds.toShortString()); 302 pw.print(prefix); pw.print("Last animation: "); 303 pw.print(" mDuration="); pw.print(mDuration); 304 pw.print(" mStartTime="); pw.print(mStartTime); 305 pw.print(" curTime="); pw.println(SystemClock.uptimeMillis()); 306 pw.print(prefix); pw.print(" mStartAlpha="); pw.print(mStartAlpha); 307 pw.print(" mTargetAlpha="); pw.println(mTargetAlpha); 308 } 309} 310