blob: a6aa90916c2525d48c3ea54474257c913eaf5bcc [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 Dupinbb83b892019-07-19 11:45:16 -070019import static com.android.systemui.doze.DozeMachine.State.DOZE;
Lucas Dupin4df92c32018-01-08 10:21:52 -080020import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
21
Adrian Roosfe54aa02016-11-07 14:14:25 -080022import android.app.AlarmManager;
Adrian Roosff2c4562016-11-03 12:13:36 -070023import android.content.Context;
Adrian Roosfe54aa02016-11-07 14:14:25 -080024import android.os.Handler;
25import android.os.SystemClock;
Adrian Roose4b564c2017-04-14 14:48:05 -070026import android.text.format.Formatter;
27import android.util.Log;
Adrian Roosfe54aa02016-11-07 14:14:25 -080028
Lucas Dupin16cfe452018-02-08 13:14:50 -080029import com.android.internal.annotations.VisibleForTesting;
30import com.android.keyguard.KeyguardUpdateMonitor;
31import com.android.keyguard.KeyguardUpdateMonitorCallback;
Lucas Dupin43d0d732017-11-16 11:23:49 -080032import com.android.systemui.statusbar.phone.DozeParameters;
Adrian Roosef5cf2b2017-06-28 15:46:03 +020033import com.android.systemui.util.AlarmTimeout;
Adrian Roosc1b50322017-02-27 21:07:58 +010034import com.android.systemui.util.wakelock.WakeLock;
35
Adrian Roosfe54aa02016-11-07 14:14:25 -080036import java.util.Calendar;
Adrian Roosff2c4562016-11-03 12:13:36 -070037
38/**
39 * The policy controlling doze.
40 */
41public class DozeUi implements DozeMachine.Part {
42
Adrian Roose4b564c2017-04-14 14:48:05 -070043 private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
Adrian Roosff2c4562016-11-03 12:13:36 -070044 private final Context mContext;
45 private final DozeHost mHost;
Adrian Roosfe54aa02016-11-07 14:14:25 -080046 private final Handler mHandler;
Adrian Roosc1b50322017-02-27 21:07:58 +010047 private final WakeLock mWakeLock;
Adrian Roosfe54aa02016-11-07 14:14:25 -080048 private final DozeMachine mMachine;
Adrian Roosef5cf2b2017-06-28 15:46:03 +020049 private final AlarmTimeout mTimeTicker;
Lucas Dupin16cfe452018-02-08 13:14:50 -080050 private final boolean mCanAnimateTransition;
51 private final DozeParameters mDozeParameters;
Beverlycc4a62f2019-09-26 14:55:28 -040052 private final DozeLog mDozeLog;
Lucas Dupin16cfe452018-02-08 13:14:50 -080053
54 private boolean mKeyguardShowing;
55 private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
56 new KeyguardUpdateMonitorCallback() {
57
58 @Override
59 public void onKeyguardVisibilityChanged(boolean showing) {
60 mKeyguardShowing = showing;
61 updateAnimateScreenOff();
62 }
63 };
Adrian Roosff2c4562016-11-03 12:13:36 -070064
Adrian Roose4b564c2017-04-14 14:48:05 -070065 private long mLastTimeTickElapsed = 0;
Adrian Roosfe54aa02016-11-07 14:14:25 -080066
67 public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
Lucas Dupin43d0d732017-11-16 11:23:49 -080068 WakeLock wakeLock, DozeHost host, Handler handler,
Beverlycc4a62f2019-09-26 14:55:28 -040069 DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
70 DozeLog dozeLog) {
Adrian Roosff2c4562016-11-03 12:13:36 -070071 mContext = context;
72 mMachine = machine;
73 mWakeLock = wakeLock;
74 mHost = host;
Adrian Roosfe54aa02016-11-07 14:14:25 -080075 mHandler = handler;
Lucas Dupin16cfe452018-02-08 13:14:50 -080076 mCanAnimateTransition = !params.getDisplayNeedsBlanking();
77 mDozeParameters = params;
Adrian Roosef5cf2b2017-06-28 15:46:03 +020078 mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
Lucas Dupin16cfe452018-02-08 13:14:50 -080079 keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
Beverlycc4a62f2019-09-26 14:55:28 -040080 mDozeLog = dozeLog;
Lucas Dupin16cfe452018-02-08 13:14:50 -080081 }
82
83 /**
84 * Decide if we're taking over the screen-off animation
85 * when the device was configured to skip doze after screen off.
86 */
87 private void updateAnimateScreenOff() {
88 if (mCanAnimateTransition) {
Lucas Dupinbd7366d2019-09-25 13:39:21 -070089 final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing
90 && !mHost.isPowerSaveActive();
Lucas Dupin16cfe452018-02-08 13:14:50 -080091 mDozeParameters.setControlScreenOffAnimation(controlScreenOff);
92 mHost.setAnimateScreenOff(controlScreenOff);
93 }
Adrian Roosff2c4562016-11-03 12:13:36 -070094 }
95
96 private void pulseWhileDozing(int reason) {
97 mHost.pulseWhileDozing(
98 new DozeHost.PulseCallback() {
99 @Override
100 public void onPulseStarted() {
Lucas Dupin09f85272019-03-08 15:04:06 -0800101 try {
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700102 mMachine.requestState(
Beverlycc4a62f2019-09-26 14:55:28 -0400103 reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700104 ? DozeMachine.State.DOZE_PULSING_BRIGHT
105 : DozeMachine.State.DOZE_PULSING);
Lucas Dupin09f85272019-03-08 15:04:06 -0800106 } catch (IllegalStateException e) {
107 // It's possible that the pulse was asynchronously cancelled while
108 // we were waiting for it to start (under stress conditions.)
109 // In those cases we should just ignore it. b/127657926
110 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700111 }
112
113 @Override
114 public void onPulseFinished() {
115 mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
116 }
117 }, reason);
118 }
119
120 @Override
121 public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
122 switch (newState) {
Adrian Roosfe54aa02016-11-07 14:14:25 -0800123 case DOZE_AOD:
Jerry Changae4dc4b2019-10-16 18:45:03 +0800124 case DOZE_AOD_DOCKED:
Lucas Dupinbb83b892019-07-19 11:45:16 -0700125 if (oldState == DOZE_AOD_PAUSED || oldState == DOZE) {
Lucas Dupinf9583c42018-04-05 22:20:44 -0700126 // Whenever turning on the display, it's necessary to push a new frame.
127 // The display buffers will be empty and need to be filled.
Lucas Dupin4df92c32018-01-08 10:21:52 -0800128 mHost.dozeTimeTick();
Lucas Dupinf9583c42018-04-05 22:20:44 -0700129 // The first frame may arrive when the display isn't ready yet.
Lucas Dupina11298b2018-06-26 15:09:08 -0700130 mHandler.postDelayed(mWakeLock.wrap(mHost::dozeTimeTick), 500);
Lucas Dupin4df92c32018-01-08 10:21:52 -0800131 }
132 scheduleTimeTick();
133 break;
Adrian Roos6023ccb2017-06-28 16:22:02 +0200134 case DOZE_AOD_PAUSING:
Adrian Roosfe54aa02016-11-07 14:14:25 -0800135 scheduleTimeTick();
136 break;
137 case DOZE:
Adrian Roos67cca742017-04-13 16:52:51 -0700138 case DOZE_AOD_PAUSED:
Adrian Roosfe54aa02016-11-07 14:14:25 -0800139 unscheduleTimeTick();
140 break;
Adrian Roosff2c4562016-11-03 12:13:36 -0700141 case DOZE_REQUEST_PULSE:
TYM Tsai25c05492019-01-04 16:59:07 +0800142 scheduleTimeTick();
Adrian Roosd7b9d102017-04-28 15:42:58 -0700143 pulseWhileDozing(mMachine.getPulseReason());
Adrian Roosff2c4562016-11-03 12:13:36 -0700144 break;
145 case INITIALIZED:
146 mHost.startDozing();
147 break;
148 case FINISH:
149 mHost.stopDozing();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800150 unscheduleTimeTick();
Adrian Roosff2c4562016-11-03 12:13:36 -0700151 break;
152 }
Adrian Roos013fc4c2017-08-02 19:32:28 +0200153 updateAnimateWakeup(newState);
Adrian Roos28f90c72017-05-08 17:24:26 -0700154 }
155
Adrian Roos013fc4c2017-08-02 19:32:28 +0200156 private void updateAnimateWakeup(DozeMachine.State state) {
Adrian Roos28f90c72017-05-08 17:24:26 -0700157 switch (state) {
Adrian Roos28f90c72017-05-08 17:24:26 -0700158 case DOZE_REQUEST_PULSE:
159 case DOZE_PULSING:
Lucas Dupin5f00fa52019-03-27 22:46:53 -0700160 case DOZE_PULSING_BRIGHT:
Adrian Roos28f90c72017-05-08 17:24:26 -0700161 case DOZE_PULSE_DONE:
Adrian Roos013fc4c2017-08-02 19:32:28 +0200162 mHost.setAnimateWakeup(true);
163 break;
164 case FINISH:
165 // Keep current state.
166 break;
Adrian Roos28f90c72017-05-08 17:24:26 -0700167 default:
Lucas Dupin16cfe452018-02-08 13:14:50 -0800168 mHost.setAnimateWakeup(mCanAnimateTransition && mDozeParameters.getAlwaysOn());
Adrian Roos013fc4c2017-08-02 19:32:28 +0200169 break;
Adrian Roos28f90c72017-05-08 17:24:26 -0700170 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700171 }
Adrian Roosfe54aa02016-11-07 14:14:25 -0800172
173 private void scheduleTimeTick() {
Adrian Roosef5cf2b2017-06-28 15:46:03 +0200174 if (mTimeTicker.isScheduled()) {
Adrian Roosfe54aa02016-11-07 14:14:25 -0800175 return;
176 }
177
Lucas Dupin69d4b572018-09-06 10:36:08 -0700178 long time = System.currentTimeMillis();
179 long delta = roundToNextMinute(time) - System.currentTimeMillis();
180 boolean scheduled = mTimeTicker.schedule(delta, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
181 if (scheduled) {
Beverlycc4a62f2019-09-26 14:55:28 -0400182 mDozeLog.traceTimeTickScheduled(time, time + delta);
Lucas Dupin69d4b572018-09-06 10:36:08 -0700183 }
Adrian Roose4b564c2017-04-14 14:48:05 -0700184 mLastTimeTickElapsed = SystemClock.elapsedRealtime();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800185 }
186
187 private void unscheduleTimeTick() {
Adrian Roosef5cf2b2017-06-28 15:46:03 +0200188 if (!mTimeTicker.isScheduled()) {
Adrian Roosfe54aa02016-11-07 14:14:25 -0800189 return;
190 }
Adrian Roose4b564c2017-04-14 14:48:05 -0700191 verifyLastTimeTick();
Adrian Roosef5cf2b2017-06-28 15:46:03 +0200192 mTimeTicker.cancel();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800193 }
194
Adrian Roose4b564c2017-04-14 14:48:05 -0700195 private void verifyLastTimeTick() {
196 long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed;
197 if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) {
198 String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick);
Beverlycc4a62f2019-09-26 14:55:28 -0400199 mDozeLog.traceMissedTick(delay);
Adrian Roose4b564c2017-04-14 14:48:05 -0700200 Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay);
201 }
202 }
203
Adrian Roosfe54aa02016-11-07 14:14:25 -0800204 private long roundToNextMinute(long timeInMillis) {
Neil Fuller9c610f72018-07-04 16:41:14 +0100205 Calendar calendar = Calendar.getInstance();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800206 calendar.setTimeInMillis(timeInMillis);
207 calendar.set(Calendar.MILLISECOND, 0);
208 calendar.set(Calendar.SECOND, 0);
209 calendar.add(Calendar.MINUTE, 1);
210
211 return calendar.getTimeInMillis();
212 }
213
214 private void onTimeTick() {
Adrian Roose4b564c2017-04-14 14:48:05 -0700215 verifyLastTimeTick();
Adrian Roosfe54aa02016-11-07 14:14:25 -0800216
217 mHost.dozeTimeTick();
218
219 // Keep wakelock until a frame has been pushed.
220 mHandler.post(mWakeLock.wrap(() -> {}));
221
Adrian Roosfe54aa02016-11-07 14:14:25 -0800222 scheduleTimeTick();
223 }
Lucas Dupin16cfe452018-02-08 13:14:50 -0800224
225 @VisibleForTesting
226 KeyguardUpdateMonitorCallback getKeyguardCallback() {
227 return mKeyguardVisibilityCallback;
228 }
Adrian Roosff2c4562016-11-03 12:13:36 -0700229}