TimerReceiver.java revision feabb7a335fb8c7644783d2dca53b864009054d8
163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson/* 263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * Copyright (C) 2012 The Android Open Source Project 363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * 463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * Licensed under the Apache License, Version 2.0 (the "License"); 563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * you may not use this file except in compliance with the License. 663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * You may obtain a copy of the License at 763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * 863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * http://www.apache.org/licenses/LICENSE-2.0 963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * 1063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * Unless required by applicable law or agreed to in writing, software 1163211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * distributed under the License is distributed on an "AS IS" BASIS, 1263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * See the License for the specific language governing permissions and 1463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson * limitations under the License. 1563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson */ 1663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 1763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonpackage com.android.deskclock.timer; 1863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 19871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelsonimport android.app.AlarmManager; 2063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.app.Notification; 211ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelsonimport android.app.NotificationManager; 2263211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.app.PendingIntent; 2363211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.content.BroadcastReceiver; 2463211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.content.Context; 2563211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.content.Intent; 26871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelsonimport android.content.SharedPreferences; 27871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelsonimport android.preference.PreferenceManager; 2863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonimport android.util.Log; 2963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 30871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelsonimport com.android.deskclock.DeskClock; 311ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelsonimport com.android.deskclock.R; 323f99104b4dc4df9a774ff7433084b8e483d88744Isaac Katzenelsonimport com.android.deskclock.TimerRingService; 33a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelsonimport com.android.deskclock.Utils; 34871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 35871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelsonimport java.util.ArrayList; 36871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelsonimport java.util.Iterator; 37871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 3863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelsonpublic class TimerReceiver extends BroadcastReceiver { 3963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson private static final String TAG = "TimerReceiver"; 4063211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 4164575cfee07cf0ec38f65a12055692f542e78e70Sam Blitzstein private static final int IN_USE_NOTIFICATION_ID = 2; 421ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 43871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson ArrayList<TimerObj> mTimers; 44871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 45871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson @Override 4663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson public void onReceive(final Context context, final Intent intent) { 471ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson int timer; 481ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson String actionType = intent.getAction(); 4963211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 501ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // Get the updated timers data. 511ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (mTimers == null) { 521ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson mTimers = new ArrayList<TimerObj> (); 531ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 541ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 551ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj.getTimersFromSharedPrefs(prefs, mTimers); 5663211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 5763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 581ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (intent.hasExtra(Timers.TIMER_INTENT_EXTRA)) { 591ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // Get the alarm out of the Intent 601ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson timer = intent.getIntExtra(Timers.TIMER_INTENT_EXTRA, -1); 611ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timer == -1) { 621ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Log.d(TAG, " got intent without Timer data: "+actionType); 631ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 641ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else if (Timers.NOTIF_IN_USE_SHOW.equals(actionType)){ 651ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson showInUseNotification(context); 661ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 671ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else if (Timers.NOTIF_IN_USE_CANCEL.equals(actionType)) { 681ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson cancelInUseNotification(context); 691ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 701ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else { 711ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // No data to work with, do nothing 721ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Log.d(TAG, " got intent without Timer data"); 731ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 741ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 751ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 761ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj t = Timers.findTimer(mTimers, timer); 7763211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson 781ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (intent.getBooleanExtra(Timers.UPDATE_NOTIFICATION, false)) { 791ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (Timers.TIMER_STOP.equals(actionType)) { 801ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (t == null) { 811ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Log.d(TAG, "timer not found in list - can't stop it."); 821ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 831ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 841ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson t.mState = TimerObj.STATE_DONE; 851ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson t.writeToSharedPref(prefs); 861ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson SharedPreferences.Editor editor = prefs.edit(); 871ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson editor.putBoolean(Timers.FROM_NOTIFICATION, true); 88a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelson editor.putLong(Timers.NOTIF_TIME, Utils.getTimeNow()); 891ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson editor.putInt(Timers.NOTIF_ID, timer); 901ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson editor.apply(); 91871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 921ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson stopRingtoneIfNoTimesup(context); 93871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 941ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Intent activityIntent = new Intent(context, DeskClock.class); 951ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 961ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson activityIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX); 971ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson context.startActivity(activityIntent); 981ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 991ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 1001ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 1011ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 1021ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (Timers.TIMES_UP.equals(actionType)) { 103871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson // Find the timer (if it doesn't exists, it was probably deleted). 104871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson if (t == null) { 105871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson Log.d(TAG, " timer not found in list - do nothing"); 106871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson return; 107871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } 108871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 109871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson t.mState = TimerObj.STATE_TIMESUP; 110871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson t.writeToSharedPref(prefs); 111647353dd437f8c075aa96f3b98efb84442e8b7bfRobyn Coultas // Play ringtone by using TimerRingService service with a default alarm. 112871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson Log.d(TAG, "playing ringtone"); 113871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson Intent si = new Intent(); 1143f99104b4dc4df9a774ff7433084b8e483d88744Isaac Katzenelson si.setClass(context, TimerRingService.class); 115871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson context.startService(si); 116871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 117feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas // Update the in-use notification 118a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelson if (getNextRunningTimer(mTimers, false, Utils.getTimeNow()) == null) { 1191ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // Found no running timers. 1201ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson cancelInUseNotification(context); 121feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas } else { 122feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas showInUseNotification(context); 123871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } 1241ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 125feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas // Start the TimerAlertFullScreen activity. 126feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas Intent timersAlert = new Intent(context, TimerAlertFullScreen.class); 127feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas timersAlert.setFlags( 128feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION); 129feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas context.startActivity(timersAlert); 1301ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else if (Timers.TIMER_RESET.equals(actionType) 1311ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson || Timers.DELETE_TIMER.equals(actionType) 1321ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson || Timers.TIMER_DONE.equals(actionType)) { 133feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas // Stop Ringtone if all timers are not in times-up status 1341ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson stopRingtoneIfNoTimesup(context); 135871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } 136871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson // Update the next "Times up" alarm 1371ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson updateNextTimesup(context); 1381ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 1391ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 1401ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private void stopRingtoneIfNoTimesup(final Context context) { 1411ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (Timers.findExpiredTimer(mTimers) == null) { 1421ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // Stop ringtone 1431ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Log.d(TAG, "stopping ringtone"); 1441ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Intent si = new Intent(); 1451ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson si.setClass(context, TimerRingService.class); 1461ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson context.stopService(si); 1471ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 14863211efa1565b5dc171938740ba183302d0e46f3Isaac Katzenelson } 149871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 150871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson // Scan all timers and find the one that will expire next. 151871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson // Tell AlarmManager to send a "Time's up" message to this receiver when this timer expires. 152871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson // If no timer exists, clear "time's up" message. 153871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson private void updateNextTimesup(Context context) { 154a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelson TimerObj t = getNextRunningTimer(mTimers, false, Utils.getTimeNow()); 1551ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long nextTimesup = (t == null) ? -1 : t.getTimesupTime(); 1561ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson int timerId = (t == null) ? -1 : t.mTimerId; 157871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 158871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson Intent intent = new Intent(); 159871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson intent.setAction(Timers.TIMES_UP); 160871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson intent.setClass(context, TimerReceiver.class); 1611ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (!mTimers.isEmpty()) { 1621ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson intent.putExtra(Timers.TIMER_INTENT_EXTRA, timerId); 163871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } 164871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson AlarmManager mngr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); 165871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson PendingIntent p = PendingIntent.getBroadcast(context, 166871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); 1671ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (t != null) { 168a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelson mngr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTimesup, p); 169871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson Log.d(TAG,"Setting times up to " + nextTimesup); 170871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } else { 171871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson Log.d(TAG,"canceling times up"); 172871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson mngr.cancel(p); 173871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } 174871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson } 175871d7d00b561dc0e100c5ac7f79542d20ae9578dIsaac Katzenelson 1761ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private void showInUseNotification(final Context context) { 1771ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 1781ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson boolean appOpen = prefs.getBoolean(Timers.NOTIF_APP_OPEN, false); 1791ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson ArrayList<TimerObj> timersInUse = Timers.timersInUse(mTimers); 1801ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson int numTimersInUse = timersInUse.size(); 1811ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 1821ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (appOpen || numTimersInUse == 0) { 1831ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 1841ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 1851ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 1861ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson String title, contentText; 1871ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Long nextBroadcastTime = null; 188a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelson long now = Utils.getTimeNow(); 1891ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timersInUse.size() == 1) { 1901ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj timer = timersInUse.get(0); 1910f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein String label = timer.mLabel.equals("") ? 1920f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein context.getString(R.string.timer_notification_label) : timer.mLabel; 1931ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson title = timer.isTicking() ? label : context.getString(R.string.timer_stopped); 1941ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long timeLeft = timer.isTicking() ? timer.getTimesupTime() - now : timer.mTimeLeft; 1951ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson contentText = buildTimeRemaining(context, timeLeft); 1961ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timeLeft > 60) { 1971ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson nextBroadcastTime = getBroadcastTime(now, timeLeft); 1981ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 1991ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else { 2001ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj timer = getNextRunningTimer(timersInUse, false, now); 2011ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timer == null) { 2021ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // No running timers. 2031ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson title = String.format( 2041ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson context.getString(R.string.timers_stopped), numTimersInUse); 2051ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson contentText = context.getString(R.string.all_timers_stopped_notif); 2061ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else { 2071ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // We have at least one timer running and other timers stopped. 2081ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson title = String.format( 2091ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson context.getString(R.string.timers_in_use), numTimersInUse); 2101ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long completionTime = timer.getTimesupTime(); 2111ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long timeLeft = completionTime - now; 2121ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson contentText = String.format(context.getString(R.string.next_timer_notif), 2131ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson buildTimeRemaining(context, timeLeft)); 2141ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timeLeft <= 60) { 2151ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj timerWithUpdate = getNextRunningTimer(timersInUse, true, now); 2161ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timerWithUpdate != null) { 2171ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson completionTime = timerWithUpdate.getTimesupTime(); 2181ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson timeLeft = completionTime - now; 2191ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson nextBroadcastTime = getBroadcastTime(now, timeLeft); 2201ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2211ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else { 2221ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson nextBroadcastTime = getBroadcastTime(now, timeLeft); 2231ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2241ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2251ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2261ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson showCollapsedNotificationWithNext(context, title, contentText, nextBroadcastTime); 2271ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2281ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 2291ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private long getBroadcastTime(long now, long timeUntilBroadcast) { 2301ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long seconds = timeUntilBroadcast / 1000; 2311ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson seconds = seconds - ( (seconds / 60) * 60 ); 2321ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return now + (seconds * 1000); 2331ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2341ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 2350f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein /** Public and static to allow timer fragment to update notification with new label. **/ 2360f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein public static void showExpiredAlarmNotification(Context context, TimerObj t) { 2370f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein Intent broadcastIntent = new Intent(); 2380f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein broadcastIntent.putExtra(Timers.TIMER_INTENT_EXTRA, t.mTimerId); 2390f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein broadcastIntent.setAction(Timers.TIMER_STOP); 2400f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein broadcastIntent.putExtra(Timers.UPDATE_NOTIFICATION, true); 2410f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein PendingIntent pendingBroadcastIntent = PendingIntent.getBroadcast( 2420f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein context, 0, broadcastIntent, 0); 2430f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein String label = t.mLabel.equals("") ? context.getString(R.string.timer_notification_label) : 2440f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein t.mLabel; 2450f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein String contentText = context.getString(R.string.timer_times_up); 2460f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein showCollapsedNotification(context, label, contentText, Notification.PRIORITY_MAX, 2470f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein pendingBroadcastIntent, t.mTimerId, true); 2480f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein } 2490f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein 2501ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private void showCollapsedNotificationWithNext( 2511ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson final Context context, String title, String text, Long nextBroadcastTime) { 2521ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Intent activityIntent = new Intent(context, DeskClock.class); 2531ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2541ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson activityIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX); 2551ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson PendingIntent pendingActivityIntent = PendingIntent.getActivity(context, 0, activityIntent, 2561ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); 2571ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson showCollapsedNotification(context, title, text, Notification.PRIORITY_HIGH, 25806077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein pendingActivityIntent, IN_USE_NOTIFICATION_ID, false); 2591ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 2601ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (nextBroadcastTime == null) { 2611ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return; 2621ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2631ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Intent nextBroadcast = new Intent(); 2641ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson nextBroadcast.setAction(Timers.NOTIF_IN_USE_SHOW); 2651ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson PendingIntent pendingNextBroadcast = 2661ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson PendingIntent.getBroadcast(context, 0, nextBroadcast, 0); 2671ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson AlarmManager alarmManager = 2681ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 269a65d3eb00d543735305221f86ce630c8650e65e2Isaac Katzenelson alarmManager.set(AlarmManager.ELAPSED_REALTIME, nextBroadcastTime, pendingNextBroadcast); 2701ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2711ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 2720f6e3350fed144e3909ba4e45f3006f042c0187cSam Blitzstein private static void showCollapsedNotification(final Context context, String title, String text, 27306077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein int priority, PendingIntent pendingIntent, int notificationId, boolean showTicker) { 27406077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein Notification.Builder builder = new Notification.Builder(context) 2751ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setAutoCancel(false) 2761ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setContentTitle(title) 2771ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setContentText(text) 2781ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setDeleteIntent(pendingIntent) 2791ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setOngoing(true) 2801ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setPriority(priority) 2811ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson .setShowWhen(false) 28206077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein .setSmallIcon(R.drawable.stat_notify_timer); 28306077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein if (showTicker) { 28406077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein builder.setTicker(text); 28506077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein } 28606077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein 28706077d25a16684bc4d26c1ee0c48db556983c86cSam Blitzstein Notification notification = builder.build(); 2881ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson notification.contentIntent = pendingIntent; 2891ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson NotificationManager notificationManager = 2901ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 2911ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson notificationManager.notify(notificationId, notification); 2921ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 2931ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 2941ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private String buildTimeRemaining(Context context, long timeLeft) { 2951ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timeLeft < 0) { 2961ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson // We should never be here... 2971ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Log.v(TAG, "Will not show notification for timer already expired."); 2981ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return null; 2991ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3001ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 3011ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long hundreds, seconds, minutes, hours; 3021ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson seconds = timeLeft / 1000; 3031ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson minutes = seconds / 60; 3041ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson seconds = seconds - minutes * 60; 3051ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson hours = minutes / 60; 3061ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson minutes = minutes - hours * 60; 3071ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (hours > 99) { 3081ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson hours = 0; 3091ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3101ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 3111ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson String hourSeq = (hours == 0) ? "" : 3121ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson ( (hours == 1) ? context.getString(R.string.hour) : 3131ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson context.getString(R.string.hours, Long.toString(hours)) ); 3141ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson String minSeq = (minutes == 0) ? "" : 3151ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson ( (minutes == 1) ? context.getString(R.string.minute) : 3161ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson context.getString(R.string.minutes, Long.toString(minutes)) ); 3171ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 3181ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson boolean dispHour = hours > 0; 3191ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson boolean dispMinute = minutes > 0; 3201ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson int index = (dispHour ? 1 : 0) | (dispMinute ? 2 : 0); 3211ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson String[] formats = context.getResources().getStringArray(R.array.timer_notifications); 3221ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return String.format(formats[index], hourSeq, minSeq); 3231ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3241ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 3251ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private TimerObj getNextRunningTimer( 3261ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson ArrayList<TimerObj> timers, boolean requireNextUpdate, long now) { 3271ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long nextTimesup = Long.MAX_VALUE; 3281ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson boolean nextTimerFound = false; 3291ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson Iterator<TimerObj> i = timers.iterator(); 3301ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj t = null; 3311ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson while(i.hasNext()) { 3321ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson TimerObj tmp = i.next(); 3331ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (tmp.mState == TimerObj.STATE_RUNNING) { 3341ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long timesupTime = tmp.getTimesupTime(); 3351ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson long timeLeft = timesupTime - now; 3361ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (timesupTime < nextTimesup && (!requireNextUpdate || timeLeft > 60) ) { 3371ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson nextTimesup = timesupTime; 3381ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson nextTimerFound = true; 3391ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson t = tmp; 3401ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3411ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3421ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3431ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson if (nextTimerFound) { 3441ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return t; 3451ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } else { 3461ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson return null; 3471ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3481ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 3491ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson 3501ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson private void cancelInUseNotification(final Context context) { 3511ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson NotificationManager notificationManager = 3521ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 3531ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson notificationManager.cancel(IN_USE_NOTIFICATION_ID); 3541ce69abc1f8bea2d7903f24ee32fec42cee83634Itzhak Katzenelson } 355feabb7a335fb8c7644783d2dca53b864009054d8Robyn Coultas} 356