Home | History | Annotate | Download | only in wm
      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