TimerReceiver.java revision 7f5209b10f08a3919245552516e60b4f07982a04
1815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson/*
2815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * Copyright (C) 2012 The Android Open Source Project
3815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson *
4815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * Licensed under the Apache License, Version 2.0 (the "License");
5815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * you may not use this file except in compliance with the License.
6815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * You may obtain a copy of the License at
7815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson *
8815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson *      http://www.apache.org/licenses/LICENSE-2.0
9815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson *
10815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * Unless required by applicable law or agreed to in writing, software
11815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * distributed under the License is distributed on an "AS IS" BASIS,
12815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * See the License for the specific language governing permissions and
14815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson * limitations under the License.
15815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson */
16815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
17815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonpackage com.android.deskclock.timer;
18815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
19dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.app.AlarmManager;
20815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.app.Notification;
21815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.app.PendingIntent;
22815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.BroadcastReceiver;
23815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.Context;
24815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.Intent;
25dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.content.SharedPreferences;
26dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.preference.PreferenceManager;
27b7224ca55c54d7298d50f28f031197f442318a19Annie Chinimport android.support.v4.app.NotificationCompat;
28b7224ca55c54d7298d50f28f031197f442318a19Annie Chinimport android.support.v4.app.NotificationManagerCompat;
29815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.util.Log;
30815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
31dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport com.android.deskclock.DeskClock;
32b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzsteinimport com.android.deskclock.R;
335cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport com.android.deskclock.TimerRingService;
347cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelsonimport com.android.deskclock.Utils;
35dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
36dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport java.util.ArrayList;
37dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport java.util.Iterator;
38dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
39815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonpublic class TimerReceiver extends BroadcastReceiver {
40815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson    private static final String TAG = "TimerReceiver";
41815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
4258c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas    // Make this a large number to avoid the alarm ID's which seem to be 1, 2, ...
4358c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas    // Must also be different than StopwatchService.NOTIFICATION_ID
4458c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas    private static final int IN_USE_NOTIFICATION_ID = Integer.MAX_VALUE - 2;
45b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
46dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    ArrayList<TimerObj> mTimers;
47dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
48dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    @Override
49815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson    public void onReceive(final Context context, final Intent intent) {
504ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson        if (Timers.LOGGING) {
514ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson            Log.v(TAG, "Received intent " + intent.toString());
524ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson        }
53b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String actionType = intent.getAction();
54e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // This action does not need the timers data
55e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        if (Timers.NOTIF_IN_USE_CANCEL.equals(actionType)) {
56e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            cancelInUseNotification(context);
57e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            return;
58e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        }
59e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
60b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        // Get the updated timers data.
61b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (mTimers == null) {
62b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            mTimers = new ArrayList<TimerObj> ();
63b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
64b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
65b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        TimerObj.getTimersFromSharedPrefs(prefs, mTimers);
66815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
67e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // These actions do not provide a timer ID, but do use the timers data
68e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        if (Timers.NOTIF_IN_USE_SHOW.equals(actionType)) {
69b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            showInUseNotification(context);
70b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
71e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        } else if (Timers.NOTIF_TIMES_UP_SHOW.equals(actionType)) {
72e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            showTimesUpNotification(context);
73b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
74e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        } else if (Timers.NOTIF_TIMES_UP_CANCEL.equals(actionType)) {
75e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            cancelTimesUpNotification(context);
76b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
77b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
78b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
79e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Remaining actions provide a timer Id
80e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        if (!intent.hasExtra(Timers.TIMER_INTENT_EXTRA)) {
81e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // No data to work with, do nothing
824ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson            Log.e(TAG, "got intent without Timer data");
83e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            return;
84e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        }
85815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
86e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Get the timer out of the Intent
87e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        int timerId = intent.getIntExtra(Timers.TIMER_INTENT_EXTRA, -1);
88e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        if (timerId == -1) {
89e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            Log.d(TAG, "OnReceive:intent without Timer data for " + actionType);
90b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
914ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson
92e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        TimerObj t = Timers.findTimer(mTimers, timerId);
93b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
94b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (Timers.TIMES_UP.equals(actionType)) {
95dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            // Find the timer (if it doesn't exists, it was probably deleted).
96dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            if (t == null) {
97dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson                Log.d(TAG, " timer not found in list - do nothing");
98dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson                return;
99dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            }
100dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
101bae6862c87f851be4bbcbab57ac71ac5385c9850James Lemieux            t.setState(TimerObj.STATE_TIMESUP);
102dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            t.writeToSharedPref(prefs);
103733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas            // Play ringtone by using TimerRingService service with a default alarm.
104dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            Log.d(TAG, "playing ringtone");
105dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            Intent si = new Intent();
1065cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            si.setClass(context, TimerRingService.class);
107dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            context.startService(si);
108dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
10998b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            // Update the in-use notification
1107cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelson            if (getNextRunningTimer(mTimers, false, Utils.getTimeNow()) == null) {
111b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                // Found no running timers.
112b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                cancelInUseNotification(context);
11398b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            } else {
11498b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas                showInUseNotification(context);
115dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            }
116b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
11798b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            // Start the TimerAlertFullScreen activity.
11898b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            Intent timersAlert = new Intent(context, TimerAlertFullScreen.class);
11998b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            timersAlert.setFlags(
12098b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas                    Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
12198b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            context.startActivity(timersAlert);
122b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else if (Timers.TIMER_RESET.equals(actionType)
123b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                || Timers.DELETE_TIMER.equals(actionType)
124b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                || Timers.TIMER_DONE.equals(actionType)) {
12598b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas            // Stop Ringtone if all timers are not in times-up status
126b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            stopRingtoneIfNoTimesup(context);
127e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        } else if (Timers.NOTIF_TIMES_UP_STOP.equals(actionType)) {
128e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Find the timer (if it doesn't exists, it was probably deleted).
129e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (t == null) {
130e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                Log.d(TAG, "timer to stop not found in list - do nothing");
131e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                return;
132e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            } else if (t.mState != TimerObj.STATE_TIMESUP) {
133e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                Log.d(TAG, "action to stop but timer not in times-up state - do nothing");
134e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                return;
135e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
136e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
137e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Update timer state
138bae6862c87f851be4bbcbab57ac71ac5385c9850James Lemieux            t.setState(t.getDeleteAfterUse() ? TimerObj.STATE_DELETED : TimerObj.STATE_RESTART);
139d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang            t.mTimeLeft = t.mOriginalLength = t.mSetupLength;
140e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            t.writeToSharedPref(prefs);
141e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
142e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Flag to tell DeskClock to re-sync with the database
143bae6862c87f851be4bbcbab57ac71ac5385c9850James Lemieux            prefs.edit().putBoolean(Timers.REFRESH_UI_WITH_LATEST_DATA, true).apply();
144e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
145e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            cancelTimesUpNotification(context, t);
146e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
147e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Done with timer - delete from data base
148e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (t.getDeleteAfterUse()) {
149e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                t.deleteFromSharedPref(prefs);
150e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
151e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
152e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Stop Ringtone if no timers are in times-up status
153e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            stopRingtoneIfNoTimesup(context);
154e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        } else if (Timers.NOTIF_TIMES_UP_PLUS_ONE.equals(actionType)) {
155e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Find the timer (if it doesn't exists, it was probably deleted).
156e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (t == null) {
157e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                Log.d(TAG, "timer to +1m not found in list - do nothing");
158e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                return;
159e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            } else if (t.mState != TimerObj.STATE_TIMESUP) {
160e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                Log.d(TAG, "action to +1m but timer not in times up state - do nothing");
161e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                return;
162e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
163e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
164e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Restarting the timer with 1 minute left.
165bae6862c87f851be4bbcbab57ac71ac5385c9850James Lemieux            t.setState(TimerObj.STATE_RUNNING);
166e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            t.mStartTime = Utils.getTimeNow();
167e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            t.mTimeLeft = t. mOriginalLength = TimerObj.MINUTE_IN_MILLIS;
168e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            t.writeToSharedPref(prefs);
169e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
170e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Flag to tell DeskClock to re-sync with the database
171bae6862c87f851be4bbcbab57ac71ac5385c9850James Lemieux            prefs.edit().putBoolean(Timers.REFRESH_UI_WITH_LATEST_DATA, true).apply();
172e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
173e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            cancelTimesUpNotification(context, t);
174e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
175e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // If the app is not open, refresh the in-use notification
176e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (!prefs.getBoolean(Timers.NOTIF_APP_OPEN, false)) {
177e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                showInUseNotification(context);
178e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
179e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
180e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Stop Ringtone if no timers are in times-up status
181e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            stopRingtoneIfNoTimesup(context);
182e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        } else if (Timers.TIMER_UPDATE.equals(actionType)) {
1833c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro            // Find the timer (if it doesn't exists, it was probably deleted).
1843c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro            if (t == null) {
1853c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro                Log.d(TAG, " timer to update not found in list - do nothing");
1863c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro                return;
1873c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro            }
1883c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro
189e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            // Refresh buzzing notification
190e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (t.mState == TimerObj.STATE_TIMESUP) {
191e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                // Must cancel the previous notification to get all updates displayed correctly
192e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                cancelTimesUpNotification(context, t);
193e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                showTimesUpNotification(context, t);
194e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
195dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        }
196dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        // Update the next "Times up" alarm
197b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        updateNextTimesup(context);
198b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
199b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
200b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void stopRingtoneIfNoTimesup(final Context context) {
201b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (Timers.findExpiredTimer(mTimers) == null) {
202b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // Stop ringtone
203b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Log.d(TAG, "stopping ringtone");
204b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Intent si = new Intent();
205b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            si.setClass(context, TimerRingService.class);
206b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            context.stopService(si);
207b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
208815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson    }
209dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
210dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    // Scan all timers and find the one that will expire next.
211dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    // Tell AlarmManager to send a "Time's up" message to this receiver when this timer expires.
212dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    // If no timer exists, clear "time's up" message.
213dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    private void updateNextTimesup(Context context) {
2147cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelson        TimerObj t = getNextRunningTimer(mTimers, false, Utils.getTimeNow());
215b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long nextTimesup = (t == null) ? -1 : t.getTimesupTime();
216b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int timerId = (t == null) ? -1 : t.mTimerId;
217dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
218dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        Intent intent = new Intent();
219dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        intent.setAction(Timers.TIMES_UP);
220dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        intent.setClass(context, TimerReceiver.class);
22150733f22a2989a9e3df15ecbdb1ef2ea49bbce01Budi Kusmiantoro        // Time-critical, should be foreground
22250733f22a2989a9e3df15ecbdb1ef2ea49bbce01Budi Kusmiantoro        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
223b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (!mTimers.isEmpty()) {
224b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            intent.putExtra(Timers.TIMER_INTENT_EXTRA, timerId);
225dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        }
226dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        AlarmManager mngr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
227dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        PendingIntent p = PendingIntent.getBroadcast(context,
228dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson                0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
229b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (t != null) {
230f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson            if (Utils.isKitKatOrLater()) {
2314fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas                mngr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTimesup, p);
2324fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas            } else {
2334fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas                mngr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTimesup, p);
2344fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas            }
235e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (Timers.LOGGING) {
236e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                Log.d(TAG, "Setting times up to " + nextTimesup);
237e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
238dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        } else {
239dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            mngr.cancel(p);
240e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            if (Timers.LOGGING) {
241e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                Log.v(TAG, "no next times up");
242e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            }
243dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        }
244dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    }
245dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
246b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void showInUseNotification(final Context context) {
247b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
248b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean appOpen = prefs.getBoolean(Timers.NOTIF_APP_OPEN, false);
249b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        ArrayList<TimerObj> timersInUse = Timers.timersInUse(mTimers);
250b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int numTimersInUse = timersInUse.size();
251b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
252b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (appOpen || numTimersInUse == 0) {
253b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
254b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
255b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
256b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String title, contentText;
257b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Long nextBroadcastTime = null;
2587cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelson        long now = Utils.getTimeNow();
259b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (timersInUse.size() == 1) {
260b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            TimerObj timer = timersInUse.get(0);
261d82ec8feb07d6d1f0f9539f75b1b84b3ae1e74d4Sam Blitzstein            boolean timerIsTicking = timer.isTicking();
262e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            String label = timer.getLabelOrDefault(context);
263d82ec8feb07d6d1f0f9539f75b1b84b3ae1e74d4Sam Blitzstein            title = timerIsTicking ? label : context.getString(R.string.timer_stopped);
264d82ec8feb07d6d1f0f9539f75b1b84b3ae1e74d4Sam Blitzstein            long timeLeft = timerIsTicking ? timer.getTimesupTime() - now : timer.mTimeLeft;
265b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            contentText = buildTimeRemaining(context, timeLeft);
26674be96baee671f1f62b4ed543ba793336012ef24Isaac Katzenelson            if (timerIsTicking && timeLeft > TimerObj.MINUTE_IN_MILLIS) {
267b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                nextBroadcastTime = getBroadcastTime(now, timeLeft);
268b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
269b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else {
270b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            TimerObj timer = getNextRunningTimer(timersInUse, false, now);
271b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (timer == null) {
272b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                // No running timers.
273b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                title = String.format(
274b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        context.getString(R.string.timers_stopped), numTimersInUse);
275b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                contentText = context.getString(R.string.all_timers_stopped_notif);
276b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            } else {
277b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                // We have at least one timer running and other timers stopped.
278b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                title = String.format(
279b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        context.getString(R.string.timers_in_use), numTimersInUse);
280b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long completionTime = timer.getTimesupTime();
281b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long timeLeft = completionTime - now;
282b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                contentText = String.format(context.getString(R.string.next_timer_notif),
283b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        buildTimeRemaining(context, timeLeft));
28474be96baee671f1f62b4ed543ba793336012ef24Isaac Katzenelson                if (timeLeft <= TimerObj.MINUTE_IN_MILLIS) {
285b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    TimerObj timerWithUpdate = getNextRunningTimer(timersInUse, true, now);
286b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    if (timerWithUpdate != null) {
287b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        completionTime = timerWithUpdate.getTimesupTime();
288b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        timeLeft = completionTime - now;
289b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        nextBroadcastTime = getBroadcastTime(now, timeLeft);
290b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    }
291b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                } else {
292b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    nextBroadcastTime = getBroadcastTime(now, timeLeft);
293b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                }
294b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
295b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
296b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        showCollapsedNotificationWithNext(context, title, contentText, nextBroadcastTime);
297b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
298b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
299b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private long getBroadcastTime(long now, long timeUntilBroadcast) {
300b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long seconds = timeUntilBroadcast / 1000;
301b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        seconds = seconds - ( (seconds / 60) * 60 );
302b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        return now + (seconds * 1000);
303b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
304b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
305b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void showCollapsedNotificationWithNext(
306b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            final Context context, String title, String text, Long nextBroadcastTime) {
307b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Intent activityIntent = new Intent(context, DeskClock.class);
308b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
309b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        activityIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX);
310b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        PendingIntent pendingActivityIntent = PendingIntent.getActivity(context, 0, activityIntent,
311b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
312b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        showCollapsedNotification(context, title, text, NotificationCompat.PRIORITY_HIGH,
313184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein                pendingActivityIntent, IN_USE_NOTIFICATION_ID, false);
314b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
315b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (nextBroadcastTime == null) {
316b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
317b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
318b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Intent nextBroadcast = new Intent();
319b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        nextBroadcast.setAction(Timers.NOTIF_IN_USE_SHOW);
320b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        PendingIntent pendingNextBroadcast =
321b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                PendingIntent.getBroadcast(context, 0, nextBroadcast, 0);
322b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        AlarmManager alarmManager =
323b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
324f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson        if (Utils.isKitKatOrLater()) {
3254fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas            alarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextBroadcastTime, pendingNextBroadcast);
3264fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas        } else {
3274fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas            alarmManager.set(AlarmManager.ELAPSED_REALTIME, nextBroadcastTime, pendingNextBroadcast);
3284fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas        }
329b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
330b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
33172332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein    private static void showCollapsedNotification(final Context context, String title, String text,
332184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein            int priority, PendingIntent pendingIntent, int notificationId, boolean showTicker) {
333b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
334692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setAutoCancel(false)
335692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setContentTitle(title)
336692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setContentText(text)
337692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setDeleteIntent(pendingIntent)
338692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setOngoing(true)
339692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setPriority(priority)
340692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro                .setShowWhen(false)
341b7224ca55c54d7298d50f28f031197f442318a19Annie Chin                .setSmallIcon(R.drawable.stat_notify_timer)
342b7224ca55c54d7298d50f28f031197f442318a19Annie Chin                .setCategory(NotificationCompat.CATEGORY_ALARM)
343b7224ca55c54d7298d50f28f031197f442318a19Annie Chin                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
344b7224ca55c54d7298d50f28f031197f442318a19Annie Chin                .setLocalOnly(true);
345184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        if (showTicker) {
346184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein            builder.setTicker(text);
347184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        }
348184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein
349b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        final Notification notification = builder.build();
350b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        notification.contentIntent = pendingIntent;
351b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        NotificationManagerCompat.from(context).notify(notificationId, notification);
352b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
353b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
354b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private String buildTimeRemaining(Context context, long timeLeft) {
355b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (timeLeft < 0) {
356b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // We should never be here...
357b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Log.v(TAG, "Will not show notification for timer already expired.");
358b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return null;
359b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
360b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
361b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long hundreds, seconds, minutes, hours;
362b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        seconds = timeLeft / 1000;
363b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        minutes = seconds / 60;
364b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        seconds = seconds - minutes * 60;
365b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        hours = minutes / 60;
366b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        minutes = minutes - hours * 60;
367b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (hours > 99) {
368b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            hours = 0;
369b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
370b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
371b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String hourSeq = (hours == 0) ? "" :
372b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            ( (hours == 1) ? context.getString(R.string.hour) :
373b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                context.getString(R.string.hours, Long.toString(hours)) );
374b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String minSeq = (minutes == 0) ? "" :
375b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            ( (minutes == 1) ? context.getString(R.string.minute) :
376b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                context.getString(R.string.minutes, Long.toString(minutes)) );
377b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
378b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean dispHour = hours > 0;
379b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean dispMinute = minutes > 0;
380b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int index = (dispHour ? 1 : 0) | (dispMinute ? 2 : 0);
381b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String[] formats = context.getResources().getStringArray(R.array.timer_notifications);
382b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        return String.format(formats[index], hourSeq, minSeq);
383b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
384b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
385b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private TimerObj getNextRunningTimer(
386b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            ArrayList<TimerObj> timers, boolean requireNextUpdate, long now) {
387b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long nextTimesup = Long.MAX_VALUE;
388b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean nextTimerFound = false;
389b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Iterator<TimerObj> i = timers.iterator();
390b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        TimerObj t = null;
391b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        while(i.hasNext()) {
392b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            TimerObj tmp = i.next();
393b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (tmp.mState == TimerObj.STATE_RUNNING) {
394b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long timesupTime = tmp.getTimesupTime();
395b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long timeLeft = timesupTime - now;
396b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                if (timesupTime < nextTimesup && (!requireNextUpdate || timeLeft > 60) ) {
397b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    nextTimesup = timesupTime;
398b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    nextTimerFound = true;
399b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    t = tmp;
400b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                }
401b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
402b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
403b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (nextTimerFound) {
404b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return t;
405b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else {
406b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return null;
407b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
408b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
409b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
410b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void cancelInUseNotification(final Context context) {
411b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        NotificationManagerCompat.from(context).cancel(IN_USE_NOTIFICATION_ID);
412b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
413e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
414e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    private void showTimesUpNotification(final Context context) {
415e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        for (TimerObj timerObj : Timers.timersInTimesUp(mTimers) ) {
416e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            showTimesUpNotification(context, timerObj);
417e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        }
418e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    }
419e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
420e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    private void showTimesUpNotification(final Context context, TimerObj timerObj) {
421e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Content Intent. When clicked will show the timer full screen
422e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        PendingIntent contentIntent = PendingIntent.getActivity(context, timerObj.mTimerId,
423e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                new Intent(context, TimerAlertFullScreen.class).putExtra(
424e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        Timers.TIMER_INTENT_EXTRA, timerObj.mTimerId),
425e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                PendingIntent.FLAG_UPDATE_CURRENT);
426e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
427e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Add one minute action button
428e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        PendingIntent addOneMinuteAction = PendingIntent.getBroadcast(context, timerObj.mTimerId,
429e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                new Intent(Timers.NOTIF_TIMES_UP_PLUS_ONE)
430e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        .putExtra(Timers.TIMER_INTENT_EXTRA, timerObj.mTimerId),
431e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                PendingIntent.FLAG_UPDATE_CURRENT);
432e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
433e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Add stop/done action button
434d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang        PendingIntent stopIntent = PendingIntent.getBroadcast(context, timerObj.mTimerId,
435e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                new Intent(Timers.NOTIF_TIMES_UP_STOP)
436e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        .putExtra(Timers.TIMER_INTENT_EXTRA, timerObj.mTimerId),
437e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                PendingIntent.FLAG_UPDATE_CURRENT);
438e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
439e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Notification creation
440b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        final NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
441e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .setContentIntent(contentIntent)
442e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .addAction(R.drawable.ic_menu_add,
443e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        context.getResources().getString(R.string.timer_plus_1_min),
444e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        addOneMinuteAction)
445e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .addAction(
446e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        timerObj.getDeleteAfterUse()
447e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                                ? android.R.drawable.ic_menu_close_clear_cancel
4487f5209b10f08a3919245552516e60b4f07982a04Annie Chin                                : R.drawable.ic_stop_24dp,
449e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                        timerObj.getDeleteAfterUse()
450e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                                ? context.getResources().getString(R.string.timer_done)
451c5deecb3c25796538d762857692182bf3e5f1e21rachelzhang                                : context.getResources().getString(R.string.timer_stop),
452d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang                        stopIntent)
453e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .setContentTitle(timerObj.getLabelOrDefault(context))
454e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .setContentText(context.getResources().getString(R.string.timer_times_up))
455e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .setSmallIcon(R.drawable.stat_notify_timer)
456e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .setOngoing(true)
457e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                .setAutoCancel(false)
458b7224ca55c54d7298d50f28f031197f442318a19Annie Chin                .setPriority(NotificationCompat.PRIORITY_MAX)
459b7224ca55c54d7298d50f28f031197f442318a19Annie Chin                .setDefaults(NotificationCompat.DEFAULT_LIGHTS)
46079c464e19f63a44a416eb4844702a7ba772b9072Annie Chin                .setWhen(0);
46179c464e19f63a44a416eb4844702a7ba772b9072Annie Chin
462e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // Send the notification using the timer's id to identify the
463e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        // correct notification
464b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        NotificationManagerCompat.from(context).notify(timerObj.mTimerId, builder.build());
465e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        if (Timers.LOGGING) {
466e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            Log.v(TAG, "Setting times-up notification for "
467e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                    + timerObj.getLabelOrDefault(context) + " #" + timerObj.mTimerId);
468e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        }
469e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    }
470e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
471e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    private void cancelTimesUpNotification(final Context context) {
472e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        for (TimerObj timerObj : Timers.timersInTimesUp(mTimers) ) {
473e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            cancelTimesUpNotification(context, timerObj);
474e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        }
475e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    }
476e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas
477e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    private void cancelTimesUpNotification(final Context context, TimerObj timerObj) {
478b7224ca55c54d7298d50f28f031197f442318a19Annie Chin        NotificationManagerCompat.from(context).cancel(timerObj.mTimerId);
479e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        if (Timers.LOGGING) {
480e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas            Log.v(TAG, "Canceling times-up notification for "
481e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas                    + timerObj.getLabelOrDefault(context) + " #" + timerObj.mTimerId);
482e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas        }
483e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas    }
48498b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas}
485