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