TimerReceiver.java revision c5deecb3c25796538d762857692182bf3e5f1e21
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; 21b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzsteinimport android.app.NotificationManager; 22815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.app.PendingIntent; 23815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.BroadcastReceiver; 24815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.Context; 25815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.Intent; 26dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.content.SharedPreferences; 27dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.preference.PreferenceManager; 28815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.util.Log; 29815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson 30dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport com.android.deskclock.DeskClock; 31b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzsteinimport com.android.deskclock.R; 325cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport com.android.deskclock.TimerRingService; 337cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelsonimport com.android.deskclock.Utils; 34dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 35dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport java.util.ArrayList; 36dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport java.util.Iterator; 37dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 38815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonpublic class TimerReceiver extends BroadcastReceiver { 39815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson private static final String TAG = "TimerReceiver"; 40815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson 4158c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas // Make this a large number to avoid the alarm ID's which seem to be 1, 2, ... 4258c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas // Must also be different than StopwatchService.NOTIFICATION_ID 4358c329f52d7952597ae7a4e88fc2ec9e15ddd93aRobyn Coultas private static final int IN_USE_NOTIFICATION_ID = Integer.MAX_VALUE - 2; 44b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 45dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson ArrayList<TimerObj> mTimers; 46dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 47dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson @Override 48815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson public void onReceive(final Context context, final Intent intent) { 494ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson if (Timers.LOGGING) { 504ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson Log.v(TAG, "Received intent " + intent.toString()); 514ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson } 52b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein String actionType = intent.getAction(); 53e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // This action does not need the timers data 54e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (Timers.NOTIF_IN_USE_CANCEL.equals(actionType)) { 55e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas cancelInUseNotification(context); 56e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas return; 57e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 58e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 59b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein // Get the updated timers data. 60b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (mTimers == null) { 61b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein mTimers = new ArrayList<TimerObj> (); 62b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 63b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 64b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein TimerObj.getTimersFromSharedPrefs(prefs, mTimers); 65815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson 66e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // These actions do not provide a timer ID, but do use the timers data 67e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (Timers.NOTIF_IN_USE_SHOW.equals(actionType)) { 68b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein showInUseNotification(context); 69b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return; 70e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (Timers.NOTIF_TIMES_UP_SHOW.equals(actionType)) { 71e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas showTimesUpNotification(context); 72b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return; 73e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (Timers.NOTIF_TIMES_UP_CANCEL.equals(actionType)) { 74e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas cancelTimesUpNotification(context); 75b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return; 76b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 77b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 78e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Remaining actions provide a timer Id 79e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (!intent.hasExtra(Timers.TIMER_INTENT_EXTRA)) { 80e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // No data to work with, do nothing 814ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson Log.e(TAG, "got intent without Timer data"); 82e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas return; 83e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 84815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson 85e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Get the timer out of the Intent 86e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas int timerId = intent.getIntExtra(Timers.TIMER_INTENT_EXTRA, -1); 87e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (timerId == -1) { 88e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.d(TAG, "OnReceive:intent without Timer data for " + actionType); 89b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 904ae58071f0a48099021e5d141ed98606cfe999ccIsaac Katzenelson 91e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas TimerObj t = Timers.findTimer(mTimers, timerId); 92b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 93b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (Timers.TIMES_UP.equals(actionType)) { 94dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson // Find the timer (if it doesn't exists, it was probably deleted). 95dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson if (t == null) { 96dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson Log.d(TAG, " timer not found in list - do nothing"); 97dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson return; 98dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } 99dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 100dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson t.mState = TimerObj.STATE_TIMESUP; 101dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson t.writeToSharedPref(prefs); 102733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas // Play ringtone by using TimerRingService service with a default alarm. 103dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson Log.d(TAG, "playing ringtone"); 104dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson Intent si = new Intent(); 1055cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson si.setClass(context, TimerRingService.class); 106dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson context.startService(si); 107dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 10898b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas // Update the in-use notification 1097cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelson if (getNextRunningTimer(mTimers, false, Utils.getTimeNow()) == null) { 110b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein // Found no running timers. 111b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein cancelInUseNotification(context); 11298b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas } else { 11398b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas showInUseNotification(context); 114dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } 115b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 11698b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas // Start the TimerAlertFullScreen activity. 11798b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas Intent timersAlert = new Intent(context, TimerAlertFullScreen.class); 11898b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas timersAlert.setFlags( 11998b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION); 12098b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas context.startActivity(timersAlert); 121b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } else if (Timers.TIMER_RESET.equals(actionType) 122b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein || Timers.DELETE_TIMER.equals(actionType) 123b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein || Timers.TIMER_DONE.equals(actionType)) { 12498b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas // Stop Ringtone if all timers are not in times-up status 125b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein stopRingtoneIfNoTimesup(context); 126e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (Timers.NOTIF_TIMES_UP_STOP.equals(actionType)) { 127e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Find the timer (if it doesn't exists, it was probably deleted). 128e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (t == null) { 129e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.d(TAG, "timer to stop not found in list - do nothing"); 130e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas return; 131e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (t.mState != TimerObj.STATE_TIMESUP) { 132e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.d(TAG, "action to stop but timer not in times-up state - do nothing"); 133e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas return; 134e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 135e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 136e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Update timer state 137d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang t.mState = t.getDeleteAfterUse() ? TimerObj.STATE_DELETED : TimerObj.STATE_RESTART; 138d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang t.mTimeLeft = t.mOriginalLength = t.mSetupLength; 139e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas t.writeToSharedPref(prefs); 140e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 141e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Flag to tell DeskClock to re-sync with the database 142e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas prefs.edit().putBoolean(Timers.FROM_NOTIFICATION, true).apply(); 143e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 144e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas cancelTimesUpNotification(context, t); 145e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 146e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Done with timer - delete from data base 147e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (t.getDeleteAfterUse()) { 148e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas t.deleteFromSharedPref(prefs); 149e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 150e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 151e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Stop Ringtone if no timers are in times-up status 152e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas stopRingtoneIfNoTimesup(context); 153e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (Timers.NOTIF_TIMES_UP_PLUS_ONE.equals(actionType)) { 154e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Find the timer (if it doesn't exists, it was probably deleted). 155e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (t == null) { 156e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.d(TAG, "timer to +1m not found in list - do nothing"); 157e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas return; 158e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (t.mState != TimerObj.STATE_TIMESUP) { 159e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.d(TAG, "action to +1m but timer not in times up state - do nothing"); 160e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas return; 161e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 162e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 163e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Restarting the timer with 1 minute left. 164e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas t.mState = TimerObj.STATE_RUNNING; 165e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas t.mStartTime = Utils.getTimeNow(); 166e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas t.mTimeLeft = t. mOriginalLength = TimerObj.MINUTE_IN_MILLIS; 167e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas t.writeToSharedPref(prefs); 168e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 169e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Flag to tell DeskClock to re-sync with the database 170e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas prefs.edit().putBoolean(Timers.FROM_NOTIFICATION, true).apply(); 171e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 172e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas cancelTimesUpNotification(context, t); 173e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 174e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // If the app is not open, refresh the in-use notification 175e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (!prefs.getBoolean(Timers.NOTIF_APP_OPEN, false)) { 176e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas showInUseNotification(context); 177e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 178e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 179e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Stop Ringtone if no timers are in times-up status 180e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas stopRingtoneIfNoTimesup(context); 181e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } else if (Timers.TIMER_UPDATE.equals(actionType)) { 1823c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro // Find the timer (if it doesn't exists, it was probably deleted). 1833c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro if (t == null) { 1843c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro Log.d(TAG, " timer to update not found in list - do nothing"); 1853c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro return; 1863c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro } 1873c16add0cffe1f7a537acca8537cdd3bf140ba97Budi Kusmiantoro 188e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Refresh buzzing notification 189e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (t.mState == TimerObj.STATE_TIMESUP) { 190e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Must cancel the previous notification to get all updates displayed correctly 191e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas cancelTimesUpNotification(context, t); 192e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas showTimesUpNotification(context, t); 193e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 194dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } 195dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson // Update the next "Times up" alarm 196b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein updateNextTimesup(context); 197b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 198b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 199b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private void stopRingtoneIfNoTimesup(final Context context) { 200b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (Timers.findExpiredTimer(mTimers) == null) { 201b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein // Stop ringtone 202b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Log.d(TAG, "stopping ringtone"); 203b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Intent si = new Intent(); 204b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein si.setClass(context, TimerRingService.class); 205b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein context.stopService(si); 206b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 207815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson } 208dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 209dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson // Scan all timers and find the one that will expire next. 210dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson // Tell AlarmManager to send a "Time's up" message to this receiver when this timer expires. 211dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson // If no timer exists, clear "time's up" message. 212dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson private void updateNextTimesup(Context context) { 2137cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelson TimerObj t = getNextRunningTimer(mTimers, false, Utils.getTimeNow()); 214b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long nextTimesup = (t == null) ? -1 : t.getTimesupTime(); 215b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein int timerId = (t == null) ? -1 : t.mTimerId; 216dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 217dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson Intent intent = new Intent(); 218dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson intent.setAction(Timers.TIMES_UP); 219dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson intent.setClass(context, TimerReceiver.class); 220b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (!mTimers.isEmpty()) { 221b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein intent.putExtra(Timers.TIMER_INTENT_EXTRA, timerId); 222dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } 223dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson AlarmManager mngr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); 224dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson PendingIntent p = PendingIntent.getBroadcast(context, 225dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); 226b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (t != null) { 227f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson if (Utils.isKitKatOrLater()) { 2284fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas mngr.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTimesup, p); 2294fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas } else { 2304fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas mngr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTimesup, p); 2314fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas } 232e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (Timers.LOGGING) { 233e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.d(TAG, "Setting times up to " + nextTimesup); 234e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 235dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } else { 236dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson mngr.cancel(p); 237e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (Timers.LOGGING) { 238e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.v(TAG, "no next times up"); 239e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 240dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } 241dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson } 242dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson 243b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private void showInUseNotification(final Context context) { 244b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 245b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein boolean appOpen = prefs.getBoolean(Timers.NOTIF_APP_OPEN, false); 246b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein ArrayList<TimerObj> timersInUse = Timers.timersInUse(mTimers); 247b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein int numTimersInUse = timersInUse.size(); 248b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 249b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (appOpen || numTimersInUse == 0) { 250b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return; 251b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 252b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 253b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein String title, contentText; 254b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Long nextBroadcastTime = null; 2557cff0e83debe70133aad4cf22163263b16d4a255Isaac Katzenelson long now = Utils.getTimeNow(); 256b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (timersInUse.size() == 1) { 257b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein TimerObj timer = timersInUse.get(0); 258d82ec8feb07d6d1f0f9539f75b1b84b3ae1e74d4Sam Blitzstein boolean timerIsTicking = timer.isTicking(); 259e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas String label = timer.getLabelOrDefault(context); 260d82ec8feb07d6d1f0f9539f75b1b84b3ae1e74d4Sam Blitzstein title = timerIsTicking ? label : context.getString(R.string.timer_stopped); 261d82ec8feb07d6d1f0f9539f75b1b84b3ae1e74d4Sam Blitzstein long timeLeft = timerIsTicking ? timer.getTimesupTime() - now : timer.mTimeLeft; 262b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein contentText = buildTimeRemaining(context, timeLeft); 26374be96baee671f1f62b4ed543ba793336012ef24Isaac Katzenelson if (timerIsTicking && timeLeft > TimerObj.MINUTE_IN_MILLIS) { 264b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein nextBroadcastTime = getBroadcastTime(now, timeLeft); 265b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 266b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } else { 267b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein TimerObj timer = getNextRunningTimer(timersInUse, false, now); 268b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (timer == null) { 269b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein // No running timers. 270b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein title = String.format( 271b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein context.getString(R.string.timers_stopped), numTimersInUse); 272b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein contentText = context.getString(R.string.all_timers_stopped_notif); 273b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } else { 274b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein // We have at least one timer running and other timers stopped. 275b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein title = String.format( 276b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein context.getString(R.string.timers_in_use), numTimersInUse); 277b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long completionTime = timer.getTimesupTime(); 278b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long timeLeft = completionTime - now; 279b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein contentText = String.format(context.getString(R.string.next_timer_notif), 280b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein buildTimeRemaining(context, timeLeft)); 28174be96baee671f1f62b4ed543ba793336012ef24Isaac Katzenelson if (timeLeft <= TimerObj.MINUTE_IN_MILLIS) { 282b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein TimerObj timerWithUpdate = getNextRunningTimer(timersInUse, true, now); 283b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (timerWithUpdate != null) { 284b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein completionTime = timerWithUpdate.getTimesupTime(); 285b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein timeLeft = completionTime - now; 286b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein nextBroadcastTime = getBroadcastTime(now, timeLeft); 287b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 288b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } else { 289b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein nextBroadcastTime = getBroadcastTime(now, timeLeft); 290b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 291b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 292b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 293b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein showCollapsedNotificationWithNext(context, title, contentText, nextBroadcastTime); 294b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 295b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 296b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private long getBroadcastTime(long now, long timeUntilBroadcast) { 297b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long seconds = timeUntilBroadcast / 1000; 298b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein seconds = seconds - ( (seconds / 60) * 60 ); 299b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return now + (seconds * 1000); 300b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 301b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 302b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private void showCollapsedNotificationWithNext( 303b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein final Context context, String title, String text, Long nextBroadcastTime) { 304b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Intent activityIntent = new Intent(context, DeskClock.class); 305b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 306b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein activityIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX); 307b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein PendingIntent pendingActivityIntent = PendingIntent.getActivity(context, 0, activityIntent, 308b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); 309b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein showCollapsedNotification(context, title, text, Notification.PRIORITY_HIGH, 310184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein pendingActivityIntent, IN_USE_NOTIFICATION_ID, false); 311b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 312b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (nextBroadcastTime == null) { 313b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return; 314b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 315b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Intent nextBroadcast = new Intent(); 316b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein nextBroadcast.setAction(Timers.NOTIF_IN_USE_SHOW); 317b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein PendingIntent pendingNextBroadcast = 318b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein PendingIntent.getBroadcast(context, 0, nextBroadcast, 0); 319b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein AlarmManager alarmManager = 320b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 321f1ce98a6e2972854968488d2a28adbc29364b0f9Isaac Katzenelson if (Utils.isKitKatOrLater()) { 3224fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas alarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextBroadcastTime, pendingNextBroadcast); 3234fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas } else { 3244fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas alarmManager.set(AlarmManager.ELAPSED_REALTIME, nextBroadcastTime, pendingNextBroadcast); 3254fd80b58da8ad66e0e4a23cbf7c900174727fb4eRobyn Coultas } 326b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 327b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 32872332c2290d17c344ece074726f72b35ea469f31Sam Blitzstein private static void showCollapsedNotification(final Context context, String title, String text, 329184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein int priority, PendingIntent pendingIntent, int notificationId, boolean showTicker) { 330184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein Notification.Builder builder = new Notification.Builder(context) 331692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setAutoCancel(false) 332692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setContentTitle(title) 333692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setContentText(text) 334692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setDeleteIntent(pendingIntent) 335692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setOngoing(true) 336692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setPriority(priority) 337692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setShowWhen(false) 338692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setSmallIcon(R.drawable.stat_notify_timer) 339692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setCategory(Notification.CATEGORY_ALARM); 340184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein if (showTicker) { 341184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein builder.setTicker(text); 342184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein } 343184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein 344184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein Notification notification = builder.build(); 345b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein notification.contentIntent = pendingIntent; 346b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein NotificationManager notificationManager = 347b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 348b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein notificationManager.notify(notificationId, notification); 349b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 350b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 351b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private String buildTimeRemaining(Context context, long timeLeft) { 352b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (timeLeft < 0) { 353b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein // We should never be here... 354b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Log.v(TAG, "Will not show notification for timer already expired."); 355b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return null; 356b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 357b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 358b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long hundreds, seconds, minutes, hours; 359b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein seconds = timeLeft / 1000; 360b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein minutes = seconds / 60; 361b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein seconds = seconds - minutes * 60; 362b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein hours = minutes / 60; 363b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein minutes = minutes - hours * 60; 364b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (hours > 99) { 365b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein hours = 0; 366b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 367b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 368b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein String hourSeq = (hours == 0) ? "" : 369b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein ( (hours == 1) ? context.getString(R.string.hour) : 370b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein context.getString(R.string.hours, Long.toString(hours)) ); 371b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein String minSeq = (minutes == 0) ? "" : 372b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein ( (minutes == 1) ? context.getString(R.string.minute) : 373b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein context.getString(R.string.minutes, Long.toString(minutes)) ); 374b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 375b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein boolean dispHour = hours > 0; 376b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein boolean dispMinute = minutes > 0; 377b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein int index = (dispHour ? 1 : 0) | (dispMinute ? 2 : 0); 378b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein String[] formats = context.getResources().getStringArray(R.array.timer_notifications); 379b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return String.format(formats[index], hourSeq, minSeq); 380b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 381b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 382b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private TimerObj getNextRunningTimer( 383b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein ArrayList<TimerObj> timers, boolean requireNextUpdate, long now) { 384b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long nextTimesup = Long.MAX_VALUE; 385b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein boolean nextTimerFound = false; 386b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein Iterator<TimerObj> i = timers.iterator(); 387b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein TimerObj t = null; 388b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein while(i.hasNext()) { 389b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein TimerObj tmp = i.next(); 390b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (tmp.mState == TimerObj.STATE_RUNNING) { 391b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long timesupTime = tmp.getTimesupTime(); 392b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein long timeLeft = timesupTime - now; 393b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (timesupTime < nextTimesup && (!requireNextUpdate || timeLeft > 60) ) { 394b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein nextTimesup = timesupTime; 395b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein nextTimerFound = true; 396b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein t = tmp; 397b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 398b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 399b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 400b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein if (nextTimerFound) { 401b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return t; 402b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } else { 403b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein return null; 404b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 405b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 406b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein 407b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein private void cancelInUseNotification(final Context context) { 408b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein NotificationManager notificationManager = 409b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 410b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein notificationManager.cancel(IN_USE_NOTIFICATION_ID); 411b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein } 412e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 413e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas private void showTimesUpNotification(final Context context) { 414e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas for (TimerObj timerObj : Timers.timersInTimesUp(mTimers) ) { 415e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas showTimesUpNotification(context, timerObj); 416e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 417e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 418e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 419e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas private void showTimesUpNotification(final Context context, TimerObj timerObj) { 420e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Content Intent. When clicked will show the timer full screen 421e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas PendingIntent contentIntent = PendingIntent.getActivity(context, timerObj.mTimerId, 422e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas new Intent(context, TimerAlertFullScreen.class).putExtra( 423e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Timers.TIMER_INTENT_EXTRA, timerObj.mTimerId), 424e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas PendingIntent.FLAG_UPDATE_CURRENT); 425e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 426e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Add one minute action button 427e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas PendingIntent addOneMinuteAction = PendingIntent.getBroadcast(context, timerObj.mTimerId, 428e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas new Intent(Timers.NOTIF_TIMES_UP_PLUS_ONE) 429e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .putExtra(Timers.TIMER_INTENT_EXTRA, timerObj.mTimerId), 430e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas PendingIntent.FLAG_UPDATE_CURRENT); 431e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 432e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Add stop/done action button 433d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang PendingIntent stopIntent = PendingIntent.getBroadcast(context, timerObj.mTimerId, 434e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas new Intent(Timers.NOTIF_TIMES_UP_STOP) 435e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .putExtra(Timers.TIMER_INTENT_EXTRA, timerObj.mTimerId), 436e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas PendingIntent.FLAG_UPDATE_CURRENT); 437e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 438e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Notification creation 439e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Notification notification = new Notification.Builder(context) 440e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setContentIntent(contentIntent) 441e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .addAction(R.drawable.ic_menu_add, 442e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas context.getResources().getString(R.string.timer_plus_1_min), 443e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas addOneMinuteAction) 444e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .addAction( 445e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas timerObj.getDeleteAfterUse() 446e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas ? android.R.drawable.ic_menu_close_clear_cancel 447c5deecb3c25796538d762857692182bf3e5f1e21rachelzhang : R.drawable.ic_notify_stop, 448e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas timerObj.getDeleteAfterUse() 449e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas ? context.getResources().getString(R.string.timer_done) 450c5deecb3c25796538d762857692182bf3e5f1e21rachelzhang : context.getResources().getString(R.string.timer_stop), 451d50ff479c37e33de776c339bc93df308f4ac7ab0rachelzhang stopIntent) 452e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setContentTitle(timerObj.getLabelOrDefault(context)) 453e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setContentText(context.getResources().getString(R.string.timer_times_up)) 454e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setSmallIcon(R.drawable.stat_notify_timer) 455e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setOngoing(true) 456e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setAutoCancel(false) 457e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setPriority(Notification.PRIORITY_MAX) 458e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setDefaults(Notification.DEFAULT_LIGHTS) 459e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .setWhen(0) 460692718499fc480f29a9aabcc3cb38ba6bb7847ceBudi Kusmiantoro .setCategory(Notification.CATEGORY_ALARM) 461e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas .build(); 462e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 463e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // Send the notification using the timer's id to identify the 464e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas // correct notification 465e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE)).notify( 466e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas timerObj.mTimerId, notification); 467e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (Timers.LOGGING) { 468e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.v(TAG, "Setting times-up notification for " 469e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas + timerObj.getLabelOrDefault(context) + " #" + timerObj.mTimerId); 470e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 471e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 472e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 473e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas private void cancelTimesUpNotification(final Context context) { 474e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas for (TimerObj timerObj : Timers.timersInTimesUp(mTimers) ) { 475e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas cancelTimesUpNotification(context, timerObj); 476e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 477e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 478e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas 479e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas private void cancelTimesUpNotification(final Context context, TimerObj timerObj) { 480e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas NotificationManager notificationManager = 481e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 482e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas notificationManager.cancel(timerObj.mTimerId); 483e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas if (Timers.LOGGING) { 484e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas Log.v(TAG, "Canceling times-up notification for " 485e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas + timerObj.getLabelOrDefault(context) + " #" + timerObj.mTimerId); 486e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 487e332c5744e5741a6149afd226e1f193111dcb7deRobyn Coultas } 48898b2b05e7a0cebcd6e065bdd0b25cb6eb86b497cRobyn Coultas} 489