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      * NOTE: Must be called with Surface transaction open.
    144      */
    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 */
    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      */
    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. */
    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      */
    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. */
    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      */
    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      */
    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 */
    297     void destroySurface() {
    298         if (DEBUG) Slog.v(TAG, "destroySurface.");
    299         if (mDimSurface != null) {
    300             mDimSurface.destroy();
    301             mDimSurface = null;
    302         }
    303     }
    304 
    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