1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.dialer.app.calllog; 18 19 import android.content.Context; 20 import android.support.annotation.NonNull; 21 import android.support.annotation.Nullable; 22 import android.support.annotation.WorkerThread; 23 import android.text.TextUtils; 24 import android.util.ArrayMap; 25 import com.android.dialer.app.R; 26 import com.android.dialer.app.calllog.CallLogNotificationsQueryHelper.NewCall; 27 import com.android.dialer.blocking.FilteredNumberAsyncQueryHandler; 28 import com.android.dialer.blocking.FilteredNumbersUtil; 29 import com.android.dialer.common.Assert; 30 import com.android.dialer.common.LogUtil; 31 import com.android.dialer.common.concurrent.DialerExecutor.Worker; 32 import com.android.dialer.common.concurrent.DialerExecutors; 33 import com.android.dialer.phonenumbercache.ContactInfo; 34 import com.android.dialer.telecom.TelecomUtil; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Map; 38 39 /** Updates voicemail notifications in the background. */ 40 class VisualVoicemailUpdateTask implements Worker<VisualVoicemailUpdateTask.Input, Void> { 41 @Nullable 42 @Override doInBackground(@onNull Input input)43 public Void doInBackground(@NonNull Input input) throws Throwable { 44 updateNotification(input.context, input.queryHelper, input.queryHandler); 45 return null; 46 } 47 48 /** 49 * Updates the notification and notifies of the call with the given URI. 50 * 51 * <p>Clears the notification if there are no new voicemails, and notifies if the given URI 52 * corresponds to a new voicemail. 53 */ 54 @WorkerThread updateNotification( Context context, CallLogNotificationsQueryHelper queryHelper, FilteredNumberAsyncQueryHandler queryHandler)55 private static void updateNotification( 56 Context context, 57 CallLogNotificationsQueryHelper queryHelper, 58 FilteredNumberAsyncQueryHandler queryHandler) { 59 Assert.isWorkerThread(); 60 61 List<NewCall> newCalls = queryHelper.getNewVoicemails(); 62 if (newCalls == null) { 63 return; 64 } 65 newCalls = filterBlockedNumbers(context, queryHandler, newCalls); 66 if (newCalls.isEmpty()) { 67 return; 68 } 69 70 // This represents a list of names to include in the notification. 71 String callers = null; 72 73 // Maps each number into a name: if a number is in the map, it has already left a more 74 // recent voicemail. 75 Map<String, ContactInfo> contactInfos = new ArrayMap<>(); 76 for (NewCall newCall : newCalls) { 77 if (!contactInfos.containsKey(newCall.number)) { 78 ContactInfo contactInfo = 79 queryHelper.getContactInfo( 80 newCall.number, newCall.numberPresentation, newCall.countryIso); 81 contactInfos.put(newCall.number, contactInfo); 82 83 // This is a new caller. Add it to the back of the list of callers. 84 if (TextUtils.isEmpty(callers)) { 85 callers = contactInfo.name; 86 } else { 87 callers = 88 context.getString( 89 R.string.notification_voicemail_callers_list, callers, contactInfo.name); 90 } 91 } 92 } 93 VisualVoicemailNotifier.showNotifications(context, newCalls, contactInfos, callers); 94 } 95 96 @WorkerThread filterBlockedNumbers( Context context, FilteredNumberAsyncQueryHandler queryHandler, List<NewCall> newCalls)97 private static List<NewCall> filterBlockedNumbers( 98 Context context, FilteredNumberAsyncQueryHandler queryHandler, List<NewCall> newCalls) { 99 Assert.isWorkerThread(); 100 if (FilteredNumbersUtil.hasRecentEmergencyCall(context)) { 101 LogUtil.i( 102 "VisualVoicemailUpdateTask.filterBlockedNumbers", 103 "not filtering due to recent emergency call"); 104 return newCalls; 105 } 106 107 List<NewCall> result = new ArrayList<>(); 108 for (NewCall newCall : newCalls) { 109 if (queryHandler.getBlockedIdSynchronous(newCall.number, newCall.countryIso) != null) { 110 LogUtil.i( 111 "VisualVoicemailUpdateTask.filterBlockedNumbers", 112 "found voicemail from blocked number, deleting"); 113 if (newCall.voicemailUri != null) { 114 // Delete the voicemail. 115 CallLogAsyncTaskUtil.deleteVoicemailSynchronous(context, newCall.voicemailUri); 116 } 117 } else { 118 result.add(newCall); 119 } 120 } 121 return result; 122 } 123 124 /** Updates the voicemail notifications displayed. */ scheduleTask(@onNull Context context, @NonNull Runnable callback)125 static void scheduleTask(@NonNull Context context, @NonNull Runnable callback) { 126 Assert.isNotNull(context); 127 Assert.isNotNull(callback); 128 if (!TelecomUtil.isDefaultDialer(context)) { 129 LogUtil.i("VisualVoicemailUpdateTask.scheduleTask", "not default dialer, not running"); 130 callback.run(); 131 return; 132 } 133 134 Input input = 135 new Input( 136 context, 137 CallLogNotificationsQueryHelper.getInstance(context), 138 new FilteredNumberAsyncQueryHandler(context)); 139 DialerExecutors.createNonUiTaskBuilder(new VisualVoicemailUpdateTask()) 140 .onSuccess( 141 output -> { 142 LogUtil.i("VisualVoicemailUpdateTask.scheduleTask", "update successful"); 143 callback.run(); 144 }) 145 .onFailure( 146 throwable -> { 147 LogUtil.i("VisualVoicemailUpdateTask.scheduleTask", "update failed: " + throwable); 148 callback.run(); 149 }) 150 .build() 151 .executeParallel(input); 152 } 153 154 static class Input { 155 @NonNull final Context context; 156 @NonNull final CallLogNotificationsQueryHelper queryHelper; 157 @NonNull final FilteredNumberAsyncQueryHandler queryHandler; 158 Input( Context context, CallLogNotificationsQueryHelper queryHelper, FilteredNumberAsyncQueryHandler queryHandler)159 Input( 160 Context context, 161 CallLogNotificationsQueryHelper queryHelper, 162 FilteredNumberAsyncQueryHandler queryHandler) { 163 this.context = context; 164 this.queryHelper = queryHelper; 165 this.queryHandler = queryHandler; 166 } 167 } 168 } 169