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) {
43        if (mDimSurface == null) {
44            if (WindowManagerService.SHOW_TRANSACTIONS ||
45                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
46                            "  DIM " + mDimSurface + ": CREATE");
47            try {
48                mDimSurface = new Surface(session, 0,
49                        "DimAnimator",
50                        -1, 16, 16, PixelFormat.OPAQUE,
51                        Surface.FX_SURFACE_DIM);
52                mDimSurface.setAlpha(0.0f);
53            } catch (Exception e) {
54                Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
55            }
56        }
57    }
58
59    /**
60     * Show the dim surface.
61     */
62    void show(int dw, int dh) {
63        if (!mDimShown) {
64            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
65                    dw + "x" + dh + ")");
66            mDimShown = true;
67            try {
68                mLastDimWidth = dw;
69                mLastDimHeight = dh;
70                mDimSurface.setPosition(0, 0);
71                mDimSurface.setSize(dw, dh);
72                mDimSurface.show();
73            } catch (RuntimeException e) {
74                Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
75            }
76        } else if (mLastDimWidth != dw || mLastDimHeight != dh) {
77            mLastDimWidth = dw;
78            mLastDimHeight = dh;
79            mDimSurface.setSize(dw, dh);
80        }
81    }
82
83    /**
84     * Set's the dim surface's layer and update dim parameters that will be used in
85     * {@link updateSurface} after all windows are examined.
86     */
87    void updateParameters(Resources res, WindowState w, long currentTime) {
88        mDimSurface.setLayer(w.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
89
90        final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
91        if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface
92                + ": layer=" + (w.mAnimLayer-1) + " target=" + target);
93        if (mDimTargetAlpha != target) {
94            // If the desired dim level has changed, then
95            // start an animation to it.
96            mLastDimAnimTime = currentTime;
97            long duration = (w.mAnimating && w.mAnimation != null)
98                    ? w.mAnimation.computeDurationHint()
99                    : WindowManagerService.DEFAULT_DIM_DURATION;
100            if (target > mDimTargetAlpha) {
101                TypedValue tv = new TypedValue();
102                res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration,
103                        tv, true);
104                if (tv.type == TypedValue.TYPE_FRACTION) {
105                    duration = (long)tv.getFraction((float)duration, (float)duration);
106                } else if (tv.type >= TypedValue.TYPE_FIRST_INT
107                        && tv.type <= TypedValue.TYPE_LAST_INT) {
108                    duration = tv.data;
109                }
110            }
111            if (duration < 1) {
112                // Don't divide by zero
113                duration = 1;
114            }
115            mDimTargetAlpha = target;
116            mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
117        }
118    }
119
120    /**
121     * Updating the surface's alpha. Returns true if the animation continues, or returns
122     * false when the animation is finished and the dim surface is hidden.
123     */
124    boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
125        if (!dimming) {
126            if (mDimTargetAlpha != 0) {
127                mLastDimAnimTime = currentTime;
128                mDimTargetAlpha = 0;
129                mDimDeltaPerMs = (-mDimCurrentAlpha) / WindowManagerService.DEFAULT_DIM_DURATION;
130            }
131        }
132
133        boolean animating = false;
134        if (mLastDimAnimTime != 0) {
135            mDimCurrentAlpha += mDimDeltaPerMs
136                    * (currentTime-mLastDimAnimTime);
137            boolean more = true;
138            if (displayFrozen) {
139                // If the display is frozen, there is no reason to animate.
140                more = false;
141            } else if (mDimDeltaPerMs > 0) {
142                if (mDimCurrentAlpha > mDimTargetAlpha) {
143                    more = false;
144                }
145            } else if (mDimDeltaPerMs < 0) {
146                if (mDimCurrentAlpha < mDimTargetAlpha) {
147                    more = false;
148                }
149            } else {
150                more = false;
151            }
152
153            // Do we need to continue animating?
154            if (more) {
155                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
156                        + mDimSurface + ": alpha=" + mDimCurrentAlpha);
157                mLastDimAnimTime = currentTime;
158                mDimSurface.setAlpha(mDimCurrentAlpha);
159                animating = true;
160            } else {
161                mDimCurrentAlpha = mDimTargetAlpha;
162                mLastDimAnimTime = 0;
163                if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM "
164                        + mDimSurface + ": final alpha=" + mDimCurrentAlpha);
165                mDimSurface.setAlpha(mDimCurrentAlpha);
166                if (!dimming) {
167                    if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, "  DIM " + mDimSurface
168                            + ": HIDE");
169                    try {
170                        mDimSurface.hide();
171                    } catch (RuntimeException e) {
172                        Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
173                    }
174                    mDimShown = false;
175                }
176            }
177        }
178        return animating;
179    }
180
181    public void printTo(String prefix, PrintWriter pw) {
182        pw.print(prefix);
183        pw.print("mDimSurface="); pw.print(mDimSurface);
184                pw.print(" "); pw.print(mLastDimWidth); pw.print(" x ");
185                pw.println(mLastDimHeight);
186        pw.print(prefix);
187        pw.print("mDimShown="); pw.print(mDimShown);
188        pw.print(" current="); pw.print(mDimCurrentAlpha);
189        pw.print(" target="); pw.print(mDimTargetAlpha);
190        pw.print(" delta="); pw.print(mDimDeltaPerMs);
191        pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
192    }
193}