Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2011 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.content.res.Resources;
     20 import android.graphics.PixelFormat;
     21 import android.util.Slog;
     22 import android.util.TypedValue;
     23 import android.view.Surface;
     24 import android.view.SurfaceSession;
     25 
     26 import java.io.PrintWriter;
     27 
     28 /**
     29  * DimAnimator class that controls the dim animation. This holds the surface and
     30  * all state used for dim animation.
     31  */
     32 class DimAnimator {
     33     static final String TAG = "DimAnimator";
     34 
     35     Surface mDimSurface;
     36     boolean mDimShown = false;
     37     float mDimCurrentAlpha;
     38     float mDimTargetAlpha;
     39     float mDimDeltaPerMs;
     40     long mLastDimAnimTime;
     41 
     42     int mLastDimWidth, mLastDimHeight;
     43 
     44     DimAnimator (SurfaceSession session, final int layerStack) {
     45         try {
     46             if (WindowManagerService.DEBUG_SURFACE_TRACE) {
     47                 mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
     48                     "DimAnimator",
     49                     16, 16, PixelFormat.OPAQUE,
     50                     Surface.FX_SURFACE_DIM | Surface.HIDDEN);
     51             } else {
     52                 mDimSurface = new Surface(session, "DimAnimator",
     53                     16, 16, PixelFormat.OPAQUE,
     54                     Surface.FX_SURFACE_DIM | Surface.HIDDEN);
     55             }
     56             if (WindowManagerService.SHOW_TRANSACTIONS ||
     57                     WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
     58                             "  DIM " + mDimSurface + ": CREATE");
     59             mDimSurface.setLayerStack(layerStack);
     60             mDimSurface.setAlpha(0.0f);
     61             mDimSurface.show();
     62         } catch (Exception e) {
     63             Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
     64         }
     65     }
     66 
     67     /**
     68      * Set's the dim surface's layer and update dim parameters that will be used in
     69      * {@link #updateSurface} after all windows are examined.
     70      */
     71     void updateParameters(final Resources res, final Parameters params, final long currentTime) {
     72         if (mDimSurface == null) {
     73             Slog.e(TAG, "updateParameters: no Surface");
     74             return;
     75         }
     76 
     77         // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
     78         // corner.
     79         final int dw = (int) (params.mDimWidth * 1.5);
     80         final int dh = (int) (params.mDimHeight * 1.5);
     81         final WindowStateAnimator winAnimator = params.mDimWinAnimator;
     82         final float target = params.mDimTarget;
     83         if (!mDimShown) {
     84             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
     85                 "  DIM " + mDimSurface + ": SHOW pos=(0,0) (" + dw + "x" + dh + ")");
     86             mDimShown = true;
     87             try {
     88                 mLastDimWidth = dw;
     89                 mLastDimHeight = dh;
     90                 // back off position so mDimXXX/4 is before and mDimXXX/4 is after
     91                 mDimSurface.setPosition(-1 * dw / 6, -1 * dh /6);
     92                 mDimSurface.setSize(dw, dh);
     93                 mDimSurface.show();
     94             } catch (RuntimeException e) {
     95                 Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
     96             }
     97         } else if (mLastDimWidth != dw || mLastDimHeight != dh) {
     98             mLastDimWidth = dw;
     99             mLastDimHeight = dh;
    100             mDimSurface.setSize(dw, dh);
    101             // back off position so mDimXXX/4 is before and mDimXXX/4 is after
    102             mDimSurface.setPosition(-1 * dw / 6, -1 * dh /6);
    103         }
    104 
    105         mDimSurface.setLayer(winAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
    106 
    107         if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
    108                 + mDimSurface + ": layer=" + (winAnimator.mAnimLayer-1) + " target=" + target);
    109         if (mDimTargetAlpha != target) {
    110             // If the desired dim level has changed, then
    111             // start an animation to it.
    112             mLastDimAnimTime = currentTime;
    113             long duration = (winAnimator.mAnimating && winAnimator.mAnimation != null)
    114                     ? winAnimator.mAnimation.computeDurationHint()
    115                     : WindowManagerService.DEFAULT_DIM_DURATION;
    116             if (target > mDimTargetAlpha) {
    117                 TypedValue tv = new TypedValue();
    118                 res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration,
    119                         tv, true);
    120                 if (tv.type == TypedValue.TYPE_FRACTION) {
    121                     duration = (long)tv.getFraction(duration, duration);
    122                 } else if (tv.type >= TypedValue.TYPE_FIRST_INT
    123                         && tv.type <= TypedValue.TYPE_LAST_INT) {
    124                     duration = tv.data;
    125                 }
    126             }
    127             if (duration < 1) {
    128                 // Don't divide by zero
    129                 duration = 1;
    130             }
    131             mDimTargetAlpha = target;
    132             mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
    133         }
    134     }
    135 
    136     /**
    137      * Updating the surface's alpha. Returns true if the animation continues, or returns
    138      * false when the animation is finished and the dim surface is hidden.
    139      */
    140     boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
    141         if (mDimSurface == null) {
    142             Slog.e(TAG, "updateSurface: no Surface");
    143             return false;
    144         }
    145 
    146         if (!dimming) {
    147             if (mDimTargetAlpha != 0) {
    148                 mLastDimAnimTime = currentTime;
    149                 mDimTargetAlpha = 0;
    150                 mDimDeltaPerMs = (-mDimCurrentAlpha) / WindowManagerService.DEFAULT_DIM_DURATION;
    151             }
    152         }
    153 
    154         boolean animating = mLastDimAnimTime != 0;
    155         if (animating) {
    156             mDimCurrentAlpha += mDimDeltaPerMs
    157                     * (currentTime-mLastDimAnimTime);
    158             if (displayFrozen) {
    159                 // If the display is frozen, there is no reason to animate.
    160                 animating = false;
    161             } else if (mDimDeltaPerMs > 0) {
    162                 if (mDimCurrentAlpha > mDimTargetAlpha) {
    163                     animating = false;
    164                 }
    165             } else if (mDimDeltaPerMs < 0) {
    166                 if (mDimCurrentAlpha < mDimTargetAlpha) {
    167                     animating = false;
    168                 }
    169             } else {
    170                 animating = false;
    171             }
    172 
    173             // Do we need to continue animating?
    174             if (animating) {
    175                 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
    176                         + mDimSurface + ": alpha=" + mDimCurrentAlpha);
    177                 mLastDimAnimTime = currentTime;
    178                 mDimSurface.setAlpha(mDimCurrentAlpha);
    179             } else {
    180                 mDimCurrentAlpha = mDimTargetAlpha;
    181                 mLastDimAnimTime = 0;
    182                 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
    183                         + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
    184                 mDimSurface.setAlpha(mDimCurrentAlpha);
    185                 if (!dimming) {
    186                     if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface
    187                             + ": HIDE");
    188                     try {
    189                         mDimSurface.hide();
    190                     } catch (RuntimeException e) {
    191                         Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
    192                     }
    193                     mDimShown = false;
    194                 }
    195             }
    196         }
    197         return animating;
    198     }
    199 
    200     public void kill() {
    201         if (mDimSurface != null) {
    202             mDimSurface.destroy();
    203             mDimSurface = null;
    204         }
    205     }
    206 
    207     public void printTo(String prefix, PrintWriter pw) {
    208         pw.print(prefix);
    209         pw.print("mDimSurface="); pw.print(mDimSurface);
    210                 pw.print(" "); pw.print(mLastDimWidth); pw.print(" x ");
    211                 pw.println(mLastDimHeight);
    212         pw.print(prefix);
    213         pw.print("mDimShown="); pw.print(mDimShown);
    214         pw.print(" current="); pw.print(mDimCurrentAlpha);
    215         pw.print(" target="); pw.print(mDimTargetAlpha);
    216         pw.print(" delta="); pw.print(mDimDeltaPerMs);
    217         pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
    218     }
    219 
    220     static class Parameters {
    221         final WindowStateAnimator mDimWinAnimator;
    222         final int mDimWidth;
    223         final int mDimHeight;
    224         final float mDimTarget;
    225         Parameters(final WindowStateAnimator dimWinAnimator, final int dimWidth,
    226                 final int dimHeight, final float dimTarget) {
    227             mDimWinAnimator = dimWinAnimator;
    228             mDimWidth = dimWidth;
    229             mDimHeight = dimHeight;
    230             mDimTarget = dimTarget;
    231         }
    232 
    233         Parameters(Parameters o) {
    234             mDimWinAnimator = o.mDimWinAnimator;
    235             mDimWidth = o.mDimWidth;
    236             mDimHeight = o.mDimHeight;
    237             mDimTarget = o.mDimTarget;
    238         }
    239 
    240         public void printTo(String prefix, PrintWriter pw) {
    241             pw.print(prefix);
    242             pw.print("mDimWinAnimator="); pw.print(mDimWinAnimator.mWin.mAttrs.getTitle());
    243                     pw.print(" "); pw.print(mDimWidth); pw.print(" x ");
    244                     pw.print(mDimHeight);
    245             pw.print(" mDimTarget="); pw.println(mDimTarget);
    246         }
    247     }
    248 }
    249