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