1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import android.graphics.PixelFormat; 20 import android.graphics.Rect; 21 import android.os.SystemClock; 22 import android.util.Slog; 23 import android.view.DisplayInfo; 24 import android.view.SurfaceControl; 25 26 import java.io.PrintWriter; 27 28 public class DimLayer { 29 private static final String TAG = "DimLayer"; 30 private static final boolean DEBUG = false; 31 32 /** Reference to the owner of this object. */ 33 final DisplayContent mDisplayContent; 34 35 /** Actual surface that dims */ 36 SurfaceControl mDimSurface; 37 38 /** Last value passed to mDimSurface.setAlpha() */ 39 float mAlpha = 0; 40 41 /** Last value passed to mDimSurface.setLayer() */ 42 int mLayer = -1; 43 44 /** Next values to pass to mDimSurface.setPosition() and mDimSurface.setSize() */ 45 Rect mBounds = new Rect(); 46 47 /** Last values passed to mDimSurface.setPosition() and mDimSurface.setSize() */ 48 Rect mLastBounds = new Rect(); 49 50 /** True after mDimSurface.show() has been called, false after mDimSurface.hide(). */ 51 private boolean mShowing = false; 52 53 /** Value of mAlpha when beginning transition to mTargetAlpha */ 54 float mStartAlpha = 0; 55 56 /** Final value of mAlpha following transition */ 57 float mTargetAlpha = 0; 58 59 /** Time in units of SystemClock.uptimeMillis() at which the current transition started */ 60 long mStartTime; 61 62 /** Time in milliseconds to take to transition from mStartAlpha to mTargetAlpha */ 63 long mDuration; 64 65 /** Owning stack */ 66 final TaskStack mStack; 67 DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent)68 DimLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) { 69 mStack = stack; 70 mDisplayContent = displayContent; 71 final int displayId = mDisplayContent.getDisplayId(); 72 if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId); 73 SurfaceControl.openTransaction(); 74 try { 75 if (WindowManagerService.DEBUG_SURFACE_TRACE) { 76 mDimSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession, 77 "DimSurface", 78 16, 16, PixelFormat.OPAQUE, 79 SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN); 80 } else { 81 mDimSurface = new SurfaceControl(service.mFxSession, TAG, 82 16, 16, PixelFormat.OPAQUE, 83 SurfaceControl.FX_SURFACE_DIM | SurfaceControl.HIDDEN); 84 } 85 if (WindowManagerService.SHOW_TRANSACTIONS || 86 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(TAG, 87 " DIM " + mDimSurface + ": CREATE"); 88 mDimSurface.setLayerStack(displayId); 89 } catch (Exception e) { 90 Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e); 91 } finally { 92 SurfaceControl.closeTransaction(); 93 } 94 } 95 96 /** Return true if dim layer is showing */ isDimming()97 boolean isDimming() { 98 return mTargetAlpha != 0; 99 } 100 101 /** Return true if in a transition period */ isAnimating()102 boolean isAnimating() { 103 return mTargetAlpha != mAlpha; 104 } 105 getTargetAlpha()106 float getTargetAlpha() { 107 return mTargetAlpha; 108 } 109 setLayer(int layer)110 void setLayer(int layer) { 111 if (mLayer != layer) { 112 mLayer = layer; 113 mDimSurface.setLayer(layer); 114 } 115 } 116 getLayer()117 int getLayer() { 118 return mLayer; 119 } 120 setAlpha(float alpha)121 private void setAlpha(float alpha) { 122 if (mAlpha != alpha) { 123 if (DEBUG) Slog.v(TAG, "setAlpha alpha=" + alpha); 124 try { 125 mDimSurface.setAlpha(alpha); 126 if (alpha == 0 && mShowing) { 127 if (DEBUG) Slog.v(TAG, "setAlpha hiding"); 128 mDimSurface.hide(); 129 mShowing = false; 130 } else if (alpha > 0 && !mShowing) { 131 if (DEBUG) Slog.v(TAG, "setAlpha showing"); 132 mDimSurface.show(); 133 mShowing = true; 134 } 135 } catch (RuntimeException e) { 136 Slog.w(TAG, "Failure setting alpha immediately", e); 137 } 138 mAlpha = alpha; 139 } 140 } 141 142 /** 143 * NOTE: Must be called with Surface transaction open. 144 */ adjustBounds()145 private void adjustBounds() { 146 final int dw, dh; 147 final float xPos, yPos; 148 if (!mStack.isFullscreen()) { 149 dw = mBounds.width(); 150 dh = mBounds.height(); 151 xPos = mBounds.left; 152 yPos = mBounds.top; 153 } else { 154 // Set surface size to screen size. 155 final DisplayInfo info = mDisplayContent.getDisplayInfo(); 156 // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose 157 // a corner. 158 dw = (int) (info.logicalWidth * 1.5); 159 dh = (int) (info.logicalHeight * 1.5); 160 // back off position so 1/4 of Surface is before and 1/4 is after. 161 xPos = -1 * dw / 6; 162 yPos = -1 * dh / 6; 163 } 164 165 mDimSurface.setPosition(xPos, yPos); 166 mDimSurface.setSize(dw, dh); 167 168 mLastBounds.set(mBounds); 169 } 170 171 /** @param bounds The new bounds to set */ setBounds(Rect bounds)172 void setBounds(Rect bounds) { 173 mBounds.set(bounds); 174 if (isDimming() && !mLastBounds.equals(bounds)) { 175 try { 176 SurfaceControl.openTransaction(); 177 adjustBounds(); 178 } catch (RuntimeException e) { 179 Slog.w(TAG, "Failure setting size", e); 180 } finally { 181 SurfaceControl.closeTransaction(); 182 } 183 } 184 } 185 186 /** 187 * @param duration The time to test. 188 * @return True if the duration would lead to an earlier end to the current animation. 189 */ durationEndsEarlier(long duration)190 private boolean durationEndsEarlier(long duration) { 191 return SystemClock.uptimeMillis() + duration < mStartTime + mDuration; 192 } 193 194 /** Jump to the end of the animation. 195 * NOTE: Must be called with Surface transaction open. */ show()196 void show() { 197 if (isAnimating()) { 198 if (DEBUG) Slog.v(TAG, "show: immediate"); 199 show(mLayer, mTargetAlpha, 0); 200 } 201 } 202 203 /** 204 * Begin an animation to a new dim value. 205 * NOTE: Must be called with Surface transaction open. 206 * 207 * @param layer The layer to set the surface to. 208 * @param alpha The dim value to end at. 209 * @param duration How long to take to get there in milliseconds. 210 */ show(int layer, float alpha, long duration)211 void show(int layer, float alpha, long duration) { 212 if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " alpha=" + alpha 213 + " duration=" + duration); 214 if (mDimSurface == null) { 215 Slog.e(TAG, "show: no Surface"); 216 // Make sure isAnimating() returns false. 217 mTargetAlpha = mAlpha = 0; 218 return; 219 } 220 221 if (!mLastBounds.equals(mBounds)) { 222 adjustBounds(); 223 } 224 setLayer(layer); 225 226 long curTime = SystemClock.uptimeMillis(); 227 final boolean animating = isAnimating(); 228 if ((animating && (mTargetAlpha != alpha || durationEndsEarlier(duration))) 229 || (!animating && mAlpha != alpha)) { 230 if (duration <= 0) { 231 // No animation required, just set values. 232 setAlpha(alpha); 233 } else { 234 // Start or continue animation with new parameters. 235 mStartAlpha = mAlpha; 236 mStartTime = curTime; 237 mDuration = duration; 238 } 239 } 240 if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime); 241 mTargetAlpha = alpha; 242 } 243 244 /** Immediate hide. 245 * NOTE: Must be called with Surface transaction open. */ hide()246 void hide() { 247 if (mShowing) { 248 if (DEBUG) Slog.v(TAG, "hide: immediate"); 249 hide(0); 250 } 251 } 252 253 /** 254 * Gradually fade to transparent. 255 * NOTE: Must be called with Surface transaction open. 256 * 257 * @param duration Time to fade in milliseconds. 258 */ hide(long duration)259 void hide(long duration) { 260 if (mShowing && (mTargetAlpha != 0 || durationEndsEarlier(duration))) { 261 if (DEBUG) Slog.v(TAG, "hide: duration=" + duration); 262 show(mLayer, 0, duration); 263 } 264 } 265 266 /** 267 * Advance the dimming per the last #show(int, float, long) call. 268 * NOTE: Must be called with Surface transaction open. 269 * 270 * @return True if animation is still required after this step. 271 */ stepAnimation()272 boolean stepAnimation() { 273 if (mDimSurface == null) { 274 Slog.e(TAG, "stepAnimation: null Surface"); 275 // Ensure that isAnimating() returns false; 276 mTargetAlpha = mAlpha = 0; 277 return false; 278 } 279 280 if (isAnimating()) { 281 final long curTime = SystemClock.uptimeMillis(); 282 final float alphaDelta = mTargetAlpha - mStartAlpha; 283 float alpha = mStartAlpha + alphaDelta * (curTime - mStartTime) / mDuration; 284 if (alphaDelta > 0 && alpha > mTargetAlpha || 285 alphaDelta < 0 && alpha < mTargetAlpha) { 286 // Don't exceed limits. 287 alpha = mTargetAlpha; 288 } 289 if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " alpha=" + alpha); 290 setAlpha(alpha); 291 } 292 293 return isAnimating(); 294 } 295 296 /** Cleanup */ destroySurface()297 void destroySurface() { 298 if (DEBUG) Slog.v(TAG, "destroySurface."); 299 if (mDimSurface != null) { 300 mDimSurface.destroy(); 301 mDimSurface = null; 302 } 303 } 304 printTo(String prefix, PrintWriter pw)305 public void printTo(String prefix, PrintWriter pw) { 306 pw.print(prefix); pw.print("mDimSurface="); pw.print(mDimSurface); 307 pw.print(" mLayer="); pw.print(mLayer); 308 pw.print(" mAlpha="); pw.println(mAlpha); 309 pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString()); 310 pw.print(" mBounds="); pw.println(mBounds.toShortString()); 311 pw.print(prefix); pw.print("Last animation: "); 312 pw.print(" mDuration="); pw.print(mDuration); 313 pw.print(" mStartTime="); pw.print(mStartTime); 314 pw.print(" curTime="); pw.println(SystemClock.uptimeMillis()); 315 pw.print(prefix); pw.print(" mStartAlpha="); pw.print(mStartAlpha); 316 pw.print(" mTargetAlpha="); pw.println(mTargetAlpha); 317 } 318 } 319