TimerReceiver.java revision 184aa695ef173081a692be38d9b23560ad34b789
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;
20733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultasimport android.app.KeyguardManager;
21815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.app.Notification;
22b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzsteinimport android.app.NotificationManager;
23815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.app.PendingIntent;
24815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.BroadcastReceiver;
25815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.Context;
26815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.content.Intent;
27dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.content.SharedPreferences;
28dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport android.preference.PreferenceManager;
29815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelsonimport android.util.Log;
30815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
31733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultasimport com.android.deskclock.AlarmAlertFullScreen;
32dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelsonimport com.android.deskclock.DeskClock;
33b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzsteinimport com.android.deskclock.R;
345cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelsonimport com.android.deskclock.TimerRingService;
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
422d0cd10f351ac3c0d04850f019d8803d100b2a1aSam Blitzstein    private static final int IN_USE_NOTIFICATION_ID = 2;
43b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
44dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    ArrayList<TimerObj> mTimers;
45dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
46dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    @Override
47815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson    public void onReceive(final Context context, final Intent intent) {
48b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int timer;
49b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String actionType = intent.getAction();
50815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
51b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        // Get the updated timers data.
52b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (mTimers == null) {
53b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            mTimers = new ArrayList<TimerObj> ();
54b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
55b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
56b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        TimerObj.getTimersFromSharedPrefs(prefs, mTimers);
57815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
58815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
59b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (intent.hasExtra(Timers.TIMER_INTENT_EXTRA)) {
60b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // Get the alarm out of the Intent
61b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            timer = intent.getIntExtra(Timers.TIMER_INTENT_EXTRA, -1);
62b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (timer == -1) {
63b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                Log.d(TAG, " got intent without Timer data: "+actionType);
64b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
65b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else if (Timers.NOTIF_IN_USE_SHOW.equals(actionType)){
66b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            showInUseNotification(context);
67b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
68b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else if (Timers.NOTIF_IN_USE_CANCEL.equals(actionType)) {
69b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            cancelInUseNotification(context);
70b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
71b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else {
72b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // No data to work with, do nothing
73b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Log.d(TAG, " got intent without Timer data");
74b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
75b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
76b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
77b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        TimerObj t = Timers.findTimer(mTimers, timer);
78815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson
79b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (intent.getBooleanExtra(Timers.UPDATE_NOTIFICATION, false)) {
80b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (Timers.TIMER_STOP.equals(actionType)) {
81b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                if (t == null) {
82b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    Log.d(TAG, "timer not found in list - can't stop it.");
83b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    return;
84b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                }
85b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                t.mState = TimerObj.STATE_DONE;
86b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                t.writeToSharedPref(prefs);
87b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                SharedPreferences.Editor editor = prefs.edit();
88b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                editor.putBoolean(Timers.FROM_NOTIFICATION, true);
89b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                editor.putLong(Timers.NOTIF_TIME, System.currentTimeMillis());
90b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                editor.putInt(Timers.NOTIF_ID, timer);
91b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                editor.apply();
92dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
93b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                stopRingtoneIfNoTimesup(context);
94dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
95b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                Intent activityIntent = new Intent(context, DeskClock.class);
96b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
97b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                activityIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX);
98b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                context.startActivity(activityIntent);
99b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
100b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein             return;
101b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
102b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
103b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (Timers.TIMES_UP.equals(actionType)) {
104dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            // Find the timer (if it doesn't exists, it was probably deleted).
105dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            if (t == null) {
106dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson                Log.d(TAG, " timer not found in list - do nothing");
107dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson                return;
108dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            }
109dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
110dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            t.mState = TimerObj.STATE_TIMESUP;
111dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            t.writeToSharedPref(prefs);
112733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas            // Play ringtone by using TimerRingService service with a default alarm.
113dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            Log.d(TAG, "playing ringtone");
114dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            Intent si = new Intent();
1155cacdd0b56950cf6a5f28e780ed07625a81bde53Isaac Katzenelson            si.setClass(context, TimerRingService.class);
116dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            context.startService(si);
117dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
118b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // Start notification for buzzing alarm.
119b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Intent broadcastIntent = new Intent();
120b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            broadcastIntent.putExtra(Timers.TIMER_INTENT_EXTRA, t.mTimerId);
121b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            broadcastIntent.setAction(Timers.TIMER_STOP);
122b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            broadcastIntent.putExtra(Timers.UPDATE_NOTIFICATION, true);
123b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            PendingIntent pendingBroadcastIntent = PendingIntent.getBroadcast(
124b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    context, 0, broadcastIntent, 0);
125b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            String label = t.mLabel == "" ? context.getString(R.string.timer_notification_label) :
126b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                t.mLabel;
127b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            String contentText = context.getString(R.string.timer_times_up);
128b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            showCollapsedNotification(context, label, contentText, Notification.PRIORITY_MAX,
129184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein                    pendingBroadcastIntent, t.mTimerId, true);
1302d0cd10f351ac3c0d04850f019d8803d100b2a1aSam Blitzstein            cancelInUseNotification(context);
131b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
132733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas            KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
133733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas            if (!km.inKeyguardRestrictedInputMode()) {
134733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                // Start the DeskClock Activity
135733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                Intent i = new Intent();
136733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                i.setClass(context, DeskClock.class);
137733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
138733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                i.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX);
139733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                context.startActivity(i);
140733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas            } else {
141733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                // Start the TimerAlertFullScreen activity.
142733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                Intent timersAlert = new Intent(context, TimerAlertFullScreen.class);
143733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                timersAlert.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_USER_ACTION);
144733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas                context.startActivity(timersAlert);
145733afe52e37148f2f1d36436c1a1eadcad5b471bRobyn Coultas            }
146dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
147b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // Cancel the inuse notification if none are inuse.
148b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (getNextRunningTimer(mTimers, false, System.currentTimeMillis()) == null) {
149b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                // Found no running timers.
150b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                cancelInUseNotification(context);
151dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            }
152b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
153b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else if (Timers.TIMER_RESET.equals(actionType)
154b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                || Timers.DELETE_TIMER.equals(actionType)
155b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                || Timers.TIMER_DONE.equals(actionType)) {
156b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // Stop Ringtone if all timers are not in timesup status
157b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            stopRingtoneIfNoTimesup(context);
158dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        }
159dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        // Update the next "Times up" alarm
160b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        updateNextTimesup(context);
161b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
162b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
163b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void stopRingtoneIfNoTimesup(final Context context) {
164b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (Timers.findExpiredTimer(mTimers) == null) {
165b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // Stop ringtone
166b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Log.d(TAG, "stopping ringtone");
167b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Intent si = new Intent();
168b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            si.setClass(context, TimerRingService.class);
169b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            context.stopService(si);
170b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
171815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson    }
172dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
173dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    // Scan all timers and find the one that will expire next.
174dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    // Tell AlarmManager to send a "Time's up" message to this receiver when this timer expires.
175dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    // If no timer exists, clear "time's up" message.
176dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    private void updateNextTimesup(Context context) {
177b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        TimerObj t = getNextRunningTimer(mTimers, false, System.currentTimeMillis());
178b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long nextTimesup = (t == null) ? -1 : t.getTimesupTime();
179b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int timerId = (t == null) ? -1 : t.mTimerId;
180dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
181dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        Intent intent = new Intent();
182dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        intent.setAction(Timers.TIMES_UP);
183dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        intent.setClass(context, TimerReceiver.class);
184b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (!mTimers.isEmpty()) {
185b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            intent.putExtra(Timers.TIMER_INTENT_EXTRA, timerId);
186dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        }
187dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        AlarmManager mngr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
188dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        PendingIntent p = PendingIntent.getBroadcast(context,
189dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson                0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
190b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (t != null) {
191dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            mngr.set(AlarmManager.RTC_WAKEUP, nextTimesup, p);
192dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            Log.d(TAG,"Setting times up to " + nextTimesup);
193dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        } else {
194dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            Log.d(TAG,"canceling times up");
195dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson            mngr.cancel(p);
196dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson        }
197dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson    }
198dfb182f455aa07eb7319d32df6d9a14492884e2fIsaac Katzenelson
199b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void showInUseNotification(final Context context) {
200b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
201b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean appOpen = prefs.getBoolean(Timers.NOTIF_APP_OPEN, false);
202b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        ArrayList<TimerObj> timersInUse = Timers.timersInUse(mTimers);
203b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int numTimersInUse = timersInUse.size();
204b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
205b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (appOpen || numTimersInUse == 0) {
206b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
207b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
208b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
209b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String title, contentText;
210b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Long nextBroadcastTime = null;
2112d0cd10f351ac3c0d04850f019d8803d100b2a1aSam Blitzstein        long now = System.currentTimeMillis();
212b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (timersInUse.size() == 1) {
213b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            TimerObj timer = timersInUse.get(0);
214b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            String label = timer.mLabel == "" ? context.getString(R.string.timer_notification_label)
215b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    : timer.mLabel;
216b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            title = timer.isTicking() ? label : context.getString(R.string.timer_stopped);
217b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            long timeLeft = timer.isTicking() ? timer.getTimesupTime() - now : timer.mTimeLeft;
218b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            contentText = buildTimeRemaining(context, timeLeft);
219b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (timeLeft > 60) {
220b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                nextBroadcastTime = getBroadcastTime(now, timeLeft);
221b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
222b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else {
223b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            TimerObj timer = getNextRunningTimer(timersInUse, false, now);
224b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (timer == null) {
225b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                // No running timers.
226b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                title = String.format(
227b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        context.getString(R.string.timers_stopped), numTimersInUse);
228b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                contentText = context.getString(R.string.all_timers_stopped_notif);
229b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            } else {
230b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                // We have at least one timer running and other timers stopped.
231b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                title = String.format(
232b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        context.getString(R.string.timers_in_use), numTimersInUse);
233b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long completionTime = timer.getTimesupTime();
234b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long timeLeft = completionTime - now;
235b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                contentText = String.format(context.getString(R.string.next_timer_notif),
236b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        buildTimeRemaining(context, timeLeft));
237b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                if (timeLeft <= 60) {
238b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    TimerObj timerWithUpdate = getNextRunningTimer(timersInUse, true, now);
239b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    if (timerWithUpdate != null) {
240b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        completionTime = timerWithUpdate.getTimesupTime();
241b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        timeLeft = completionTime - now;
242b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                        nextBroadcastTime = getBroadcastTime(now, timeLeft);
243b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    }
244b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                } else {
245b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    nextBroadcastTime = getBroadcastTime(now, timeLeft);
246b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                }
247b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
248b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
249b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        showCollapsedNotificationWithNext(context, title, contentText, nextBroadcastTime);
250b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
251b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
252b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private long getBroadcastTime(long now, long timeUntilBroadcast) {
253b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long seconds = timeUntilBroadcast / 1000;
254b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        seconds = seconds - ( (seconds / 60) * 60 );
255b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        return now + (seconds * 1000);
256b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
257b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
258b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void showCollapsedNotificationWithNext(
259b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            final Context context, String title, String text, Long nextBroadcastTime) {
260b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Intent activityIntent = new Intent(context, DeskClock.class);
261b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
262b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        activityIntent.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX);
263b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        PendingIntent pendingActivityIntent = PendingIntent.getActivity(context, 0, activityIntent,
264b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
265b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        showCollapsedNotification(context, title, text, Notification.PRIORITY_HIGH,
266184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein                pendingActivityIntent, IN_USE_NOTIFICATION_ID, false);
267b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
268b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (nextBroadcastTime == null) {
269b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return;
270b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
271b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Intent nextBroadcast = new Intent();
272b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        nextBroadcast.setAction(Timers.NOTIF_IN_USE_SHOW);
273b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        PendingIntent pendingNextBroadcast =
274b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                PendingIntent.getBroadcast(context, 0, nextBroadcast, 0);
275b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        AlarmManager alarmManager =
276b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
277b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        alarmManager.set(AlarmManager.RTC, nextBroadcastTime, pendingNextBroadcast);
278b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
279b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
280b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void showCollapsedNotification(final Context context, String title, String text,
281184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein            int priority, PendingIntent pendingIntent, int notificationId, boolean showTicker) {
282184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        Notification.Builder builder = new Notification.Builder(context)
283b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setAutoCancel(false)
284b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setContentTitle(title)
285b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setContentText(text)
286b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setDeleteIntent(pendingIntent)
287b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setOngoing(true)
288b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setPriority(priority)
289b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        .setShowWhen(false)
290184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        .setSmallIcon(R.drawable.stat_notify_timer);
291184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        if (showTicker) {
292184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein            builder.setTicker(text);
293184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        }
294184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein
295184aa695ef173081a692be38d9b23560ad34b789Sam Blitzstein        Notification notification = builder.build();
296b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        notification.contentIntent = pendingIntent;
297b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        NotificationManager notificationManager =
298b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
299b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        notificationManager.notify(notificationId, notification);
300b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
301b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
302b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private String buildTimeRemaining(Context context, long timeLeft) {
303b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (timeLeft < 0) {
304b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            // We should never be here...
305b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            Log.v(TAG, "Will not show notification for timer already expired.");
306b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return null;
307b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
308b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
309b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long hundreds, seconds, minutes, hours;
310b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        seconds = timeLeft / 1000;
311b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        minutes = seconds / 60;
312b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        seconds = seconds - minutes * 60;
313b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        hours = minutes / 60;
314b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        minutes = minutes - hours * 60;
315b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (hours > 99) {
316b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            hours = 0;
317b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
318b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
319b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String hourSeq = (hours == 0) ? "" :
320b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            ( (hours == 1) ? context.getString(R.string.hour) :
321b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                context.getString(R.string.hours, Long.toString(hours)) );
322b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String minSeq = (minutes == 0) ? "" :
323b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            ( (minutes == 1) ? context.getString(R.string.minute) :
324b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                context.getString(R.string.minutes, Long.toString(minutes)) );
325b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
326b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean dispHour = hours > 0;
327b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean dispMinute = minutes > 0;
328b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        int index = (dispHour ? 1 : 0) | (dispMinute ? 2 : 0);
329b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        String[] formats = context.getResources().getStringArray(R.array.timer_notifications);
330b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        return String.format(formats[index], hourSeq, minSeq);
331b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
332b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
333b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private TimerObj getNextRunningTimer(
334b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            ArrayList<TimerObj> timers, boolean requireNextUpdate, long now) {
335b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        long nextTimesup = Long.MAX_VALUE;
336b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        boolean nextTimerFound = false;
337b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        Iterator<TimerObj> i = timers.iterator();
338b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        TimerObj t = null;
339b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        while(i.hasNext()) {
340b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            TimerObj tmp = i.next();
341b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            if (tmp.mState == TimerObj.STATE_RUNNING) {
342b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long timesupTime = tmp.getTimesupTime();
343b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                long timeLeft = timesupTime - now;
344b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                if (timesupTime < nextTimesup && (!requireNextUpdate || timeLeft > 60) ) {
345b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    nextTimesup = timesupTime;
346b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    nextTimerFound = true;
347b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                    t = tmp;
348b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                }
349b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            }
350b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
351b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        if (nextTimerFound) {
352b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return t;
353b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        } else {
354b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein            return null;
355b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        }
356b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
357b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein
358b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    private void cancelInUseNotification(final Context context) {
359b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        NotificationManager notificationManager =
360b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
361b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein        notificationManager.cancel(IN_USE_NOTIFICATION_ID);
362b6a815a52fd31a96b51e51ef6275a68bed73c2c5Sam Blitzstein    }
363815e2f7431c590086d5bd4eee5d7bf08108c77ebIsaac Katzenelson}