1e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti/*
2e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * Copyright (C) 2015 The Android Open Source Project
3e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti *
4e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License");
5e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * you may not use this file except in compliance with the License.
6e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * You may obtain a copy of the License at
7e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti *
8e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti *      http://www.apache.org/licenses/LICENSE-2.0
9e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti *
10e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * Unless required by applicable law or agreed to in writing, software
11e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS,
12e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * See the License for the specific language governing permissions and
14e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * limitations under the License.
15e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti */
16e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
17e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colittipackage com.android.internal.util;
18e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
19e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colittiimport android.app.AlarmManager;
20e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colittiimport android.content.Context;
21e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colittiimport android.os.Handler;
22e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colittiimport android.os.Message;
23e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
24e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colittiimport com.android.internal.annotations.VisibleForTesting;
25e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti
26e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti /**
27e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * An AlarmListener that sends the specified message to a Handler and keeps the system awake until
28e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * the message is processed.
29e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti *
30e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * This is useful when using the AlarmManager direct callback interface to wake up the system and
31e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * request that an object whose API consists of messages (such as a StateMachine) perform some
32e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * action.
33e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti *
34e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * In this situation, using AlarmManager.onAlarmListener by itself will wake up the system to send
35e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * the message, but does not guarantee that the system will be awake until the target object has
36e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * processed it. This is because as soon as the onAlarmListener sends the message and returns, the
37e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti * AlarmManager releases its wakelock and the system is free to go to sleep again.
38e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti */
39e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colittipublic class WakeupMessage implements AlarmManager.OnAlarmListener {
40634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills    private final AlarmManager mAlarmManager;
41e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti
42e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti    @VisibleForTesting
43e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti    protected final Handler mHandler;
44e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti    @VisibleForTesting
45e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti    protected final String mCmdName;
46e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti    @VisibleForTesting
47e7636e47504034c048872f251a0a7cb240017b31Lorenzo Colitti    protected final int mCmd, mArg1, mArg2;
48eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti    @VisibleForTesting
49eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti    protected final Object mObj;
50634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills    private boolean mScheduled;
51e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
52e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    public WakeupMessage(Context context, Handler handler,
53eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti            String cmdName, int cmd, int arg1, int arg2, Object obj) {
54634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
55e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti        mHandler = handler;
56e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti        mCmdName = cmdName;
57e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti        mCmd = cmd;
58e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti        mArg1 = arg1;
59e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti        mArg2 = arg2;
60eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti        mObj = obj;
61e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    }
62e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
63e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
64eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti        this(context, handler, cmdName, cmd, arg1, 0, null);
65eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti    }
66eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti
67eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti    public WakeupMessage(Context context, Handler handler,
68eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti            String cmdName, int cmd, int arg1, int arg2) {
69eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti        this(context, handler, cmdName, cmd, arg1, arg2, null);
70e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    }
71e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
72e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
73eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti        this(context, handler, cmdName, cmd, 0, 0, null);
74e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    }
75e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
76634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills    /**
77634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     * Schedule the message to be delivered at the time in milliseconds of the
78634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
79634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     * the device when it goes off. If schedule is called multiple times without the message being
80634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     * dispatched then the alarm is rescheduled to the new time.
81634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     */
82634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills    public synchronized void schedule(long when) {
83634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        mAlarmManager.setExact(
84e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti                AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
85634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        mScheduled = true;
86e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    }
87e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
88634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills    /**
89634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     * Cancel all pending messages. This includes alarms that may have been fired, but have not been
90634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     * run on the handler yet.
91634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills     */
92634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills    public synchronized void cancel() {
93634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        if (mScheduled) {
94634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills            mAlarmManager.cancel(this);
95634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills            mScheduled = false;
96634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        }
97e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    }
98e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti
99e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    @Override
100e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    public void onAlarm() {
101634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        // Once this method is called the alarm has already been fired and removed from
102634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
103634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        // be marked as unscheduled so that it can be rescheduled in the message handler.
104634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        final boolean stillScheduled;
105634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        synchronized (this) {
106634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills            stillScheduled = mScheduled;
107634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills            mScheduled = false;
108634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        }
109634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        if (stillScheduled) {
110eab17da5882e59caff25c73aa6bcd0587aca9dd4Lorenzo Colitti            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
111a457ebbda6c84d5f6abd055828ef02ceaf809c08Erik Kline            mHandler.dispatchMessage(msg);
112634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills            msg.recycle();
113634c1f9d0d43c7874ea433188b45fdf944d98a5aMitchell Wills        }
114e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti    }
115e9ae977322d40eff94fcbe3fad186cd082a577b6Lorenzo Colitti}
116