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