• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.internal.util;
18 
19 import android.app.AlarmManager;
20 import android.content.Context;
21 import android.os.Handler;
22 import android.os.Message;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 
26  /**
27  * An AlarmListener that sends the specified message to a Handler and keeps the system awake until
28  * the message is processed.
29  *
30  * This is useful when using the AlarmManager direct callback interface to wake up the system and
31  * request that an object whose API consists of messages (such as a StateMachine) perform some
32  * action.
33  *
34  * In this situation, using AlarmManager.onAlarmListener by itself will wake up the system to send
35  * the message, but does not guarantee that the system will be awake until the target object has
36  * processed it. This is because as soon as the onAlarmListener sends the message and returns, the
37  * AlarmManager releases its wakelock and the system is free to go to sleep again.
38  */
39 public class WakeupMessage implements AlarmManager.OnAlarmListener {
40     private final AlarmManager mAlarmManager;
41 
42     @VisibleForTesting
43     protected final Handler mHandler;
44     @VisibleForTesting
45     protected final String mCmdName;
46     @VisibleForTesting
47     protected final int mCmd, mArg1, mArg2;
48     @VisibleForTesting
49     protected final Object mObj;
50     private boolean mScheduled;
51 
WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1, int arg2, Object obj)52     public WakeupMessage(Context context, Handler handler,
53             String cmdName, int cmd, int arg1, int arg2, Object obj) {
54         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
55         mHandler = handler;
56         mCmdName = cmdName;
57         mCmd = cmd;
58         mArg1 = arg1;
59         mArg2 = arg2;
60         mObj = obj;
61     }
62 
WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1)63     public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
64         this(context, handler, cmdName, cmd, arg1, 0, null);
65     }
66 
WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1, int arg2)67     public WakeupMessage(Context context, Handler handler,
68             String cmdName, int cmd, int arg1, int arg2) {
69         this(context, handler, cmdName, cmd, arg1, arg2, null);
70     }
71 
WakeupMessage(Context context, Handler handler, String cmdName, int cmd)72     public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
73         this(context, handler, cmdName, cmd, 0, 0, null);
74     }
75 
76     /**
77      * Schedule the message to be delivered at the time in milliseconds of the
78      * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
79      * the device when it goes off. If schedule is called multiple times without the message being
80      * dispatched then the alarm is rescheduled to the new time.
81      */
schedule(long when)82     public synchronized void schedule(long when) {
83         mAlarmManager.setExact(
84                 AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
85         mScheduled = true;
86     }
87 
88     /**
89      * Cancel all pending messages. This includes alarms that may have been fired, but have not been
90      * run on the handler yet.
91      */
cancel()92     public synchronized void cancel() {
93         if (mScheduled) {
94             mAlarmManager.cancel(this);
95             mScheduled = false;
96         }
97     }
98 
99     @Override
onAlarm()100     public void onAlarm() {
101         // Once this method is called the alarm has already been fired and removed from
102         // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
103         // be marked as unscheduled so that it can be rescheduled in the message handler.
104         final boolean stillScheduled;
105         synchronized (this) {
106             stillScheduled = mScheduled;
107             mScheduled = false;
108         }
109         if (stillScheduled) {
110             Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
111             mHandler.handleMessage(msg);
112             msg.recycle();
113         }
114     }
115 }
116