summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/com/android/dialer/app/AndroidManifest.xml5
-rw-r--r--java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java28
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java4
-rw-r--r--java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java58
-rw-r--r--java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java89
-rw-r--r--java/com/android/dialer/app/calllog/VoicemailQueryHandler.java10
-rw-r--r--java/com/android/dialer/constants/ScheduledJobIds.java1
7 files changed, 184 insertions, 11 deletions
diff --git a/java/com/android/dialer/app/AndroidManifest.xml b/java/com/android/dialer/app/AndroidManifest.xml
index 4200082a6..2ef5dad14 100644
--- a/java/com/android/dialer/app/AndroidManifest.xml
+++ b/java/com/android/dialer/app/AndroidManifest.xml
@@ -103,6 +103,11 @@
android:name="com.android.dialer.app.calllog.CallLogNotificationsService"
/>
+ <service
+ android:name="com.android.dialer.app.calllog.VoicemailNotificationJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ />
+
<receiver
android:directBootAware="true"
android:name="com.android.dialer.app.calllog.MissedCallNotificationReceiver">
diff --git a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
index 649a6639d..2f8b1f476 100644
--- a/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
+++ b/java/com/android/dialer/app/calllog/CallLogNotificationsQueryHelper.java
@@ -136,6 +136,10 @@ public class CallLogNotificationsQueryHelper {
return new DefaultNewCallsQuery(context.getApplicationContext(), contentResolver);
}
+ NewCallsQuery getNewCallsQuery() {
+ return mNewCallsQuery;
+ }
+
/**
* Get all voicemails with the "new" flag set to 1.
*
@@ -219,6 +223,10 @@ public class CallLogNotificationsQueryHelper {
/** Returns the new calls of a certain type for which a notification should be generated. */
@Nullable
List<NewCall> query(int type);
+
+ /** Returns a {@link NewCall} pointed by the {@code callsUri} */
+ @Nullable
+ NewCall query(Uri callsUri);
}
/** Information about a new voicemail. */
@@ -346,6 +354,26 @@ public class CallLogNotificationsQueryHelper {
}
}
+ @Nullable
+ @Override
+ public NewCall query(Uri callsUri) {
+ if (!PermissionsUtil.hasPermission(mContext, Manifest.permission.READ_CALL_LOG)) {
+ LogUtil.w(
+ "CallLogNotificationsQueryHelper.DefaultNewCallsQuery.query",
+ "No READ_CALL_LOG permission, returning null for calls lookup.");
+ return null;
+ }
+ try (Cursor cursor = mContentResolver.query(callsUri, PROJECTION, null, null, null)) {
+ if (cursor == null) {
+ return null;
+ }
+ if (!cursor.moveToFirst()) {
+ return null;
+ }
+ return createNewCallsFromCursor(cursor);
+ }
+ }
+
/** Returns an instance of {@link NewCall} created by using the values of the cursor. */
private NewCall createNewCallsFromCursor(Cursor cursor) {
String voicemailUriString = cursor.getString(VOICEMAIL_URI_COLUMN_INDEX);
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
index 27963491d..ceae3d38e 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailNotifier.java
@@ -54,9 +54,9 @@ final class VisualVoicemailNotifier {
/** Prefix used to generate a unique tag for each voicemail notification. */
private static final String NOTIFICATION_TAG_PREFIX = "VisualVoicemail_";
/** Common ID for all voicemail notifications. */
- private static final int NOTIFICATION_ID = 1;
+ static final int NOTIFICATION_ID = 1;
/** Tag for the group summary notification. */
- private static final String GROUP_SUMMARY_NOTIFICATION_TAG = "GroupSummary_VisualVoicemail";
+ static final String GROUP_SUMMARY_NOTIFICATION_TAG = "GroupSummary_VisualVoicemail";
/**
* Key used to associate all voicemail notifications and the summary as belonging to a single
* group.
diff --git a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
index d6601be36..219ad676d 100644
--- a/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
+++ b/java/com/android/dialer/app/calllog/VisualVoicemailUpdateTask.java
@@ -17,6 +17,8 @@
package com.android.dialer.app.calllog;
import android.content.Context;
+import android.net.Uri;
+import android.service.notification.StatusBarNotification;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
@@ -30,6 +32,7 @@ import com.android.dialer.common.Assert;
import com.android.dialer.common.LogUtil;
import com.android.dialer.common.concurrent.DialerExecutor.Worker;
import com.android.dialer.common.concurrent.DialerExecutors;
+import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.phonenumbercache.ContactInfo;
import com.android.dialer.telecom.TelecomUtil;
import java.util.ArrayList;
@@ -57,13 +60,20 @@ class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Inpu
CallLogNotificationsQueryHelper queryHelper,
FilteredNumberAsyncQueryHandler queryHandler) {
Assert.isWorkerThread();
+ LogUtil.enterBlock("VisualVoicemailUpdateTask.updateNotification");
- List<NewCall> newCalls = queryHelper.getNewVoicemails();
- if (newCalls == null) {
+ List<NewCall> voicemailsToNotify = queryHelper.getNewVoicemails();
+ if (voicemailsToNotify == null) {
+ // Query failed, just return
return;
}
- newCalls = filterBlockedNumbers(context, queryHandler, newCalls);
- if (newCalls.isEmpty()) {
+
+ voicemailsToNotify.addAll(getAndUpdateVoicemailsWithExistingNotification(context, queryHelper));
+ voicemailsToNotify = filterBlockedNumbers(context, queryHandler, voicemailsToNotify);
+ if (voicemailsToNotify.isEmpty()) {
+ LogUtil.i("VisualVoicemailUpdateTask.updateNotification", "no voicemails to notify about");
+ VisualVoicemailNotifier.cancelAllVoicemailNotifications(context);
+ VoicemailNotificationJobService.cancelJob(context);
return;
}
@@ -73,7 +83,7 @@ class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Inpu
// Maps each number into a name: if a number is in the map, it has already left a more
// recent voicemail.
Map<String, ContactInfo> contactInfos = new ArrayMap<>();
- for (NewCall newCall : newCalls) {
+ for (NewCall newCall : voicemailsToNotify) {
if (!contactInfos.containsKey(newCall.number)) {
ContactInfo contactInfo =
queryHelper.getContactInfo(
@@ -90,7 +100,43 @@ class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Inpu
}
}
}
- VisualVoicemailNotifier.showNotifications(context, newCalls, contactInfos, callers);
+ VisualVoicemailNotifier.showNotifications(context, voicemailsToNotify, contactInfos, callers);
+
+ // Set trigger to update notifications when database changes.
+ VoicemailNotificationJobService.scheduleJob(context);
+ }
+
+ /**
+ * Cancel notification for voicemail that is already deleted. Returns a list of voicemails that
+ * already has notifications posted and should be updated.
+ */
+ @WorkerThread
+ @NonNull
+ private static List<NewCall> getAndUpdateVoicemailsWithExistingNotification(
+ Context context, CallLogNotificationsQueryHelper queryHelper) {
+ Assert.isWorkerThread();
+ List<NewCall> result = new ArrayList<>();
+ for (StatusBarNotification notification :
+ DialerNotificationManager.getActiveNotifications(context)) {
+ if (notification.getId() != VisualVoicemailNotifier.NOTIFICATION_ID) {
+ continue;
+ }
+ if (TextUtils.equals(
+ notification.getTag(), VisualVoicemailNotifier.GROUP_SUMMARY_NOTIFICATION_TAG)) {
+ // Group header
+ continue;
+ }
+ NewCall existingCall = queryHelper.getNewCallsQuery().query(Uri.parse(notification.getTag()));
+ if (existingCall != null) {
+ result.add(existingCall);
+ } else {
+ LogUtil.i(
+ "VisualVoicemailUpdateTask.getVoicemailsWithExistingNotification",
+ "voicemail deleted, removing notification");
+ DialerNotificationManager.cancel(context, notification.getTag(), notification.getId());
+ }
+ }
+ return result;
}
@WorkerThread
diff --git a/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java b/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
new file mode 100644
index 000000000..ba61601ae
--- /dev/null
+++ b/java/com/android/dialer/app/calllog/VoicemailNotificationJobService.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.dialer.app.calllog;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Build;
+import android.provider.VoicemailContract;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.constants.ScheduledJobIds;
+
+/** Monitors voicemail provider changes to update active notifications. */
+public class VoicemailNotificationJobService extends JobService {
+
+ private static JobInfo jobInfo;
+
+ /**
+ * Start monitoring the provider. The provider should be monitored whenever a visual voicemail
+ * notification is visible.
+ */
+ public static void scheduleJob(Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "not supported");
+ } else {
+ context.getSystemService(JobScheduler.class).schedule(getJobInfo(context));
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "job scheduled");
+ }
+ }
+
+ /**
+ * Stop monitoring the provider. The provider should not be monitored when visual voicemail
+ * notification is cleared.
+ */
+ public static void cancelJob(Context context) {
+ context.getSystemService(JobScheduler.class).cancel(ScheduledJobIds.VVM_NOTIFICATION_JOB);
+ LogUtil.i("VoicemailNotificationJobService.scheduleJob", "job canceled");
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ LogUtil.i("VoicemailNotificationJobService.onStartJob", "updating notification");
+ VisualVoicemailUpdateTask.scheduleTask(
+ this,
+ () -> {
+ jobFinished(params, false);
+ });
+ return true; // Running in background
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+
+ private static JobInfo getJobInfo(Context context) {
+ if (jobInfo == null) {
+ jobInfo =
+ new JobInfo.Builder(
+ ScheduledJobIds.VVM_NOTIFICATION_JOB,
+ new ComponentName(context, VoicemailNotificationJobService.class))
+ .addTriggerContentUri(
+ new JobInfo.TriggerContentUri(
+ VoicemailContract.Voicemails.CONTENT_URI,
+ JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS))
+ .setTriggerContentMaxDelay(0)
+ .build();
+ }
+
+ return jobInfo;
+ }
+}
diff --git a/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java b/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
index 2fbebdd30..169d0fd35 100644
--- a/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
+++ b/java/com/android/dialer/app/calllog/VoicemailQueryHandler.java
@@ -45,7 +45,8 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
public static void markAllNewVoicemailsAsRead(final @NonNull Context context) {
ThreadUtil.postOnUiThread(
() -> {
- new VoicemailQueryHandler(context.getContentResolver()).markNewVoicemailsAsOld(null);
+ new VoicemailQueryHandler(context.getContentResolver())
+ .markNewVoicemailsAsOld(context, null);
});
}
@@ -59,12 +60,12 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
ThreadUtil.postOnUiThread(
() -> {
new VoicemailQueryHandler(context.getContentResolver())
- .markNewVoicemailsAsOld(voicemailUri);
+ .markNewVoicemailsAsOld(context, voicemailUri);
});
}
/** Updates all new voicemails to mark them as old. */
- private void markNewVoicemailsAsOld(@Nullable Uri voicemailUri) {
+ private void markNewVoicemailsAsOld(Context context, @Nullable Uri voicemailUri) {
// Mark all "new" voicemails as not new anymore.
StringBuilder where = new StringBuilder();
where.append(Calls.NEW);
@@ -88,5 +89,8 @@ public class VoicemailQueryHandler extends AsyncQueryHandler {
voicemailUri == null
? new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}
: new String[] {Integer.toString(Calls.VOICEMAIL_TYPE), voicemailUri.toString()});
+
+ // No more notifications, stop monitoring the voicemail provider
+ VoicemailNotificationJobService.cancelJob(context);
}
}
diff --git a/java/com/android/dialer/constants/ScheduledJobIds.java b/java/com/android/dialer/constants/ScheduledJobIds.java
index cf93a464a..3fcbb0c2e 100644
--- a/java/com/android/dialer/constants/ScheduledJobIds.java
+++ b/java/com/android/dialer/constants/ScheduledJobIds.java
@@ -34,6 +34,7 @@ public final class ScheduledJobIds {
public static final int VVM_DEVICE_PROVISIONED_JOB = 202;
public static final int VVM_TRANSCRIPTION_JOB = 203;
public static final int VVM_TRANSCRIPTION_BACKFILL_JOB = 204;
+ public static final int VVM_NOTIFICATION_JOB = 205;
public static final int VOIP_REGISTRATION = 300;