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
17package com.android.systemui.statusbar.phone;
18
19import android.annotation.NonNull;
20import android.content.Context;
21import android.os.Handler;
22import android.util.Log;
23
24import com.android.systemui.doze.DozeHost;
25import com.android.systemui.doze.DozeLog;
26
27/**
28 * Controller which handles all the doze animations of the scrims.
29 */
30public class DozeScrimController {
31    private static final String TAG = "DozeScrimController";
32    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
33
34    private final DozeParameters mDozeParameters;
35    private final Handler mHandler = new Handler();
36    private final ScrimController mScrimController;
37
38    private boolean mDozing;
39    private DozeHost.PulseCallback mPulseCallback;
40    private int mPulseReason;
41    private boolean mFullyPulsing;
42
43    private final ScrimController.Callback mScrimCallback = new ScrimController.Callback() {
44        @Override
45        public void onDisplayBlanked() {
46            if (DEBUG) {
47                Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
48                        + DozeLog.pulseReasonToString(mPulseReason));
49            }
50            if (!mDozing) {
51                return;
52            }
53
54            // Signal that the pulse is ready to turn the screen on and draw.
55            pulseStarted();
56        }
57
58        @Override
59        public void onFinished() {
60            if (DEBUG) {
61                Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
62            }
63            if (!mDozing) {
64                return;
65            }
66            mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
67            mHandler.postDelayed(mPulseOutExtended,
68                    mDozeParameters.getPulseVisibleDurationExtended());
69            mFullyPulsing = true;
70        }
71
72        /**
73         * Transition was aborted before it was over.
74         */
75        @Override
76        public void onCancelled() {
77            pulseFinished();
78        }
79    };
80
81    public DozeScrimController(ScrimController scrimController, Context context,
82            DozeParameters dozeParameters) {
83        mScrimController = scrimController;
84        mDozeParameters = dozeParameters;
85    }
86
87    public void setDozing(boolean dozing) {
88        if (mDozing == dozing) return;
89        mDozing = dozing;
90        if (!mDozing) {
91            cancelPulsing();
92        }
93    }
94
95    /** When dozing, fade screen contents in and out using the front scrim. */
96    public void pulse(@NonNull DozeHost.PulseCallback callback, int reason) {
97        if (callback == null) {
98            throw new IllegalArgumentException("callback must not be null");
99        }
100
101        if (!mDozing || mPulseCallback != null) {
102            if (DEBUG) {
103                Log.d(TAG, "Pulse supressed. Dozing: " + mDozeParameters + " had callback? "
104                        + (mPulseCallback != null));
105            }
106            // Pulse suppressed.
107            callback.onPulseFinished();
108            return;
109        }
110
111        // Begin pulse. Note that it's very important that the pulse finished callback
112        // be invoked when we're done so that the caller can drop the pulse wakelock.
113        mPulseCallback = callback;
114        mPulseReason = reason;
115
116        mScrimController.transitionTo(ScrimState.PULSING, mScrimCallback);
117    }
118
119    public void pulseOutNow() {
120        if (mPulseCallback != null && mFullyPulsing) {
121            mPulseOut.run();
122        }
123    }
124
125    public boolean isPulsing() {
126        return mPulseCallback != null;
127    }
128
129    public boolean isDozing() {
130        return mDozing;
131    }
132
133    public void extendPulse() {
134        mHandler.removeCallbacks(mPulseOut);
135    }
136
137    private void cancelPulsing() {
138        if (mPulseCallback != null) {
139            if (DEBUG) Log.d(TAG, "Cancel pulsing");
140            mFullyPulsing = false;
141            mHandler.removeCallbacks(mPulseOut);
142            mHandler.removeCallbacks(mPulseOutExtended);
143            pulseFinished();
144        }
145    }
146
147    private void pulseStarted() {
148        DozeLog.tracePulseStart(mPulseReason);
149        if (mPulseCallback != null) {
150            mPulseCallback.onPulseStarted();
151        }
152    }
153
154    private void pulseFinished() {
155        DozeLog.tracePulseFinish();
156        if (mPulseCallback != null) {
157            mPulseCallback.onPulseFinished();
158            mPulseCallback = null;
159        }
160    }
161
162    private final Runnable mPulseOutExtended = new Runnable() {
163        @Override
164        public void run() {
165            mHandler.removeCallbacks(mPulseOut);
166            mPulseOut.run();
167        }
168    };
169
170    private final Runnable mPulseOut = new Runnable() {
171        @Override
172        public void run() {
173            mFullyPulsing = false;
174            mHandler.removeCallbacks(mPulseOut);
175            mHandler.removeCallbacks(mPulseOutExtended);
176            if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
177            if (!mDozing) return;
178            mScrimController.transitionTo(ScrimState.AOD,
179                    new ScrimController.Callback() {
180                        @Override
181                        public void onDisplayBlanked() {
182                            pulseFinished();
183                        }
184                    });
185        }
186    };
187}