blob: f0eeb046bc44e7ad78c262a40396de3d95f2476c [file] [log] [blame]
Jason Monk1fd3fc32018-08-14 17:20:09 -04001/*
Beverly8fdb5332019-02-04 14:29:49 -05002 * Copyright (C) 2019 The Android Open Source Project
Jason Monk1fd3fc32018-08-14 17:20:09 -04003 *
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
Beverly8fdb5332019-02-04 14:29:49 -050014 * limitations under the License.
Jason Monk1fd3fc32018-08-14 17:20:09 -040015 */
16
17package com.android.systemui.statusbar;
18
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080019import android.animation.ObjectAnimator;
20import android.animation.ValueAnimator;
Evan Laird2ce144e2019-03-04 18:45:34 -050021import android.text.format.DateFormat;
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080022import android.util.FloatProperty;
Beverlye14f08e2019-06-06 15:33:10 -040023import android.view.View;
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080024import android.view.animation.Interpolator;
25
Evan Laird91d0f102018-09-18 17:39:55 -040026import com.android.internal.annotations.GuardedBy;
Evan Laird2ce144e2019-03-04 18:45:34 -050027import com.android.systemui.Dumpable;
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080028import com.android.systemui.Interpolators;
Beverly8fdb5332019-02-04 14:29:49 -050029import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080030import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
Jason Monkaf08c152018-12-04 11:12:39 -050031import com.android.systemui.statusbar.policy.CallbackController;
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080032
Evan Laird2ce144e2019-03-04 18:45:34 -050033import java.io.FileDescriptor;
34import java.io.PrintWriter;
Evan Laird91d0f102018-09-18 17:39:55 -040035import java.util.ArrayList;
36import java.util.Comparator;
Jason Monk1fd3fc32018-08-14 17:20:09 -040037
Jason Monk27d01a622018-12-10 15:57:09 -050038import javax.inject.Inject;
39import javax.inject.Singleton;
40
Jason Monk1fd3fc32018-08-14 17:20:09 -040041/**
42 * Tracks and reports on {@link StatusBarState}.
43 */
Jason Monk27d01a622018-12-10 15:57:09 -050044@Singleton
Beverly8fdb5332019-02-04 14:29:49 -050045public class StatusBarStateControllerImpl implements SysuiStatusBarStateController,
Evan Laird2ce144e2019-03-04 18:45:34 -050046 CallbackController<StateListener>, Dumpable {
Evan Laird91d0f102018-09-18 17:39:55 -040047 private static final String TAG = "SbStateController";
Evan Laird2ce144e2019-03-04 18:45:34 -050048 // Must be a power of 2
49 private static final int HISTORY_SIZE = 32;
Jason Monk1fd3fc32018-08-14 17:20:09 -040050
51 private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER;
52 private static final int MIN_STATE = StatusBarState.SHADE;
53
Beverly8fdb5332019-02-04 14:29:49 -050054 private static final Comparator<RankedListener> sComparator =
55 Comparator.comparingInt(o -> o.mRank);
56 private static final FloatProperty<StatusBarStateControllerImpl> SET_DARK_AMOUNT_PROPERTY =
57 new FloatProperty<StatusBarStateControllerImpl>("mDozeAmount") {
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080058
59 @Override
Beverly8fdb5332019-02-04 14:29:49 -050060 public void setValue(StatusBarStateControllerImpl object, float value) {
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080061 object.setDozeAmountInternal(value);
62 }
63
64 @Override
Beverly8fdb5332019-02-04 14:29:49 -050065 public Float get(StatusBarStateControllerImpl object) {
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080066 return object.mDozeAmount;
67 }
68 };
Evan Laird91d0f102018-09-18 17:39:55 -040069
70 private final ArrayList<RankedListener> mListeners = new ArrayList<>();
Jason Monk1fd3fc32018-08-14 17:20:09 -040071 private int mState;
72 private int mLastState;
73 private boolean mLeaveOpenOnKeyguardHide;
Jason Monk297c04e2018-08-23 17:16:59 -040074 private boolean mKeyguardRequested;
Jason Monk1fd3fc32018-08-14 17:20:09 -040075
Evan Laird2ce144e2019-03-04 18:45:34 -050076 // Record the HISTORY_SIZE most recent states
77 private int mHistoryIndex = 0;
78 private HistoricalState[] mHistoricalRecords = new HistoricalState[HISTORY_SIZE];
79
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080080 /**
Beverlye14f08e2019-06-06 15:33:10 -040081 * Current SystemUiVisibility
82 */
83 private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
84
85 /**
86 * If the device is currently pulsing (AOD2).
87 */
88 private boolean mPulsing;
89
90 /**
Lucas Dupin1a8b33d2018-11-12 18:18:15 -080091 * If the device is currently dozing or not.
92 */
93 private boolean mIsDozing;
94
95 /**
96 * Current {@link #mDozeAmount} animator.
97 */
98 private ValueAnimator mDarkAnimator;
99
100 /**
101 * Current doze amount in this frame.
102 */
103 private float mDozeAmount;
104
105 /**
106 * Where the animator will stop.
107 */
108 private float mDozeAmountTarget;
109
110 /**
111 * The type of interpolator that should be used to the doze animation.
112 */
113 private Interpolator mDozeInterpolator = Interpolators.FAST_OUT_SLOW_IN;
114
Jason Monk27d01a622018-12-10 15:57:09 -0500115 @Inject
Beverly8fdb5332019-02-04 14:29:49 -0500116 public StatusBarStateControllerImpl() {
Evan Laird2ce144e2019-03-04 18:45:34 -0500117 for (int i = 0; i < HISTORY_SIZE; i++) {
118 mHistoricalRecords[i] = new HistoricalState();
119 }
Jason Monk27d01a622018-12-10 15:57:09 -0500120 }
121
Beverly8fdb5332019-02-04 14:29:49 -0500122 @Override
Jason Monk1fd3fc32018-08-14 17:20:09 -0400123 public int getState() {
124 return mState;
125 }
126
Beverly8fdb5332019-02-04 14:29:49 -0500127 @Override
Evan Laird91d0f102018-09-18 17:39:55 -0400128 public boolean setState(int state) {
Jason Monk1fd3fc32018-08-14 17:20:09 -0400129 if (state > MAX_STATE || state < MIN_STATE) {
130 throw new IllegalArgumentException("Invalid state " + state);
131 }
132 if (state == mState) {
Evan Laird91d0f102018-09-18 17:39:55 -0400133 return false;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400134 }
Evan Laird2ce144e2019-03-04 18:45:34 -0500135
136 // Record the to-be mState and mLastState
137 recordHistoricalState(state, mState);
138
Jason Monk1fd3fc32018-08-14 17:20:09 -0400139 synchronized (mListeners) {
Evan Laird91d0f102018-09-18 17:39:55 -0400140 for (RankedListener rl : new ArrayList<>(mListeners)) {
Beverly8fdb5332019-02-04 14:29:49 -0500141 rl.mListener.onStatePreChange(mState, state);
Jason Monk1fd3fc32018-08-14 17:20:09 -0400142 }
143 mLastState = mState;
144 mState = state;
Evan Laird91d0f102018-09-18 17:39:55 -0400145 for (RankedListener rl : new ArrayList<>(mListeners)) {
Beverly8fdb5332019-02-04 14:29:49 -0500146 rl.mListener.onStateChanged(mState);
Evan Laird91d0f102018-09-18 17:39:55 -0400147 }
148
149 for (RankedListener rl : new ArrayList<>(mListeners)) {
Beverly8fdb5332019-02-04 14:29:49 -0500150 rl.mListener.onStatePostChange();
Jason Monk1fd3fc32018-08-14 17:20:09 -0400151 }
152 }
Evan Laird91d0f102018-09-18 17:39:55 -0400153
154 return true;
Jason Monk1fd3fc32018-08-14 17:20:09 -0400155 }
156
Beverly8fdb5332019-02-04 14:29:49 -0500157 @Override
Evan Lairde84d8552018-10-15 15:08:45 -0400158 public boolean isDozing() {
159 return mIsDozing;
160 }
161
Beverly8fdb5332019-02-04 14:29:49 -0500162 @Override
Lucas Dupin1a8b33d2018-11-12 18:18:15 -0800163 public float getDozeAmount() {
164 return mDozeAmount;
165 }
166
Beverly8fdb5332019-02-04 14:29:49 -0500167 @Override
Lucas Dupin1a8b33d2018-11-12 18:18:15 -0800168 public float getInterpolatedDozeAmount() {
169 return mDozeInterpolator.getInterpolation(mDozeAmount);
170 }
171
Beverly8fdb5332019-02-04 14:29:49 -0500172 @Override
Evan Lairde84d8552018-10-15 15:08:45 -0400173 public boolean setIsDozing(boolean isDozing) {
174 if (mIsDozing == isDozing) {
175 return false;
176 }
177
178 mIsDozing = isDozing;
179
180 synchronized (mListeners) {
181 for (RankedListener rl : new ArrayList<>(mListeners)) {
Beverly8fdb5332019-02-04 14:29:49 -0500182 rl.mListener.onDozingChanged(isDozing);
Evan Lairde84d8552018-10-15 15:08:45 -0400183 }
184 }
185
186 return true;
187 }
188
Beverly8fdb5332019-02-04 14:29:49 -0500189 @Override
Lucas Dupin1a8b33d2018-11-12 18:18:15 -0800190 public void setDozeAmount(float dozeAmount, boolean animated) {
191 if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
192 if (animated && mDozeAmountTarget == dozeAmount) {
193 return;
194 } else {
195 mDarkAnimator.cancel();
196 }
197 }
198
199 mDozeAmountTarget = dozeAmount;
200 if (animated) {
201 startDozeAnimation();
202 } else {
203 setDozeAmountInternal(dozeAmount);
204 }
205 }
206
207 private void startDozeAnimation() {
208 if (mDozeAmount == 0f || mDozeAmount == 1f) {
209 mDozeInterpolator = mIsDozing
210 ? Interpolators.FAST_OUT_SLOW_IN
211 : Interpolators.TOUCH_RESPONSE_REVERSE;
212 }
213 mDarkAnimator = ObjectAnimator.ofFloat(this, SET_DARK_AMOUNT_PROPERTY, mDozeAmountTarget);
214 mDarkAnimator.setInterpolator(Interpolators.LINEAR);
215 mDarkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
216 mDarkAnimator.start();
217 }
218
219 private void setDozeAmountInternal(float dozeAmount) {
220 mDozeAmount = dozeAmount;
221 float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount);
222 synchronized (mListeners) {
223 for (RankedListener rl : new ArrayList<>(mListeners)) {
Beverly8fdb5332019-02-04 14:29:49 -0500224 rl.mListener.onDozeAmountChanged(mDozeAmount, interpolatedAmount);
Lucas Dupin1a8b33d2018-11-12 18:18:15 -0800225 }
226 }
227 }
228
Beverly8fdb5332019-02-04 14:29:49 -0500229 @Override
Jason Monk1fd3fc32018-08-14 17:20:09 -0400230 public boolean goingToFullShade() {
231 return mState == StatusBarState.SHADE && mLeaveOpenOnKeyguardHide;
232 }
233
Beverly8fdb5332019-02-04 14:29:49 -0500234 @Override
Jason Monk1fd3fc32018-08-14 17:20:09 -0400235 public void setLeaveOpenOnKeyguardHide(boolean leaveOpen) {
236 mLeaveOpenOnKeyguardHide = leaveOpen;
237 }
238
Beverly8fdb5332019-02-04 14:29:49 -0500239 @Override
Jason Monk1fd3fc32018-08-14 17:20:09 -0400240 public boolean leaveOpenOnKeyguardHide() {
241 return mLeaveOpenOnKeyguardHide;
242 }
243
Beverly8fdb5332019-02-04 14:29:49 -0500244 @Override
Jason Monk1fd3fc32018-08-14 17:20:09 -0400245 public boolean fromShadeLocked() {
246 return mLastState == StatusBarState.SHADE_LOCKED;
247 }
248
Beverly8fdb5332019-02-04 14:29:49 -0500249 @Override
Jason Monkaf08c152018-12-04 11:12:39 -0500250 public void addCallback(StateListener listener) {
Jason Monk1fd3fc32018-08-14 17:20:09 -0400251 synchronized (mListeners) {
Evan Laird91d0f102018-09-18 17:39:55 -0400252 addListenerInternalLocked(listener, Integer.MAX_VALUE);
Jason Monk1fd3fc32018-08-14 17:20:09 -0400253 }
254 }
255
Evan Laird91d0f102018-09-18 17:39:55 -0400256 /**
257 * Add a listener and a rank based on the priority of this message
258 * @param listener the listener
259 * @param rank the order in which you'd like to be called. Ranked listeners will be
260 * notified before unranked, and we will sort ranked listeners from low to high
261 *
262 * @deprecated This method exists only to solve latent inter-dependencies from refactoring
263 * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking
264 * (i.e., they are non-dependent on the order of operations of StatusBarState listeners).
265 */
Beverly8fdb5332019-02-04 14:29:49 -0500266 @Deprecated
267 @Override
Jason Monkaf08c152018-12-04 11:12:39 -0500268 public void addCallback(StateListener listener, @SbStateListenerRank int rank) {
Evan Laird91d0f102018-09-18 17:39:55 -0400269 synchronized (mListeners) {
270 addListenerInternalLocked(listener, rank);
271 }
272 }
273
274 @GuardedBy("mListeners")
275 private void addListenerInternalLocked(StateListener listener, int rank) {
276 // Protect against double-subscribe
277 for (RankedListener rl : mListeners) {
Beverly8fdb5332019-02-04 14:29:49 -0500278 if (rl.mListener.equals(listener)) {
Evan Laird91d0f102018-09-18 17:39:55 -0400279 return;
280 }
281 }
282
Beverly8fdb5332019-02-04 14:29:49 -0500283 RankedListener rl = new SysuiStatusBarStateController.RankedListener(listener, rank);
Evan Laird91d0f102018-09-18 17:39:55 -0400284 mListeners.add(rl);
Beverly8fdb5332019-02-04 14:29:49 -0500285 mListeners.sort(sComparator);
Evan Laird91d0f102018-09-18 17:39:55 -0400286 }
287
Beverly8fdb5332019-02-04 14:29:49 -0500288
289 @Override
Jason Monkaf08c152018-12-04 11:12:39 -0500290 public void removeCallback(StateListener listener) {
Jason Monk1fd3fc32018-08-14 17:20:09 -0400291 synchronized (mListeners) {
Beverly8fdb5332019-02-04 14:29:49 -0500292 mListeners.removeIf((it) -> it.mListener.equals(listener));
Jason Monk1fd3fc32018-08-14 17:20:09 -0400293 }
294 }
295
Beverly8fdb5332019-02-04 14:29:49 -0500296 @Override
Jason Monk297c04e2018-08-23 17:16:59 -0400297 public void setKeyguardRequested(boolean keyguardRequested) {
298 mKeyguardRequested = keyguardRequested;
299 }
300
Beverly8fdb5332019-02-04 14:29:49 -0500301 @Override
Jason Monk297c04e2018-08-23 17:16:59 -0400302 public boolean isKeyguardRequested() {
303 return mKeyguardRequested;
304 }
305
Beverlye14f08e2019-06-06 15:33:10 -0400306 @Override
307 public void setSystemUiVisibility(int visibility) {
308 if (mSystemUiVisibility != visibility) {
309 mSystemUiVisibility = visibility;
310 synchronized (mListeners) {
311 for (RankedListener rl : new ArrayList<>(mListeners)) {
312 rl.mListener.onSystemUiVisibilityChanged(mSystemUiVisibility);
313 }
314 }
315 }
316 }
317
318 @Override
319 public void setPulsing(boolean pulsing) {
320 if (mPulsing != pulsing) {
321 mPulsing = pulsing;
322 synchronized (mListeners) {
323 for (RankedListener rl : new ArrayList<>(mListeners)) {
324 rl.mListener.onPulsingChanged(pulsing);
325 }
326 }
327 }
328 }
329
Beverly8fdb5332019-02-04 14:29:49 -0500330 /**
331 * Returns String readable state of status bar from {@link StatusBarState}
332 */
Evan Laird91d0f102018-09-18 17:39:55 -0400333 public static String describe(int state) {
334 return StatusBarState.toShortString(state);
335 }
Evan Laird2ce144e2019-03-04 18:45:34 -0500336
337 @Override
338 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
339 pw.println("StatusBarStateController: ");
340 pw.println(" mState=" + mState + " (" + describe(mState) + ")");
341 pw.println(" mLastState=" + mLastState + " (" + describe(mLastState) + ")");
342 pw.println(" mLeaveOpenOnKeyguardHide=" + mLeaveOpenOnKeyguardHide);
343 pw.println(" mKeyguardRequested=" + mKeyguardRequested);
344 pw.println(" mIsDozing=" + mIsDozing);
345 pw.println(" Historical states:");
346 // Ignore records without a timestamp
347 int size = 0;
348 for (int i = 0; i < HISTORY_SIZE; i++) {
349 if (mHistoricalRecords[i].mTimestamp != 0) size++;
350 }
351 for (int i = mHistoryIndex + HISTORY_SIZE;
352 i >= mHistoryIndex + HISTORY_SIZE - size + 1; i--) {
353 pw.println(" (" + (mHistoryIndex + HISTORY_SIZE - i + 1) + ")"
354 + mHistoricalRecords[i & (HISTORY_SIZE - 1)]);
355 }
356 }
357
358 private void recordHistoricalState(int currentState, int lastState) {
359 mHistoryIndex = (mHistoryIndex + 1) % HISTORY_SIZE;
360 HistoricalState state = mHistoricalRecords[mHistoryIndex];
361 state.mState = currentState;
362 state.mLastState = lastState;
363 state.mTimestamp = System.currentTimeMillis();
364 }
365
366 /**
367 * For keeping track of our previous state to help with debugging
368 */
369 private static class HistoricalState {
370 int mState;
371 int mLastState;
372 long mTimestamp;
373
374 @Override
375 public String toString() {
376 if (mTimestamp != 0) {
377 StringBuilder sb = new StringBuilder();
378 sb.append("state=").append(mState)
379 .append(" (").append(describe(mState)).append(")");
380 sb.append("lastState=").append(mLastState).append(" (").append(describe(mLastState))
381 .append(")");
382 sb.append("timestamp=")
383 .append(DateFormat.format("MM-dd HH:mm:ss", mTimestamp));
384
385 return sb.toString();
386 }
387 return "Empty " + getClass().getSimpleName();
388 }
389 }
Jason Monk1fd3fc32018-08-14 17:20:09 -0400390}