blob: 76565649dd6902aa56277b770716ad492f55868a [file] [log] [blame]
Adrian Roosff2c4562016-11-03 12:13:36 -07001/*
2 * Copyright (C) 2016 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.doze;
18
Lucas Dupin4df92c32018-01-08 10:21:52 -080019import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
20
Adrian Roosfe54aa02016-11-07 14:14:25 -080021import android.app.AlarmManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070022import android.content.Context;
Adrian Roosfe54aa02016-11-07 14:14:25 -080023import android.os.Handler;
24import android.os.SystemClock;
Adrian Roose4b564c2017-04-14 14:48:05 -070025import android.text.format.Formatter;
26import android.util.Log;
Adrian Roosfe54aa02016-11-07 14:14:25 -080027
Lucas Dupin16cfe452018-02-08 13:14:50 -080028import com.android.internal.annotations.VisibleForTesting;
29import com.android.keyguard.KeyguardUpdateMonitor;
30import com.android.keyguard.KeyguardUpdateMonitorCallback;
Lucas Dupin43d0d732017-11-16 11:23:49 -080031import com.android.systemui.statusbar.phone.DozeParameters;
Adrian Roosef5cf2b2017-06-28 15:46:03 +020032import com.android.systemui.util.AlarmTimeout;
Adrian Roosc1b50322017-02-27 21:07:58 +010033import com.android.systemui.util.wakelock.WakeLock;
34
Adrian Roosfe54aa02016-11-07 14:14:25 -080035import java.util.Calendar;
Adrian Roosff2c4562016-11-03 12:13:36 -070036
37/**
38 * The policy controlling doze.
39 */
40public class DozeUi implements DozeMachine.Part {
41
Adrian Roose4b564c2017-04-14 14:48:05 -070042 private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
Adrian Roosff2c4562016-11-03 12:13:36 -070043 private final Context mContext;
44 private final DozeHost mHost;
Adrian Roosfe54aa02016-11-07 14:14:25 -080045 private final Handler mHandler;
Adrian Roosc1b50322017-02-27 21:07:58 +010046 private final WakeLock mWakeLock;
Adrian Roosfe54aa02016-11-07 14:14:25 -080047 private final DozeMachine mMachine;
Adrian Roosef5cf2b2017-06-28 15:46:03 +020048 private final AlarmTimeout mTimeTicker;
Lucas Dupin16cfe452018-02-08 13:14:50 -080049 private final boolean mCanAnimateTransition;
50 private final DozeParameters mDozeParameters;
51
52 private boolean mKeyguardShowing;
53 private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
54 new KeyguardUpdateMonitorCallback() {
55
56 @Override
57 public void onKeyguardVisibilityChanged(boolean showing) {
58 mKeyguardShowing = showing;
59 updateAnimateScreenOff();
60 }
61 };
Adrian Roosff2c4562016-11-03 12:13:36 -070062
Adrian Roose4b564c2017-04-14 14:48:05 -070063 private long mLastTimeTickElapsed = 0;
Adrian Roosfe54aa02016-11-07 14:14:25 -080064
65 public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
Lucas Dupin43d0d732017-11-16 11:23:49 -080066 WakeLock wakeLock, DozeHost host, Handler handler,
Lucas Dupin16cfe452018-02-08 13:14:50 -080067 DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor) {
Adrian Roosff2c4562016-11-03 12:13:36 -070068 mContext = context;
69 mMachine = machine;
70 mWakeLock = wakeLock;
71 mHost = host;
Adrian Roosfe54aa02016-11-07 14:14:25 -080072 mHandler = handler;
Lucas Dupin16cfe452018-02-08 13:14:50 -080073 mCanAnimateTransition = !params.getDisplayNeedsBlanking();
74 mDozeParameters = params;
Adrian Roosef5cf2b2017-06-28 15:46:03 +020075 mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
Lucas Dupin16cfe452018-02-08 13:14:50 -080076 keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
77 }
78
79 /**
80 * Decide if we're taking over the screen-off animation
81 * when the device was configured to skip doze after screen off.
82 */
83 private void updateAnimateScreenOff() {
84 if (mCanAnimateTransition) {
85 final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing;
86 mDozeParameters.setControlScreenOffAnimation(controlScreenOff);
87 mHost.setAnimateScreenOff(controlScreenOff);
88 }
Adrian Roosff2c4562016-11-03 12:13:36 -070089 }
90
91 private void pulseWhileDozing(int reason) {
92 mHost.pulseWhileDozing(
93 new DozeHost.PulseCallback() {
94 @Override
95 public void onPulseStarted() {
96 mMachine.requestState(DozeMachine.State.DOZE_PULSING);
97 }
98
99 @Override
100 public void onPulseFinished() {
101 mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
102 }
103 }, reason);
104 }
105
106 @Override
107 public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
108 switch (newState) {
Adrian Roosfe54aa02016-11-07 14:14:25 -0800109 case DOZE_AOD:
Lucas Dupin4df92c32018-01-08 10:21:52 -0800110 if (oldState == DOZE_AOD_PAUSED) {
Lucas Dupinf9583c42018-04-05 22:20:44 -0700111 // Whenever turning on the display, it's necessary to push a new frame.
112 // The display buffers will be empty and need to be filled.
Lucas Dupin4df92c32018-01-08 10:21:52 -0800113 mHost.dozeTimeTick();
Lucas Dupinf9583c42018-04-05 22:20:44 -0700114 // The first frame may arrive when the display isn't ready yet.
Lucas Dupina11298b2018-06-26 15:09:08 -0700115 mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 500);
Lucas Dupin4df92c32018-01-08 10:21:52 -0800116 }
117 scheduleTimeTick();
118 break;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200119 case DOZE_AOD_PAUSING:
Adrian Roosfe54aa02016-11-07 14:14:25 -0800120 scheduleTimeTick();
121 break;
122 case DOZE:
Adrian Roos67cca742017-04-13 16:52:51 -0700123 case DOZE_AOD_PAUSED:
Adrian Roosfe54aa02016-11-07 14:14:25 -0800124 unscheduleTimeTick();
125 break;
Adrian Roosff2c4562016-11-03 12:13:36 -0700126 case DOZE_REQUEST_PULSE:
TYM Tsai25c05492019-01-04 16:59:07 +0800127 scheduleTimeTick();
Adrian Roosd7b9d102017-04-28 15:42:58 -0700128 pulseWhileDozing(mMachine.getPulseReason());
Adrian Roosff2c4562016-11-03 12:13:36 -0700129 break;
130 case INITIALIZED:
131 mHost.startDozing();
132 break;
133 case FINISH:
134 mHost.stopDozing();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800135 unscheduleTimeTick();
Adrian Roosff2c4562016-11-03 12:13:36 -0700136 break;
137 }
Adrian Roos013fc4c2017-08-02 19:32:28 +0200138 updateAnimateWakeup(newState);
Adrian Roos28f90c72017-05-08 17:24:26 -0700139 }
140
Adrian Roos013fc4c2017-08-02 19:32:28 +0200141 private void updateAnimateWakeup(DozeMachine.State state) {
Adrian Roos28f90c72017-05-08 17:24:26 -0700142 switch (state) {
Adrian Roos28f90c72017-05-08 17:24:26 -0700143 case DOZE_REQUEST_PULSE:
144 case DOZE_PULSING:
145 case DOZE_PULSE_DONE:
Adrian Roos013fc4c2017-08-02 19:32:28 +0200146 mHost.setAnimateWakeup(true);
147 break;
148 case FINISH:
149 // Keep current state.
150 break;
Adrian Roos28f90c72017-05-08 17:24:26 -0700151 default:
Lucas Dupin16cfe452018-02-08 13:14:50 -0800152 mHost.setAnimateWakeup(mCanAnimateTransition && mDozeParameters.getAlwaysOn());
Adrian Roos013fc4c2017-08-02 19:32:28 +0200153 break;
Adrian Roos28f90c72017-05-08 17:24:26 -0700154 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700155 }
Adrian Roosfe54aa02016-11-07 14:14:25 -0800156
157 private void scheduleTimeTick() {
Adrian Roosef5cf2b2017-06-28 15:46:03 +0200158 if (mTimeTicker.isScheduled()) {
Adrian Roosfe54aa02016-11-07 14:14:25 -0800159 return;
160 }
161
Lucas Dupin69d4b572018-09-06 10:36:08 -0700162 long time = System.currentTimeMillis();
163 long delta = roundToNextMinute(time) - System.currentTimeMillis();
164 boolean scheduled = mTimeTicker.schedule(delta, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
165 if (scheduled) {
166 DozeLog.traceTimeTickScheduled(time, time + delta);
167 }
Adrian Roose4b564c2017-04-14 14:48:05 -0700168 mLastTimeTickElapsed = SystemClock.elapsedRealtime();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800169 }
170
171 private void unscheduleTimeTick() {
Adrian Roosef5cf2b2017-06-28 15:46:03 +0200172 if (!mTimeTicker.isScheduled()) {
Adrian Roosfe54aa02016-11-07 14:14:25 -0800173 return;
174 }
Adrian Roose4b564c2017-04-14 14:48:05 -0700175 verifyLastTimeTick();
Adrian Roosef5cf2b2017-06-28 15:46:03 +0200176 mTimeTicker.cancel();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800177 }
178
Adrian Roose4b564c2017-04-14 14:48:05 -0700179 private void verifyLastTimeTick() {
180 long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed;
181 if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) {
182 String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick);
183 DozeLog.traceMissedTick(delay);
184 Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay);
185 }
186 }
187
Adrian Roosfe54aa02016-11-07 14:14:25 -0800188 private long roundToNextMinute(long timeInMillis) {
Neil Fuller9c610f72018-07-04 16:41:14 +0100189 Calendar calendar = Calendar.getInstance();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800190 calendar.setTimeInMillis(timeInMillis);
191 calendar.set(Calendar.MILLISECOND, 0);
192 calendar.set(Calendar.SECOND, 0);
193 calendar.add(Calendar.MINUTE, 1);
194
195 return calendar.getTimeInMillis();
196 }
197
198 private void onTimeTick() {
Adrian Roose4b564c2017-04-14 14:48:05 -0700199 verifyLastTimeTick();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800200
201 mHost.dozeTimeTick();
202
203 // Keep wakelock until a frame has been pushed.
204 mHandler.post(mWakeLock.wrap(() -> {}));
205
Adrian Roosfe54aa02016-11-07 14:14:25 -0800206 scheduleTimeTick();
207 }
Lucas Dupin16cfe452018-02-08 13:14:50 -0800208
209 @VisibleForTesting
210 KeyguardUpdateMonitorCallback getKeyguardCallback() {
211 return mKeyguardVisibilityCallback;
212 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700213}