Add notifications for new voicemails.
New voicemails trigger a broadcast: receive the broadcast and show the
notification in the status bar for it.
Lookup the number and contact name (if any) and include those in the
notification.
Bug: 4968670
Change-Id: I7c68458696199c47fe49b37a732fe10ce24e3fe9
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index f4c6227..56bf4e5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -612,6 +612,16 @@
android:resource="@xml/social_widget_info" />
</receiver>
+ <receiver android:name=".calllog.NewVoicemailReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.NEW_VOICEMAIL" />
+ <data
+ android:scheme="content"
+ android:host="com.android.voicemail"
+ />
+ </intent-filter>
+ </receiver>
+
<activity
android:name=".socialwidget.SocialWidgetConfigureActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar" >
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0064a8b..a2baaa2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1021,7 +1021,7 @@
<!-- Button caption that allows the user to clear the defaults (like primary email) of one
contact. [CHAR LIMIT=15] -->
<string name="quickcontact_clear_defaults_button">Clear</string>
-
+
<!-- The menu item to open the list of accounts -->
<string name="menu_accounts">Accounts</string>
@@ -1427,7 +1427,7 @@
contact aggregation suggestion in Contact editor. [CHAR LIMIT=128]-->
<string name="aggregation_suggestion_edit_dialog_title">Edit selected contacts</string>
- <!-- The message in a confirmation dialog shown when the user selects a
+ <!-- The message in a confirmation dialog shown when the user selects a
contact aggregation suggestion in Contact editor. [CHAR LIMIT=512]-->
<string name="aggregation_suggestion_edit_dialog_message">Switch to editing
the selected contact? Information you entered so far will be copied.</string>
@@ -1542,7 +1542,7 @@
</plurals>
<!-- Confirmation message of the dialog that allows deletion of a contact group [CHAR LIMIT=256] -->
- <string name="delete_group_dialog_message">Are you sure you want to delete the group
+ <string name="delete_group_dialog_message">Are you sure you want to delete the group
\'<xliff:g id="group_label" example="Friends">%1$s</xliff:g>\'?
(Contacts themselves will not be deleted.)
</string>
@@ -1558,7 +1558,7 @@
<!-- Toast shown when text is copied to the clipboard [CHAR LIMIT=64] -->
<string name="toast_text_copied">Text copied</string>
-
+
<!-- Title of the alert dialog when the user hits the Cancel button in the editor [CHAR LIMIT=64] -->
<string name="cancel_confirmation_dialog_title">Discard changes</string>
@@ -1585,4 +1585,7 @@
<!-- The title of the activity that edits an existing group [CHAR LIMIT=NONE] -->
<string name="editGroup_title_edit">Edit group</string>
+
+ <!-- Title of the notification of new voicemail. -->
+ <string name="notification_voicemail_title">New voicemail</string>
</resources>
diff --git a/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java b/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
new file mode 100644
index 0000000..b2ee5ce
--- /dev/null
+++ b/src/com/android/contacts/calllog/DefaultVoicemailNotifier.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.contacts.calllog;
+
+import com.android.contacts.R;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.VoicemailContract;
+
+/**
+ * Implementation of {@link VoicemailNotifier} that shows a notification in the status bar.
+ */
+public class DefaultVoicemailNotifier implements VoicemailNotifier {
+ /** The tag used to identify notifications from this class. */
+ private static final String NOTIFICATION_TAG = "DefaultVoicemailNotifier";
+ /** The identifier of the notification of new voicemails. */
+ private static final int NOTIFICATION_ID = 1;
+
+ private final Context mContext;
+ private final NotificationManager mNotificationManager;
+ private final VoicemailNumberQuery mVoicemailNumberQuery;
+ private final NameLookupQuery mNameLookupQuery;
+
+ public DefaultVoicemailNotifier(Context context, NotificationManager notificationManager,
+ VoicemailNumberQuery voicemailNumberQuery, NameLookupQuery nameLookupQuery) {
+ mContext = context;
+ mNotificationManager = notificationManager;
+ mVoicemailNumberQuery = voicemailNumberQuery;
+ mNameLookupQuery = nameLookupQuery;
+ }
+
+ @Override
+ public void notifyNewVoicemail(Uri uri) {
+ // Lookup the number that left the voicemail.
+ String number = mVoicemailNumberQuery.query(uri);
+ // Lookup the name of the contact associated with this number.
+ String name = mNameLookupQuery.query(number);
+ // Show the name of the contact if available, falling back to using the number if not.
+ String displayName = name == null ? number : name;
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(android.R.drawable.stat_notify_voicemail)
+ .setContentTitle(mContext.getString(R.string.notification_voicemail_title))
+ .setContentText(displayName)
+ .setDefaults(Notification.DEFAULT_ALL)
+ .setAutoCancel(true)
+ .getNotification();
+
+ // Open the voicemail when clicking on the notification.
+ notification.contentIntent =
+ PendingIntent.getActivity(mContext, 0, new Intent(Intent.ACTION_VIEW, uri), 0);
+
+ mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, notification);
+ }
+
+ @Override
+ public void clearNewVoicemailNotification() {
+ mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
+ }
+
+ /** Allows determining the number associated with a given voicemail. */
+ public interface VoicemailNumberQuery {
+ /**
+ * Returns the number associated with a voicemail URI, or null if the URI does not actually
+ * correspond to a voicemail.
+ *
+ * @throws IllegalArgumentException if the given {@code uri} is not a voicemail URI.
+ */
+ public String query(Uri uri);
+ }
+
+ /** Create a new instance of {@link VoicemailNumberQuery}. */
+ public static VoicemailNumberQuery createVoicemailNumberQuery(ContentResolver contentResolver) {
+ return new DefaultVoicemailNumberQuery(contentResolver);
+ }
+
+ /**
+ * Default implementation of {@link VoicemailNumberQuery} that looks up the number in the
+ * voicemail content provider.
+ */
+ private static final class DefaultVoicemailNumberQuery implements VoicemailNumberQuery {
+ private static final String[] PROJECTION = { VoicemailContract.Voicemails.NUMBER };
+ private static final int NUMBER_COLUMN_INDEX = 0;
+
+ private final ContentResolver mContentResolver;
+
+ private DefaultVoicemailNumberQuery(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ @Override
+ public String query(Uri uri) {
+ validateVoicemailUri(uri);
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(uri, PROJECTION, null, null, null);
+ if (cursor.getCount() != 1) return null;
+ if (!cursor.moveToFirst()) return null;
+ return cursor.getString(NUMBER_COLUMN_INDEX);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ /**
+ * Makes sure that the given URI is a valid voicemail URI.
+ *
+ * @throws IllegalArgumentException if the URI is not valid
+ */
+ private void validateVoicemailUri(Uri uri) {
+ // Cannot be null.
+ if (uri == null) throw new IllegalArgumentException("invalid voicemail URI");
+ // Must have the right schema.
+ if (!VoicemailContract.Voicemails.CONTENT_URI.getScheme().equals(uri.getScheme())) {
+ throw new IllegalArgumentException("invalid voicemail URI");
+ }
+ // Must have the right authority.
+ if (!VoicemailContract.AUTHORITY.equals(uri.getAuthority())) {
+ throw new IllegalArgumentException("invalid voicemail URI");
+ }
+ // Must have a valid path.
+ if (uri.getPath() == null) {
+ throw new IllegalArgumentException("invalid voicemail URI");
+ }
+ // Must be a path within the voicemails table.
+ if (!uri.getPath().startsWith(VoicemailContract.Voicemails.CONTENT_URI.getPath())) {
+ throw new IllegalArgumentException("invalid voicemail URI");
+ }
+ }
+ }
+
+ /** Allows determining the name associated with a given phone number. */
+ public interface NameLookupQuery {
+ /**
+ * Returns the name associated with the given number in the contacts database, or null if
+ * the number does not correspond to any of the contacts.
+ * <p>
+ * If there are multiple contacts with the same phone number, it will return the name of one
+ * of the matching contacts.
+ */
+ public String query(String number);
+ }
+
+ /** Create a new instance of {@link NameLookupQuery}. */
+ public static NameLookupQuery createNameLookupQuery(ContentResolver contentResolver) {
+ return new DefaultNameLookupQuery(contentResolver);
+ }
+
+ private static final class DefaultNameLookupQuery implements NameLookupQuery {
+ private static final String[] PROJECTION = { PhoneLookup.DISPLAY_NAME };
+ private static final int DISPLAY_NAME_COLUMN_INDEX = 0;
+
+ private final ContentResolver mContentResolver;
+
+ private DefaultNameLookupQuery(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ @Override
+ public String query(String number) {
+ Cursor cursor = null;
+ try {
+ cursor = mContentResolver.query(
+ Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
+ PROJECTION, null, null, null);
+ if (!cursor.moveToFirst()) return null;
+ return cursor.getString(DISPLAY_NAME_COLUMN_INDEX);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/contacts/calllog/NewVoicemailReceiver.java b/src/com/android/contacts/calllog/NewVoicemailReceiver.java
new file mode 100644
index 0000000..0b9f2fa
--- /dev/null
+++ b/src/com/android/contacts/calllog/NewVoicemailReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.contacts.calllog;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receiver for new voicemail notifications.
+ * <p>
+ * Delegates to a {@link VoicemailNotifier}.
+ */
+public class NewVoicemailReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ getVoicemailNotifier(context).notifyNewVoicemail(intent.getData());
+ }
+
+ private VoicemailNotifier getVoicemailNotifier(Context context) {
+ NotificationManager notificationManager =
+ (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ return new DefaultVoicemailNotifier(context, notificationManager,
+ DefaultVoicemailNotifier.createVoicemailNumberQuery(context.getContentResolver()),
+ DefaultVoicemailNotifier.createNameLookupQuery(context.getContentResolver()));
+ }
+}
diff --git a/src/com/android/contacts/calllog/VoicemailNotifier.java b/src/com/android/contacts/calllog/VoicemailNotifier.java
new file mode 100644
index 0000000..ba82f21
--- /dev/null
+++ b/src/com/android/contacts/calllog/VoicemailNotifier.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.contacts.calllog;
+
+import android.net.Uri;
+
+/**
+ * Handles notifications for voicemails.
+ */
+public interface VoicemailNotifier {
+ /**
+ * Notifies the user of a new voicemail.
+ *
+ * @param newVoicemailUri URI of the new voicemail record just inserted
+ * @throws IllegalArgumentException if the URI does not correspond to a voicemail
+ */
+ public void notifyNewVoicemail(Uri newVoicemailUri);
+
+ /** Clears the new voicemail notification. */
+ public void clearNewVoicemailNotification();
+}