AlertService.java revision 7321a0630aca3e5093d12f0e4f55da77620f53ed
1146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/*
2146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *
4146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * you may not use this file except in compliance with the License.
6146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * You may obtain a copy of the License at
7146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *
8146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project *
10146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * See the License for the specific language governing permissions and
14146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * limitations under the License.
15146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */
16146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
1723e7da3eacee7bceb105cdfc7b5329c7a43846d5Mason Tangpackage com.android.calendar.alerts;
1823e7da3eacee7bceb105cdfc7b5329c7a43846d5Mason Tang
194b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawaimport com.android.calendar.GeneralPreferences;
2023e7da3eacee7bceb105cdfc7b5329c7a43846d5Mason Tangimport com.android.calendar.R;
2123e7da3eacee7bceb105cdfc7b5329c7a43846d5Mason Tangimport com.android.calendar.R.string;
22146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
23146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.AlarmManager;
24146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.Notification;
25146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.NotificationManager;
26146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.app.Service;
27146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentResolver;
28e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chanimport android.content.ContentUris;
29146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.ContentValues;
30146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Context;
31146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.Intent;
32146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.content.SharedPreferences;
33146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.database.Cursor;
341fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shumaimport android.media.AudioManager;
35146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.net.Uri;
36146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Bundle;
37146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Handler;
38146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.HandlerThread;
39146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.IBinder;
40146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Looper;
41146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Message;
42146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.os.Process;
43146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.Attendees;
44146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.provider.Calendar.CalendarAlerts;
45146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.text.TextUtils;
46146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectimport android.util.Log;
47e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
48e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chanimport java.util.HashMap;
49146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
50146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project/**
51146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project * This service is used to handle calendar event reminders.
52146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project */
53146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Projectpublic class AlertService extends Service {
54e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    static final boolean DEBUG = true;
55146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final String TAG = "AlertService";
560e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
57146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private volatile Looper mServiceLooper;
58146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private volatile ServiceHandler mServiceHandler;
590e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
600e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan    private static final String[] ALERT_PROJECTION = new String[] {
61146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts._ID,                     // 0
62146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.EVENT_ID,                // 1
63146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.STATE,                   // 2
64146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.TITLE,                   // 3
65146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.EVENT_LOCATION,          // 4
66146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.SELF_ATTENDEE_STATUS,    // 5
67146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.ALL_DAY,                 // 6
68146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.ALARM_TIME,              // 7
69146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.MINUTES,                 // 8
70146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.BEGIN,                   // 9
71e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        CalendarAlerts.END,                     // 10
72146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
730e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
74146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_ID = 0;
75146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_EVENT_ID = 1;
76146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_STATE = 2;
77146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_TITLE = 3;
78146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_EVENT_LOCATION = 4;
79146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_SELF_ATTENDEE_STATUS = 5;
80146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_ALL_DAY = 6;
81146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_ALARM_TIME = 7;
82146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_MINUTES = 8;
83146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private static final int ALERT_INDEX_BEGIN = 9;
84e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    private static final int ALERT_INDEX_END = 10;
85146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
86e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    private static final String ACTIVE_ALERTS_SELECTION = "(" + CalendarAlerts.STATE + "=? OR "
87e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            + CalendarAlerts.STATE + "=?) AND " + CalendarAlerts.ALARM_TIME + "<=";
88146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
89e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    private static final String[] ACTIVE_ALERTS_SELECTION_ARGS = new String[] {
90e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            Integer.toString(CalendarAlerts.FIRED), Integer.toString(CalendarAlerts.SCHEDULED)
91146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    };
920e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
93e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    private static final String ACTIVE_ALERTS_SORT = "begin DESC, end DESC";
940e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
958af2529989a9b10a0bb84736695c22fc02a17a4aThe Android Open Source Project    void processMessage(Message msg) {
96146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Bundle bundle = (Bundle) msg.obj;
970e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
98146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // On reboot, update the notification bar with the contents of the
99146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        // CalendarAlerts table.
100146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        String action = bundle.getString("action");
101e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (DEBUG) {
102e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            Log.d(TAG, "" + bundle.getLong(android.provider.Calendar.CalendarAlerts.ALARM_TIME)
103e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    + " Action = " + action);
104e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        }
105e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
106146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        if (action.equals(Intent.ACTION_BOOT_COMPLETED)
107146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                || action.equals(Intent.ACTION_TIME_CHANGED)) {
108146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            doTimeChanged();
109146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            return;
110146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
111146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
112e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (!action.equals(android.provider.Calendar.EVENT_REMINDER_ACTION)
113e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                && !action.equals(Intent.ACTION_LOCALE_CHANGED)) {
114e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            Log.w(TAG, "Invalid action: " + action);
115e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            return;
116146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
117146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
118e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        updateAlertNotification(this);
119e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    }
120605a0901134c0840b2fcf0514b4c1f8bc10dc7e0Michael Chan
121e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    static boolean updateAlertNotification(Context context) {
122e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        ContentResolver cr = context.getContentResolver();
123e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        final long currentTime = System.currentTimeMillis();
1240e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
125e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        Cursor alertCursor = CalendarAlerts.query(cr, ALERT_PROJECTION, ACTIVE_ALERTS_SELECTION
126e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                + currentTime, ACTIVE_ALERTS_SELECTION_ARGS, ACTIVE_ALERTS_SORT);
1270e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
128e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (alertCursor == null || alertCursor.getCount() == 0) {
129146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            if (alertCursor != null) {
130146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                alertCursor.close();
131146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
132e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
133e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            if (DEBUG) Log.d(TAG, "No fired or scheduled alerts");
134e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            NotificationManager nm =
135e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
136e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            nm.cancel(0);
137e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            return false;
138146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1390e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
140e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (DEBUG) {
141e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            Log.d(TAG, "alert count:" + alertCursor.getCount());
142146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
1430e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
144e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        String notificationEventName = null;
145e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        String notificationEventLocation = null;
146e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        long notificationEventBegin = 0;
147e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        int notificationEventStatus = 0;
1487321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan        boolean notificationEventAllDay = true;
149e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        HashMap<Long, Long> eventIds = new HashMap<Long, Long>();
150e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        int numReminders = 0;
151e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        int numFired = 0;
152146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        try {
153e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            while (alertCursor.moveToNext()) {
154e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final long alertId = alertCursor.getLong(ALERT_INDEX_ID);
155e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final long eventId = alertCursor.getLong(ALERT_INDEX_EVENT_ID);
156e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final int minutes = alertCursor.getInt(ALERT_INDEX_MINUTES);
157e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final String eventName = alertCursor.getString(ALERT_INDEX_TITLE);
158e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final String location = alertCursor.getString(ALERT_INDEX_EVENT_LOCATION);
159e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final int status = alertCursor.getInt(ALERT_INDEX_SELF_ATTENDEE_STATUS);
160e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final boolean declined = status == Attendees.ATTENDEE_STATUS_DECLINED;
161e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final long beginTime = alertCursor.getLong(ALERT_INDEX_BEGIN);
162e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final long endTime = alertCursor.getLong(ALERT_INDEX_END);
163e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final Uri alertUri = ContentUris
164e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        .withAppendedId(CalendarAlerts.CONTENT_URI, alertId);
165e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                final long alarmTime = alertCursor.getLong(ALERT_INDEX_ALARM_TIME);
166e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                int state = alertCursor.getInt(ALERT_INDEX_STATE);
1677321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan                final boolean allDay = alertCursor.getInt(ALERT_INDEX_ALL_DAY) != 0;
168e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
169e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (DEBUG) {
170e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    Log.d(TAG, "alarmTime:" + alarmTime + " alertId:" + alertId
171e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                            + " eventId:" + eventId + " state: " + state + " minutes:" + minutes
172e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                            + " declined:" + declined + " beginTime:" + beginTime
173e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                            + " endTime:" + endTime);
174146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
1750e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
176e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                ContentValues values = new ContentValues();
177e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                int newState = -1;
178e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
179e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // Uncomment for the behavior of clearing out alerts after the
180e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // events ended. b/1880369
181e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                //
182e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // if (endTime < currentTime) {
183e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                //     newState = CalendarAlerts.DISMISSED;
184e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // } else
185e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
186e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // Remove declined events and duplicate alerts for the same event
187e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (!declined && eventIds.put(eventId, beginTime) == null) {
188e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    numReminders++;
189e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    if (state == CalendarAlerts.SCHEDULED) {
190e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        newState = CalendarAlerts.FIRED;
191e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        numFired++;
192e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
193e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        // Record the received time in the CalendarAlerts table.
194e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        // This is useful for finding bugs that cause alarms to be
195e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        // missed or delayed.
196e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        values.put(CalendarAlerts.RECEIVED_TIME, currentTime);
197e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    }
198e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                } else {
199e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    newState = CalendarAlerts.DISMISSED;
200e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    if (DEBUG) {
201e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        if (!declined) Log.d(TAG, "dropping dup alert for event " + eventId);
202146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                    }
203146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
204146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
205e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // Update row if state changed
206e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (newState != -1) {
207e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    values.put(CalendarAlerts.STATE, newState);
208e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    state = newState;
209146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2100e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
211e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (state == CalendarAlerts.FIRED) {
212e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    // Record the time posting to notification manager.
213e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    // This is used for debugging missed alarms.
214e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    values.put(CalendarAlerts.NOTIFY_TIME, currentTime);
215146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
2160e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
217e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // Write row to if anything changed
218e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (values.size() > 0) cr.update(alertUri, values, null, null);
2190e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
220e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (state != CalendarAlerts.FIRED) {
221e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    continue;
222e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                }
223146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
224e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // Pick an Event title for the notification panel by the latest
225e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // alertTime and give prefer accepted events in case of ties.
226e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                int newStatus;
227e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                switch (status) {
228e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    case Attendees.ATTENDEE_STATUS_ACCEPTED:
229e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        newStatus = 2;
230e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        break;
231e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    case Attendees.ATTENDEE_STATUS_TENTATIVE:
232e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        newStatus = 1;
233e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        break;
234e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    default:
235e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        newStatus = 0;
236e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                }
237e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
238e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // TODO Prioritize by "primary" calendar
239e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                // Assumes alerts are sorted by begin time in reverse
240e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                if (notificationEventName == null
241e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                        || (notificationEventBegin <= beginTime &&
242e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                                notificationEventStatus < newStatus)) {
243e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    notificationEventName = eventName;
244e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    notificationEventLocation = location;
245e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    notificationEventBegin = beginTime;
246e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                    notificationEventStatus = newStatus;
2477321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan                    notificationEventAllDay = allDay;
248146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                }
249146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
250146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        } finally {
251e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            if (alertCursor != null) {
252e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                alertCursor.close();
253e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            }
254146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2550e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
2564b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(context);
257cca9ecb23b079c47856af22f89f7a6f3dec7a492Mason Tang
2584b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        boolean doAlert = prefs.getBoolean(GeneralPreferences.KEY_ALERTS, true);
2594b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa        boolean doPopup = prefs.getBoolean(GeneralPreferences.KEY_ALERTS_POPUP, false);
2600e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
261e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        // TODO check for this before adding stuff to the alerts table.
262cca9ecb23b079c47856af22f89f7a6f3dec7a492Mason Tang        if (!doAlert) {
263e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            if (DEBUG) {
264146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Log.d(TAG, "alert preference is OFF");
265146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            }
266e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            return true;
267e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        }
268e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
269ccf4a12bc3b25c46d592d3f9116f52751b96010cMason Tang        boolean quietUpdate = numFired == 0;
270cca9ecb23b079c47856af22f89f7a6f3dec7a492Mason Tang        boolean highPriority = numFired > 0 && doPopup;
271e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        postNotification(context, prefs, notificationEventName, notificationEventLocation,
2727321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan                numReminders, quietUpdate, highPriority, notificationEventBegin,
2737321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan                notificationEventAllDay);
274e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
275e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        return true;
276e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    }
277e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
278e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    private static void postNotification(Context context, SharedPreferences prefs,
279ccf4a12bc3b25c46d592d3f9116f52751b96010cMason Tang            String eventName, String location, int numReminders,
2807321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan            boolean quietUpdate, boolean highPriority, long startMillis, boolean allDay) {
281e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (DEBUG) {
282e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            Log.d(TAG, "###### creating new alarm notification, numReminders: " + numReminders
283c9656c9e42d9bb640688648b9dfe8d9f4e16b47dMason Tang                    + (quietUpdate ? " QUIET" : " loud")
284c9656c9e42d9bb640688648b9dfe8d9f4e16b47dMason Tang                    + (highPriority ? " high-priority" : ""));
285146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2860e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
2870e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan        NotificationManager nm =
288e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
289146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
290e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (numReminders == 0) {
291e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            nm.cancel(0);
292e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            return;
293146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
2940e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
295e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        Notification notification = AlertReceiver.makeNewAlertNotification(context, eventName,
2967321a0630aca3e5093d12f0e4f55da77620f53edMichael Chan                location, numReminders, highPriority, startMillis, allDay);
297e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        notification.defaults |= Notification.DEFAULT_LIGHTS;
298e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
299e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        // Quietly update notification bar. Nothing new. Maybe something just got deleted.
300e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        if (!quietUpdate) {
301e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            // Flash ticker in status bar
302e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            notification.tickerText = eventName;
303e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            if (!TextUtils.isEmpty(location)) {
304e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                notification.tickerText = eventName + " - " + location;
305e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            }
306e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
307e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            // Generate either a pop-up dialog, status bar notification, or
308e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            // neither. Pop-up dialog and status bar notification may include a
309e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            // sound, an alert, or both. A status bar notification also includes
310e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            // a toast.
3111fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma
3121fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            // Find out the circumstances under which to vibrate.
3131fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            // Migrate from pre-Froyo boolean setting if necessary.
3141fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            String vibrateWhen; // "always" or "silent" or "never"
3154b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa            if(prefs.contains(GeneralPreferences.KEY_ALERTS_VIBRATE_WHEN))
3161fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            {
3171fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                // Look up Froyo setting
3181fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                vibrateWhen =
3194b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                    prefs.getString(GeneralPreferences.KEY_ALERTS_VIBRATE_WHEN, null);
3204b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa            } else if(prefs.contains(GeneralPreferences.KEY_ALERTS_VIBRATE)) {
3211fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                // No Froyo setting. Migrate pre-Froyo setting to new Froyo-defined value.
3221fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                boolean vibrate =
3234b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                    prefs.getBoolean(GeneralPreferences.KEY_ALERTS_VIBRATE, false);
3241fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                vibrateWhen = vibrate ?
3251fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                    context.getString(R.string.prefDefault_alerts_vibrate_true) :
3261fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                    context.getString(R.string.prefDefault_alerts_vibrate_false);
3271fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            } else {
3281fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                // No setting. Use Froyo-defined default.
3291fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                vibrateWhen = context.getString(R.string.prefDefault_alerts_vibrateWhen);
3301fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            }
3311fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            boolean vibrateAlways = vibrateWhen.equals("always");
3321fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            boolean vibrateSilent = vibrateWhen.equals("silent");
3331fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            AudioManager audioManager =
3341fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
3351fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            boolean nowSilent =
3361fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma                audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
337e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan
338e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            // Possibly generate a vibration
3391fec2207219842a71fbbb8567cd968ab61ce3c1cJim Shuma            if (vibrateAlways || (vibrateSilent && nowSilent)) {
340e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan                notification.defaults |= Notification.DEFAULT_VIBRATE;
341e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan            }
3420e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
3430e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan            // Possibly generate a sound. If 'Silent' is chosen, the ringtone
3440e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan            // string will be empty.
3450e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan            String reminderRingtone = prefs.getString(
3464b441bd6544fe6d11be75f974a41afd8fa040a4fDaisuke Miyakawa                    GeneralPreferences.KEY_ALERTS_RINGTONE, null);
3470e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan            notification.sound = TextUtils.isEmpty(reminderRingtone) ? null : Uri
3480e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan                    .parse(reminderRingtone);
349146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
350146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
351146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        nm.notify(0, notification);
352146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3530e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
354146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private void doTimeChanged() {
355146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        ContentResolver cr = getContentResolver();
356146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        Object service = getSystemService(Context.ALARM_SERVICE);
357146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        AlarmManager manager = (AlarmManager) service;
358146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        CalendarAlerts.rescheduleMissedAlarms(cr, this, manager);
359e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan        updateAlertNotification(this);
360146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
3610e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
362146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    private final class ServiceHandler extends Handler {
363146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public ServiceHandler(Looper looper) {
364146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            super(looper);
365146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        }
3660e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
367146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        @Override
368146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        public void handleMessage(Message msg) {
369146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            processMessage(msg);
370146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // NOTE: We MUST not call stopSelf() directly, since we need to
371146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            // make sure the wake lock acquired by AlertReceiver is released.
372146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project            AlertReceiver.finishStartingService(AlertService.this, msg.arg1);
3730e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan        }
374e2ae1ef8decfddcc4e5802483e92cab93c6fc67cMichael Chan    }
375146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
376146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
377146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onCreate() {
378146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        HandlerThread thread = new HandlerThread("AlertService",
379146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project                Process.THREAD_PRIORITY_BACKGROUND);
380146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        thread.start();
3810e7235b00fdf47c773592a324c4a62ef95d1dcf4Michael Chan
382146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mServiceLooper = thread.getLooper();
383146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mServiceHandler = new ServiceHandler(mServiceLooper);
384146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
385146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
386146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
387c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff    public int onStartCommand(Intent intent, int flags, int startId) {
388c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff        if (intent != null) {
389c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff            Message msg = mServiceHandler.obtainMessage();
390c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff            msg.arg1 = startId;
391c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff            msg.obj = intent.getExtras();
392c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff            mServiceHandler.sendMessage(msg);
393c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff        }
394c1dc950c9b5756937a1df44463cc09fdf0649420Ken Shirriff        return START_REDELIVER_INTENT;
395146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
396146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
397146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
398146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public void onDestroy() {
399146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        mServiceLooper.quit();
400146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
401146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project
402146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    @Override
403146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    public IBinder onBind(Intent intent) {
404146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project        return null;
405146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project    }
406146de36083f6ce8b7e8a1f974d3990594a36bfecThe Android Open Source Project}
407