• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.systemui.doze;
18 
19 import android.app.AlarmManager;
20 import android.content.Context;
21 import android.os.Handler;
22 import android.os.SystemClock;
23 import android.text.format.Formatter;
24 import android.util.Log;
25 
26 import com.android.systemui.util.wakelock.WakeLock;
27 
28 import java.util.Calendar;
29 import java.util.GregorianCalendar;
30 
31 /**
32  * The policy controlling doze.
33  */
34 public class DozeUi implements DozeMachine.Part {
35 
36     private static final long TIME_TICK_DEADLINE_MILLIS = 90 * 1000; // 1.5min
37     private final Context mContext;
38     private final AlarmManager mAlarmManager;
39     private final DozeHost mHost;
40     private final Handler mHandler;
41     private final WakeLock mWakeLock;
42     private final DozeMachine mMachine;
43     private final AlarmManager.OnAlarmListener mTimeTick;
44 
45     private boolean mTimeTickScheduled = false;
46     private long mLastTimeTickElapsed = 0;
47 
DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine, WakeLock wakeLock, DozeHost host, Handler handler)48     public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
49             WakeLock wakeLock, DozeHost host, Handler handler) {
50         mContext = context;
51         mAlarmManager = alarmManager;
52         mMachine = machine;
53         mWakeLock = wakeLock;
54         mHost = host;
55         mHandler = handler;
56 
57         mTimeTick = this::onTimeTick;
58     }
59 
pulseWhileDozing(int reason)60     private void pulseWhileDozing(int reason) {
61         mHost.pulseWhileDozing(
62                 new DozeHost.PulseCallback() {
63                     @Override
64                     public void onPulseStarted() {
65                         mMachine.requestState(DozeMachine.State.DOZE_PULSING);
66                     }
67 
68                     @Override
69                     public void onPulseFinished() {
70                         mMachine.requestState(DozeMachine.State.DOZE_PULSE_DONE);
71                     }
72                 }, reason);
73     }
74 
75     @Override
transitionTo(DozeMachine.State oldState, DozeMachine.State newState)76     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
77         switch (newState) {
78             case DOZE_AOD:
79                 scheduleTimeTick();
80                 break;
81             case DOZE:
82             case DOZE_AOD_PAUSED:
83                 unscheduleTimeTick();
84                 break;
85             case DOZE_REQUEST_PULSE:
86                 pulseWhileDozing(mMachine.getPulseReason());
87                 break;
88             case DOZE_PULSE_DONE:
89                 mHost.abortPulsing();
90             case INITIALIZED:
91                 mHost.startDozing();
92                 break;
93             case FINISH:
94                 mHost.stopDozing();
95                 unscheduleTimeTick();
96                 break;
97         }
98         mHost.setAnimateWakeup(shouldAnimateWakeup(newState));
99     }
100 
shouldAnimateWakeup(DozeMachine.State state)101     private boolean shouldAnimateWakeup(DozeMachine.State state) {
102         switch (state) {
103             case DOZE_AOD:
104             case DOZE_REQUEST_PULSE:
105             case DOZE_PULSING:
106             case DOZE_PULSE_DONE:
107                 return true;
108             default:
109                 return false;
110         }
111     }
112 
scheduleTimeTick()113     private void scheduleTimeTick() {
114         if (mTimeTickScheduled) {
115             return;
116         }
117 
118         long delta = roundToNextMinute(System.currentTimeMillis()) - System.currentTimeMillis();
119         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
120                 SystemClock.elapsedRealtime() + delta, "doze_time_tick", mTimeTick, mHandler);
121 
122         mTimeTickScheduled = true;
123         mLastTimeTickElapsed = SystemClock.elapsedRealtime();
124     }
125 
unscheduleTimeTick()126     private void unscheduleTimeTick() {
127         if (!mTimeTickScheduled) {
128             return;
129         }
130         verifyLastTimeTick();
131         mAlarmManager.cancel(mTimeTick);
132     }
133 
verifyLastTimeTick()134     private void verifyLastTimeTick() {
135         long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed;
136         if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) {
137             String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick);
138             DozeLog.traceMissedTick(delay);
139             Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay);
140         }
141     }
142 
roundToNextMinute(long timeInMillis)143     private long roundToNextMinute(long timeInMillis) {
144         Calendar calendar = GregorianCalendar.getInstance();
145         calendar.setTimeInMillis(timeInMillis);
146         calendar.set(Calendar.MILLISECOND, 0);
147         calendar.set(Calendar.SECOND, 0);
148         calendar.add(Calendar.MINUTE, 1);
149 
150         return calendar.getTimeInMillis();
151     }
152 
onTimeTick()153     private void onTimeTick() {
154         if (!mTimeTickScheduled) {
155             // Alarm was canceled, but we still got the callback. Ignore.
156             return;
157         }
158         verifyLastTimeTick();
159 
160         mHost.dozeTimeTick();
161 
162         // Keep wakelock until a frame has been pushed.
163         mHandler.post(mWakeLock.wrap(() -> {}));
164 
165         mTimeTickScheduled = false;
166         scheduleTimeTick();
167     }
168 }
169