1 /*
2  * Copyright (C) 2017 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.util;
18 
19 import android.app.AlarmManager;
20 import android.os.Handler;
21 import android.os.SystemClock;
22 
23 /**
24  * Schedules a timeout through AlarmManager. Ensures that the timeout is called even when
25  * the device is asleep.
26  */
27 public class AlarmTimeout implements AlarmManager.OnAlarmListener {
28 
29     public static final int MODE_CRASH_IF_SCHEDULED = 0;
30     public static final int MODE_IGNORE_IF_SCHEDULED = 1;
31     public static final int MODE_RESCHEDULE_IF_SCHEDULED = 2;
32 
33     private final AlarmManager mAlarmManager;
34     private final AlarmManager.OnAlarmListener mListener;
35     private final String mTag;
36     private final Handler mHandler;
37     private boolean mScheduled;
38 
AlarmTimeout(AlarmManager alarmManager, AlarmManager.OnAlarmListener listener, String tag, Handler handler)39     public AlarmTimeout(AlarmManager alarmManager, AlarmManager.OnAlarmListener listener,
40             String tag, Handler handler) {
41         mAlarmManager = alarmManager;
42         mListener = listener;
43         mTag = tag;
44         mHandler = handler;
45     }
46 
schedule(long timeout, int mode)47     public void schedule(long timeout, int mode) {
48         switch (mode) {
49             case MODE_CRASH_IF_SCHEDULED:
50                 if (mScheduled) {
51                     throw new IllegalStateException(mTag + " timeout is already scheduled");
52                 }
53                 break;
54             case MODE_IGNORE_IF_SCHEDULED:
55                 if (mScheduled) {
56                     return;
57                 }
58                 break;
59             case MODE_RESCHEDULE_IF_SCHEDULED:
60                 if (mScheduled) {
61                     cancel();
62                 }
63                 break;
64             default:
65                 throw new IllegalArgumentException("Illegal mode: " + mode);
66         }
67 
68         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
69                 SystemClock.elapsedRealtime() + timeout, mTag, this, mHandler);
70         mScheduled = true;
71     }
72 
isScheduled()73     public boolean isScheduled() {
74         return mScheduled;
75     }
76 
cancel()77     public void cancel() {
78         if (mScheduled) {
79             mAlarmManager.cancel(this);
80             mScheduled = false;
81         }
82     }
83 
84     @Override
onAlarm()85     public void onAlarm() {
86         if (!mScheduled) {
87             // We canceled the alarm, but it still fired. Ignore.
88             return;
89         }
90         mScheduled = false;
91         mListener.onAlarm();
92     }
93 }
94