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