1 // Copyright 2012 Google Inc. All Rights Reserved. 2 3 package com.android.server.wm; 4 5 import android.graphics.PixelFormat; 6 import android.os.SystemClock; 7 import android.util.Slog; 8 import android.view.DisplayInfo; 9 import android.view.Surface; 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 /** 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); 51 SurfaceControl.openTransaction(); 52 try { 53 if (WindowManagerService.DEBUG_SURFACE_TRACE) { 54 mDimSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession, 55 "DimSurface", 56 16, 16, PixelFormat.OPAQUE, 57 SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN); 58 } else { 59 mDimSurface = new SurfaceControl(service.mFxSession, TAG, 60 16, 16, PixelFormat.OPAQUE, 61 SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN); 62 } 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 { 70 SurfaceControl.closeTransaction(); 71 } 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 88 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 99 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 } 270