Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014, 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.server.telecom.ui; |
| 18 | |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 19 | import static android.Manifest.permission.READ_PHONE_STATE; |
| 20 | |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 21 | import android.content.ComponentName; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 22 | import android.content.ContentProvider; |
| 23 | import android.content.pm.PackageManager.NameNotFoundException; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 24 | import android.telecom.PhoneAccountHandle; |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 25 | import android.telecom.TelecomManager; |
Hall Liu | a33c44b | 2015-10-19 18:10:26 -0700 | [diff] [blame] | 26 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 27 | import com.android.server.telecom.Call; |
Santos Cordon | 9269451 | 2015-04-23 14:47:28 -0700 | [diff] [blame] | 28 | import com.android.server.telecom.CallState; |
Ihab Awad | abcbce4 | 2015-04-07 14:04:01 -0700 | [diff] [blame] | 29 | import com.android.server.telecom.CallerInfoAsyncQueryFactory; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 30 | import com.android.server.telecom.CallsManager; |
| 31 | import com.android.server.telecom.CallsManagerListenerBase; |
| 32 | import com.android.server.telecom.Constants; |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 33 | import com.android.server.telecom.ContactsAsyncHelper; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 34 | import com.android.server.telecom.Log; |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 35 | import com.android.server.telecom.MissedCallNotifier; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 36 | import com.android.server.telecom.PhoneAccountRegistrar; |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 37 | import com.android.server.telecom.PhoneNumberUtilsAdapter; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 38 | import com.android.server.telecom.R; |
Brad Ebinger | e62e9e8 | 2016-02-01 18:26:40 -0800 | [diff] [blame] | 39 | import com.android.server.telecom.Runnable; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 40 | import com.android.server.telecom.TelecomBroadcastIntentProcessor; |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 41 | import com.android.server.telecom.TelecomSystem; |
Yorke Lee | 226ae56 | 2015-03-27 14:00:13 -0700 | [diff] [blame] | 42 | import com.android.server.telecom.components.TelecomBroadcastReceiver; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 43 | |
| 44 | import android.app.Notification; |
| 45 | import android.app.NotificationManager; |
| 46 | import android.app.PendingIntent; |
| 47 | import android.app.TaskStackBuilder; |
| 48 | import android.content.AsyncQueryHandler; |
| 49 | import android.content.ContentValues; |
| 50 | import android.content.Context; |
| 51 | import android.content.Intent; |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 52 | import android.content.pm.ResolveInfo; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 53 | import android.database.Cursor; |
| 54 | import android.graphics.Bitmap; |
| 55 | import android.graphics.drawable.BitmapDrawable; |
| 56 | import android.graphics.drawable.Drawable; |
| 57 | import android.net.Uri; |
| 58 | import android.os.AsyncTask; |
Anthony Lee | 761a63f | 2015-03-26 11:28:52 -0700 | [diff] [blame] | 59 | import android.os.Binder; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 60 | import android.os.UserHandle; |
| 61 | import android.provider.CallLog.Calls; |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 62 | import android.telecom.DefaultDialerManager; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 63 | import android.telecom.DisconnectCause; |
| 64 | import android.telecom.PhoneAccount; |
| 65 | import android.telephony.PhoneNumberUtils; |
Tyler Gunn | c8e528b | 2015-09-21 13:13:52 -0700 | [diff] [blame] | 66 | import android.telephony.TelephonyManager; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 67 | import android.text.BidiFormatter; |
| 68 | import android.text.TextDirectionHeuristics; |
| 69 | import android.text.TextUtils; |
| 70 | |
Victor Chang | 9e7f98a | 2016-01-04 16:03:27 +0000 | [diff] [blame] | 71 | import com.android.internal.telephony.CallerInfo; |
| 72 | |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 73 | import java.lang.Override; |
| 74 | import java.lang.String; |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 75 | import java.util.List; |
Tyler Gunn | c8e528b | 2015-09-21 13:13:52 -0700 | [diff] [blame] | 76 | import java.util.Locale; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 77 | import java.util.concurrent.ConcurrentHashMap; |
| 78 | import java.util.concurrent.ConcurrentMap; |
| 79 | import java.util.concurrent.atomic.AtomicInteger; |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 80 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 81 | // TODO: Needed for move to system service: import com.android.internal.R; |
| 82 | |
| 83 | /** |
| 84 | * Creates a notification for calls that the user missed (neither answered nor rejected). |
| 85 | * |
| 86 | * TODO: Make TelephonyManager.clearMissedCalls call into this class. |
| 87 | * |
| 88 | * TODO: Reduce dependencies in this implementation; remove the need to create a new Call |
| 89 | * simply to look up caller metadata, and if possible, make it unnecessary to get a |
| 90 | * direct reference to the CallsManager. Try to make this class simply handle the UI |
| 91 | * and Android-framework entanglements of missed call notification. |
| 92 | */ |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 93 | public class MissedCallNotifierImpl extends CallsManagerListenerBase implements MissedCallNotifier { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 94 | |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 95 | public interface MissedCallNotifierImplFactory { |
| 96 | MissedCallNotifier makeMissedCallNotifierImpl(Context context, |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 97 | PhoneAccountRegistrar phoneAccountRegistrar, |
| 98 | PhoneNumberUtilsAdapter phoneNumberUtilsAdapter); |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 99 | } |
| 100 | |
Hall Liu | a33c44b | 2015-10-19 18:10:26 -0700 | [diff] [blame] | 101 | public interface NotificationBuilderFactory { |
| 102 | Notification.Builder getBuilder(Context context); |
| 103 | } |
| 104 | |
| 105 | private static class DefaultNotificationBuilderFactory implements NotificationBuilderFactory { |
| 106 | public DefaultNotificationBuilderFactory() {} |
| 107 | |
| 108 | @Override |
| 109 | public Notification.Builder getBuilder(Context context) { |
| 110 | return new Notification.Builder(context); |
| 111 | } |
| 112 | } |
| 113 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 114 | private static final String[] CALL_LOG_PROJECTION = new String[] { |
| 115 | Calls._ID, |
| 116 | Calls.NUMBER, |
| 117 | Calls.NUMBER_PRESENTATION, |
| 118 | Calls.DATE, |
| 119 | Calls.DURATION, |
| 120 | Calls.TYPE, |
| 121 | }; |
| 122 | |
| 123 | private static final int CALL_LOG_COLUMN_ID = 0; |
| 124 | private static final int CALL_LOG_COLUMN_NUMBER = 1; |
| 125 | private static final int CALL_LOG_COLUMN_NUMBER_PRESENTATION = 2; |
| 126 | private static final int CALL_LOG_COLUMN_DATE = 3; |
| 127 | private static final int CALL_LOG_COLUMN_DURATION = 4; |
| 128 | private static final int CALL_LOG_COLUMN_TYPE = 5; |
| 129 | |
| 130 | private static final int MISSED_CALL_NOTIFICATION_ID = 1; |
| 131 | |
| 132 | private final Context mContext; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 133 | private final PhoneAccountRegistrar mPhoneAccountRegistrar; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 134 | private final NotificationManager mNotificationManager; |
Hall Liu | a33c44b | 2015-10-19 18:10:26 -0700 | [diff] [blame] | 135 | private final NotificationBuilderFactory mNotificationBuilderFactory; |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 136 | private final PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 137 | private UserHandle mCurrentUserHandle; |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 138 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 139 | // Used to track the number of missed calls. |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 140 | private ConcurrentMap<UserHandle, AtomicInteger> mMissedCallCounts; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 141 | |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 142 | public MissedCallNotifierImpl(Context context, PhoneAccountRegistrar phoneAccountRegistrar, |
| 143 | PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) { |
| 144 | this(context, phoneAccountRegistrar, phoneNumberUtilsAdapter, |
| 145 | new DefaultNotificationBuilderFactory()); |
Hall Liu | a33c44b | 2015-10-19 18:10:26 -0700 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | public MissedCallNotifierImpl(Context context, |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 149 | PhoneAccountRegistrar phoneAccountRegistrar, |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 150 | PhoneNumberUtilsAdapter phoneNumberUtilsAdapter, |
Hall Liu | a33c44b | 2015-10-19 18:10:26 -0700 | [diff] [blame] | 151 | NotificationBuilderFactory notificationBuilderFactory) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 152 | mContext = context; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 153 | mPhoneAccountRegistrar = phoneAccountRegistrar; |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 154 | mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter; |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 155 | mNotificationManager = |
| 156 | (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 157 | |
Hall Liu | a33c44b | 2015-10-19 18:10:26 -0700 | [diff] [blame] | 158 | mNotificationBuilderFactory = notificationBuilderFactory; |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 159 | mMissedCallCounts = new ConcurrentHashMap<>(); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 160 | } |
| 161 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 162 | /** Clears missed call notification and marks the call log's missed calls as read. */ |
Yorke Lee | 226ae56 | 2015-03-27 14:00:13 -0700 | [diff] [blame] | 163 | @Override |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 164 | public void clearMissedCalls(UserHandle userHandle) { |
| 165 | // If the default dialer is showing the missed call notification then it will modify the |
| 166 | // call log and we don't have to do anything here. |
| 167 | if (!shouldManageNotificationThroughDefaultDialer(userHandle)) { |
| 168 | markMissedCallsAsRead(userHandle); |
| 169 | } |
| 170 | cancelMissedCallNotification(userHandle); |
| 171 | } |
| 172 | |
| 173 | private void markMissedCallsAsRead(final UserHandle userHandle) { |
Brad Ebinger | f5e0666 | 2016-08-25 16:16:27 -0700 | [diff] [blame] | 174 | AsyncTask.execute(new Runnable("MCNI.mMCAR", null /*lock*/) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 175 | @Override |
Brad Ebinger | e62e9e8 | 2016-02-01 18:26:40 -0800 | [diff] [blame] | 176 | public void loggedRun() { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 177 | // Clear the list of new missed calls from the call log. |
| 178 | ContentValues values = new ContentValues(); |
| 179 | values.put(Calls.NEW, 0); |
| 180 | values.put(Calls.IS_READ, 1); |
| 181 | StringBuilder where = new StringBuilder(); |
| 182 | where.append(Calls.NEW); |
| 183 | where.append(" = 1 AND "); |
| 184 | where.append(Calls.TYPE); |
| 185 | where.append(" = ?"); |
Shriram Ganesh | 0f39c55 | 2015-06-24 15:56:51 -0700 | [diff] [blame] | 186 | try { |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 187 | Uri callsUri = ContentProvider |
| 188 | .maybeAddUserId(Calls.CONTENT_URI, userHandle.getIdentifier()); |
| 189 | mContext.getContentResolver().update(callsUri, values, |
Shriram Ganesh | 0f39c55 | 2015-06-24 15:56:51 -0700 | [diff] [blame] | 190 | where.toString(), new String[]{ Integer.toString(Calls. |
| 191 | MISSED_TYPE) }); |
| 192 | } catch (IllegalArgumentException e) { |
| 193 | Log.w(this, "ContactsProvider update command failed", e); |
| 194 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 195 | } |
Brad Ebinger | e62e9e8 | 2016-02-01 18:26:40 -0800 | [diff] [blame] | 196 | }.prepare()); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 197 | } |
| 198 | |
| 199 | /** |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 200 | * Returns the missed-call notificatino intent to send to the default dialer for the given user. * Note, the passed in userHandle is always the non-managed user for SIM calls (multi-user |
| 201 | * calls). In this case we return the default dialer for the logged in user. This is never the |
| 202 | * managed (work profile) dialer. |
| 203 | * |
| 204 | * For non-multi-user calls (3rd party phone accounts), the passed in userHandle is the user |
| 205 | * handle of the phone account. This could be a managed user. In that case we return the default |
| 206 | * dialer for the given user which could be a managed (work profile) dialer. |
| 207 | */ |
| 208 | private Intent getShowMissedCallIntentForDefaultDialer(UserHandle userHandle) { |
| 209 | String dialerPackage = DefaultDialerManager |
| 210 | .getDefaultDialerApplication(mContext, userHandle.getIdentifier()); |
| 211 | if (TextUtils.isEmpty(dialerPackage)) { |
| 212 | return null; |
| 213 | } |
| 214 | return new Intent(TelecomManager.ACTION_SHOW_MISSED_CALLS_NOTIFICATION) |
| 215 | .setPackage(dialerPackage); |
| 216 | } |
| 217 | |
| 218 | private boolean shouldManageNotificationThroughDefaultDialer(UserHandle userHandle) { |
| 219 | Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle); |
| 220 | if (intent == null) { |
| 221 | return false; |
| 222 | } |
| 223 | |
Sailesh Nepal | 4d34c5b | 2016-01-23 13:47:49 -0800 | [diff] [blame] | 224 | List<ResolveInfo> receivers = mContext.getPackageManager() |
| 225 | .queryBroadcastReceiversAsUser(intent, 0, userHandle.getIdentifier()); |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 226 | return receivers.size() > 0; |
| 227 | } |
| 228 | |
| 229 | private void sendNotificationThroughDefaultDialer(Call call, UserHandle userHandle) { |
| 230 | int count = mMissedCallCounts.get(userHandle).get(); |
| 231 | Intent intent = getShowMissedCallIntentForDefaultDialer(userHandle) |
| 232 | .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) |
Wei Liu | 6191486 | 2016-11-01 18:40:41 -0700 | [diff] [blame] | 233 | .putExtra(TelecomManager.EXTRA_CLEAR_MISSED_CALLS_INTENT, |
| 234 | createClearMissedCallsPendingIntent(userHandle)) |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 235 | .putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, count) |
| 236 | .putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER, |
| 237 | call != null ? call.getPhoneNumber() : null); |
| 238 | |
Wei Liu | 6191486 | 2016-11-01 18:40:41 -0700 | [diff] [blame] | 239 | if (count == 1 && call != null) { |
| 240 | final Uri handleUri = call.getHandle(); |
| 241 | String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart(); |
| 242 | |
| 243 | if (!TextUtils.isEmpty(handle) && !TextUtils.equals(handle, |
| 244 | mContext.getString(R.string.handle_restricted))) { |
| 245 | intent.putExtra(TelecomManager.EXTRA_CALL_BACK_INTENT, |
| 246 | createCallBackPendingIntent(handleUri, userHandle)); |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 251 | Log.w(this, "Showing missed calls through default dialer."); |
| 252 | mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE); |
| 253 | } |
| 254 | |
| 255 | /** |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 256 | * Create a system notification for the missed call. |
| 257 | * |
| 258 | * @param call The missed call. |
| 259 | */ |
Yorke Lee | 226ae56 | 2015-03-27 14:00:13 -0700 | [diff] [blame] | 260 | @Override |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 261 | public void showMissedCallNotification(Call call) { |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 262 | final PhoneAccountHandle phoneAccountHandle = call.getTargetPhoneAccount(); |
| 263 | final PhoneAccount phoneAccount = |
| 264 | mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle); |
| 265 | UserHandle userHandle; |
| 266 | if (phoneAccount != null && |
| 267 | phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) { |
| 268 | userHandle = mCurrentUserHandle; |
| 269 | } else { |
| 270 | userHandle = phoneAccountHandle.getUserHandle(); |
| 271 | } |
| 272 | showMissedCallNotification(call, userHandle); |
| 273 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 274 | |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 275 | private void showMissedCallNotification(Call call, UserHandle userHandle) { |
Tony Mak | 3cf8d22 | 2016-01-15 16:25:35 +0000 | [diff] [blame] | 276 | mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0)); |
| 277 | int missCallCounts = mMissedCallCounts.get(userHandle).incrementAndGet(); |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 278 | |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 279 | if (shouldManageNotificationThroughDefaultDialer(userHandle)) { |
| 280 | sendNotificationThroughDefaultDialer(call, userHandle); |
| 281 | return; |
| 282 | } |
| 283 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 284 | final int titleResId; |
| 285 | final String expandedText; // The text in the notification's line 1 and 2. |
| 286 | |
| 287 | // Display the first line of the notification: |
| 288 | // 1 missed call: <caller name || handle> |
| 289 | // More than 1 missed call: <number of calls> + "missed calls" |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 290 | if (missCallCounts == 1) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 291 | expandedText = getNameForCall(call); |
Victor Chang | 9e7f98a | 2016-01-04 16:03:27 +0000 | [diff] [blame] | 292 | |
| 293 | CallerInfo ci = call.getCallerInfo(); |
| 294 | if (ci != null && ci.userType == CallerInfo.USER_TYPE_WORK) { |
| 295 | titleResId = R.string.notification_missedWorkCallTitle; |
| 296 | } else { |
| 297 | titleResId = R.string.notification_missedCallTitle; |
| 298 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 299 | } else { |
| 300 | titleResId = R.string.notification_missedCallsTitle; |
| 301 | expandedText = |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 302 | mContext.getString(R.string.notification_missedCallsMsg, missCallCounts); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 303 | } |
| 304 | |
Tyler Gunn | 8fd6d31 | 2015-10-06 09:17:38 -0700 | [diff] [blame] | 305 | // Create a public viewable version of the notification, suitable for display when sensitive |
| 306 | // notification content is hidden. |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 307 | // We use user's context here to make sure notification is badged if it is a managed user. |
| 308 | Context contextForUser = getContextForUser(userHandle); |
| 309 | Notification.Builder publicBuilder = mNotificationBuilderFactory.getBuilder(contextForUser); |
Tyler Gunn | 8fd6d31 | 2015-10-06 09:17:38 -0700 | [diff] [blame] | 310 | publicBuilder.setSmallIcon(android.R.drawable.stat_notify_missed_call) |
| 311 | .setColor(mContext.getResources().getColor(R.color.theme_color)) |
| 312 | .setWhen(call.getCreationTimeMillis()) |
| 313 | // Show "Phone" for notification title. |
| 314 | .setContentTitle(mContext.getText(R.string.userCallActivityLabel)) |
| 315 | // Notification details shows that there are missed call(s), but does not reveal |
| 316 | // the missed caller information. |
| 317 | .setContentText(mContext.getText(titleResId)) |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 318 | .setContentIntent(createCallLogPendingIntent(userHandle)) |
Tyler Gunn | 8fd6d31 | 2015-10-06 09:17:38 -0700 | [diff] [blame] | 319 | .setAutoCancel(true) |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 320 | .setDeleteIntent(createClearMissedCallsPendingIntent(userHandle)); |
Tyler Gunn | 8fd6d31 | 2015-10-06 09:17:38 -0700 | [diff] [blame] | 321 | |
| 322 | // Create the notification suitable for display when sensitive information is showing. |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 323 | Notification.Builder builder = mNotificationBuilderFactory.getBuilder(contextForUser); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 324 | builder.setSmallIcon(android.R.drawable.stat_notify_missed_call) |
| 325 | .setColor(mContext.getResources().getColor(R.color.theme_color)) |
| 326 | .setWhen(call.getCreationTimeMillis()) |
| 327 | .setContentTitle(mContext.getText(titleResId)) |
| 328 | .setContentText(expandedText) |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 329 | .setContentIntent(createCallLogPendingIntent(userHandle)) |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 330 | .setAutoCancel(true) |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 331 | .setDeleteIntent(createClearMissedCallsPendingIntent(userHandle)) |
Tyler Gunn | 8fd6d31 | 2015-10-06 09:17:38 -0700 | [diff] [blame] | 332 | // Include a public version of the notification to be shown when the missed call |
| 333 | // notification is shown on the user's lock screen and they have chosen to hide |
| 334 | // sensitive notification information. |
| 335 | .setPublicVersion(publicBuilder.build()); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 336 | |
| 337 | Uri handleUri = call.getHandle(); |
| 338 | String handle = handleUri == null ? null : handleUri.getSchemeSpecificPart(); |
| 339 | |
| 340 | // Add additional actions when there is only 1 missed call, like call-back and SMS. |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 341 | if (missCallCounts == 1) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 342 | Log.d(this, "Add actions with number %s.", Log.piiHandle(handle)); |
| 343 | |
| 344 | if (!TextUtils.isEmpty(handle) |
| 345 | && !TextUtils.equals(handle, mContext.getString(R.string.handle_restricted))) { |
Andrew Lee | bbdd44c | 2015-05-27 12:34:14 -0700 | [diff] [blame] | 346 | builder.addAction(R.drawable.ic_phone_24dp, |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 347 | mContext.getString(R.string.notification_missedCall_call_back), |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 348 | createCallBackPendingIntent(handleUri, userHandle)); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 349 | |
Santos Cordon | 35ed797 | 2015-09-16 16:33:44 -0700 | [diff] [blame] | 350 | if (canRespondViaSms(call)) { |
| 351 | builder.addAction(R.drawable.ic_message_24dp, |
| 352 | mContext.getString(R.string.notification_missedCall_message), |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 353 | createSendSmsFromNotificationPendingIntent(handleUri, userHandle)); |
Santos Cordon | 35ed797 | 2015-09-16 16:33:44 -0700 | [diff] [blame] | 354 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | Bitmap photoIcon = call.getPhotoIcon(); |
| 358 | if (photoIcon != null) { |
| 359 | builder.setLargeIcon(photoIcon); |
| 360 | } else { |
| 361 | Drawable photo = call.getPhoto(); |
| 362 | if (photo != null && photo instanceof BitmapDrawable) { |
| 363 | builder.setLargeIcon(((BitmapDrawable) photo).getBitmap()); |
| 364 | } |
| 365 | } |
| 366 | } else { |
| 367 | Log.d(this, "Suppress actions. handle: %s, missedCalls: %d.", Log.piiHandle(handle), |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 368 | missCallCounts); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 369 | } |
| 370 | |
| 371 | Notification notification = builder.build(); |
| 372 | configureLedOnNotification(notification); |
| 373 | |
| 374 | Log.i(this, "Adding missed call notification for %s.", call); |
Anthony Lee | 761a63f | 2015-03-26 11:28:52 -0700 | [diff] [blame] | 375 | long token = Binder.clearCallingIdentity(); |
| 376 | try { |
| 377 | mNotificationManager.notifyAsUser( |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 378 | null /* tag */, MISSED_CALL_NOTIFICATION_ID, notification, userHandle); |
Anthony Lee | 761a63f | 2015-03-26 11:28:52 -0700 | [diff] [blame] | 379 | } finally { |
| 380 | Binder.restoreCallingIdentity(token); |
| 381 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 382 | } |
| 383 | |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 384 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 385 | /** Cancels the "missed call" notification. */ |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 386 | private void cancelMissedCallNotification(UserHandle userHandle) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 387 | // Reset the number of missed calls to 0. |
Tony Mak | 3cf8d22 | 2016-01-15 16:25:35 +0000 | [diff] [blame] | 388 | mMissedCallCounts.putIfAbsent(userHandle, new AtomicInteger(0)); |
| 389 | mMissedCallCounts.get(userHandle).set(0); |
Bryce Lee | 41045b4 | 2015-08-05 13:10:39 -0700 | [diff] [blame] | 390 | |
Sailesh Nepal | 39245e7 | 2016-01-21 19:03:00 -0800 | [diff] [blame] | 391 | if (shouldManageNotificationThroughDefaultDialer(userHandle)) { |
| 392 | sendNotificationThroughDefaultDialer(null, userHandle); |
| 393 | return; |
| 394 | } |
| 395 | |
Anthony Lee | 761a63f | 2015-03-26 11:28:52 -0700 | [diff] [blame] | 396 | long token = Binder.clearCallingIdentity(); |
| 397 | try { |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 398 | mNotificationManager.cancelAsUser(null, MISSED_CALL_NOTIFICATION_ID, userHandle); |
Anthony Lee | 761a63f | 2015-03-26 11:28:52 -0700 | [diff] [blame] | 399 | } finally { |
| 400 | Binder.restoreCallingIdentity(token); |
| 401 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | /** |
| 405 | * Returns the name to use in the missed call notification. |
| 406 | */ |
| 407 | private String getNameForCall(Call call) { |
| 408 | String handle = call.getHandle() == null ? null : call.getHandle().getSchemeSpecificPart(); |
| 409 | String name = call.getName(); |
| 410 | |
Tyler Gunn | c8e528b | 2015-09-21 13:13:52 -0700 | [diff] [blame] | 411 | if (!TextUtils.isEmpty(handle)) { |
| 412 | String formattedNumber = PhoneNumberUtils.formatNumber(handle, |
| 413 | getCurrentCountryIso(mContext)); |
| 414 | |
| 415 | // The formatted number will be null if there was a problem formatting it, but we can |
| 416 | // default to using the unformatted number instead (e.g. a SIP URI may not be able to |
| 417 | // be formatted. |
| 418 | if (!TextUtils.isEmpty(formattedNumber)) { |
| 419 | handle = formattedNumber; |
| 420 | } |
| 421 | } |
| 422 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 423 | if (!TextUtils.isEmpty(name) && TextUtils.isGraphic(name)) { |
| 424 | return name; |
| 425 | } else if (!TextUtils.isEmpty(handle)) { |
| 426 | // A handle should always be displayed LTR using {@link BidiFormatter} regardless of the |
| 427 | // content of the rest of the notification. |
| 428 | // TODO: Does this apply to SIP addresses? |
| 429 | BidiFormatter bidiFormatter = BidiFormatter.getInstance(); |
| 430 | return bidiFormatter.unicodeWrap(handle, TextDirectionHeuristics.LTR); |
| 431 | } else { |
| 432 | // Use "unknown" if the call is unidentifiable. |
| 433 | return mContext.getString(R.string.unknown); |
| 434 | } |
| 435 | } |
| 436 | |
| 437 | /** |
Tyler Gunn | c8e528b | 2015-09-21 13:13:52 -0700 | [diff] [blame] | 438 | * @return The ISO 3166-1 two letters country code of the country the user is in based on the |
| 439 | * network location. If the network location does not exist, fall back to the locale |
| 440 | * setting. |
| 441 | */ |
| 442 | private String getCurrentCountryIso(Context context) { |
| 443 | // Without framework function calls, this seems to be the most accurate location service |
| 444 | // we can rely on. |
| 445 | final TelephonyManager telephonyManager = |
| 446 | (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); |
| 447 | String countryIso = telephonyManager.getNetworkCountryIso().toUpperCase(); |
| 448 | |
| 449 | if (countryIso == null) { |
| 450 | countryIso = Locale.getDefault().getCountry(); |
| 451 | Log.w(this, "No CountryDetector; falling back to countryIso based on locale: " |
| 452 | + countryIso); |
| 453 | } |
| 454 | return countryIso; |
| 455 | } |
| 456 | |
| 457 | /** |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 458 | * Creates a new pending intent that sends the user to the call log. |
| 459 | * |
| 460 | * @return The pending intent. |
| 461 | */ |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 462 | private PendingIntent createCallLogPendingIntent(UserHandle userHandle) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 463 | Intent intent = new Intent(Intent.ACTION_VIEW, null); |
| 464 | intent.setType(Calls.CONTENT_TYPE); |
| 465 | |
| 466 | TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(mContext); |
| 467 | taskStackBuilder.addNextIntent(intent); |
| 468 | |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 469 | return taskStackBuilder.getPendingIntent(0, 0, null, userHandle); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 470 | } |
| 471 | |
| 472 | /** |
| 473 | * Creates an intent to be invoked when the missed call notification is cleared. |
| 474 | */ |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 475 | private PendingIntent createClearMissedCallsPendingIntent(UserHandle userHandle) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 476 | return createTelecomPendingIntent( |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 477 | TelecomBroadcastIntentProcessor.ACTION_CLEAR_MISSED_CALLS, null, userHandle); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 478 | } |
| 479 | |
| 480 | /** |
| 481 | * Creates an intent to be invoked when the user opts to "call back" from the missed call |
| 482 | * notification. |
| 483 | * |
| 484 | * @param handle The handle to call back. |
| 485 | */ |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 486 | private PendingIntent createCallBackPendingIntent(Uri handle, UserHandle userHandle) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 487 | return createTelecomPendingIntent( |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 488 | TelecomBroadcastIntentProcessor.ACTION_CALL_BACK_FROM_NOTIFICATION, handle, |
| 489 | userHandle); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 490 | } |
| 491 | |
| 492 | /** |
| 493 | * Creates an intent to be invoked when the user opts to "send sms" from the missed call |
| 494 | * notification. |
| 495 | */ |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 496 | private PendingIntent createSendSmsFromNotificationPendingIntent(Uri handle, |
| 497 | UserHandle userHandle) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 498 | return createTelecomPendingIntent( |
| 499 | TelecomBroadcastIntentProcessor.ACTION_SEND_SMS_FROM_NOTIFICATION, |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 500 | Uri.fromParts(Constants.SCHEME_SMSTO, handle.getSchemeSpecificPart(), null), |
| 501 | userHandle); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 502 | } |
| 503 | |
| 504 | /** |
| 505 | * Creates generic pending intent from the specified parameters to be received by |
| 506 | * {@link TelecomBroadcastIntentProcessor}. |
| 507 | * |
| 508 | * @param action The intent action. |
| 509 | * @param data The intent data. |
| 510 | */ |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 511 | private PendingIntent createTelecomPendingIntent(String action, Uri data, |
| 512 | UserHandle userHandle) { |
Yorke Lee | 226ae56 | 2015-03-27 14:00:13 -0700 | [diff] [blame] | 513 | Intent intent = new Intent(action, data, mContext, TelecomBroadcastReceiver.class); |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 514 | intent.putExtra(TelecomBroadcastIntentProcessor.EXTRA_USERHANDLE, userHandle); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 515 | return PendingIntent.getBroadcast(mContext, 0, intent, 0); |
| 516 | } |
| 517 | |
| 518 | /** |
| 519 | * Configures a notification to emit the blinky notification light. |
| 520 | */ |
| 521 | private void configureLedOnNotification(Notification notification) { |
| 522 | notification.flags |= Notification.FLAG_SHOW_LIGHTS; |
| 523 | notification.defaults |= Notification.DEFAULT_LIGHTS; |
| 524 | } |
| 525 | |
Santos Cordon | 35ed797 | 2015-09-16 16:33:44 -0700 | [diff] [blame] | 526 | private boolean canRespondViaSms(Call call) { |
| 527 | // Only allow respond-via-sms for "tel:" calls. |
| 528 | return call.getHandle() != null && |
| 529 | PhoneAccount.SCHEME_TEL.equals(call.getHandle().getScheme()); |
| 530 | } |
| 531 | |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 532 | /** |
| 533 | * Adds the missed call notification on startup if there are unread missed calls. |
| 534 | */ |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 535 | @Override |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 536 | public void reloadFromDatabase( |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 537 | final TelecomSystem.SyncRoot lock, |
| 538 | final CallsManager callsManager, |
Ihab Awad | abcbce4 | 2015-04-07 14:04:01 -0700 | [diff] [blame] | 539 | final ContactsAsyncHelper contactsAsyncHelper, |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 540 | final CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory, |
| 541 | final UserHandle userHandle) { |
| 542 | Log.d(this, "reloadFromDatabase()..."); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 543 | |
| 544 | // instantiate query handler |
| 545 | AsyncQueryHandler queryHandler = new AsyncQueryHandler(mContext.getContentResolver()) { |
| 546 | @Override |
| 547 | protected void onQueryComplete(int token, Object cookie, Cursor cursor) { |
| 548 | Log.d(MissedCallNotifierImpl.this, "onQueryComplete()..."); |
| 549 | if (cursor != null) { |
| 550 | try { |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 551 | mMissedCallCounts.remove(userHandle); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 552 | while (cursor.moveToNext()) { |
| 553 | // Get data about the missed call from the cursor |
| 554 | final String handleString = cursor.getString(CALL_LOG_COLUMN_NUMBER); |
| 555 | final int presentation = |
| 556 | cursor.getInt(CALL_LOG_COLUMN_NUMBER_PRESENTATION); |
| 557 | final long date = cursor.getLong(CALL_LOG_COLUMN_DATE); |
| 558 | |
| 559 | final Uri handle; |
| 560 | if (presentation != Calls.PRESENTATION_ALLOWED |
| 561 | || TextUtils.isEmpty(handleString)) { |
| 562 | handle = null; |
| 563 | } else { |
| 564 | handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(handleString) ? |
| 565 | PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, |
| 566 | handleString, null); |
| 567 | } |
| 568 | |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 569 | synchronized (lock) { |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 570 | |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 571 | // Convert the data to a call object |
Tyler Gunn | 8452be0 | 2015-09-17 09:57:02 -0700 | [diff] [blame] | 572 | Call call = new Call(Call.CALL_ID_UNKNOWN, mContext, callsManager, |
| 573 | lock, null, contactsAsyncHelper, |
Brad Ebinger | 6ab66c3 | 2016-07-15 19:27:51 -0700 | [diff] [blame] | 574 | callerInfoAsyncQueryFactory, mPhoneNumberUtilsAdapter, null, |
| 575 | null, null, null, Call.CALL_DIRECTION_INCOMING, false, |
| 576 | false); |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 577 | call.setDisconnectCause( |
| 578 | new DisconnectCause(DisconnectCause.MISSED)); |
Santos Cordon | 5fa4e4f | 2015-06-10 14:56:01 -0700 | [diff] [blame] | 579 | call.setState(CallState.DISCONNECTED, "throw away call"); |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 580 | call.setCreationTimeMillis(date); |
| 581 | |
| 582 | // Listen for the update to the caller information before posting |
| 583 | // the notification so that we have the contact info and photo. |
| 584 | call.addListener(new Call.ListenerBase() { |
| 585 | @Override |
| 586 | public void onCallerInfoChanged(Call call) { |
| 587 | call.removeListener( |
| 588 | this); // No longer need to listen to call |
| 589 | // changes after the contact info |
| 590 | // is retrieved. |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 591 | showMissedCallNotification(call, userHandle); |
Ihab Awad | 8d5d9dd | 2015-03-12 11:11:06 -0700 | [diff] [blame] | 592 | } |
| 593 | }); |
| 594 | // Set the handle here because that is what triggers the contact |
| 595 | // info query. |
| 596 | call.setHandle(handle, presentation); |
| 597 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 598 | } |
| 599 | } finally { |
| 600 | cursor.close(); |
| 601 | } |
| 602 | } |
| 603 | } |
| 604 | }; |
| 605 | |
| 606 | // setup query spec, look for all Missed calls that are new. |
Pooja Jain | 68385f5 | 2016-08-04 16:48:36 +0530 | [diff] [blame] | 607 | StringBuilder where = new StringBuilder("(type="); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 608 | where.append(Calls.MISSED_TYPE); |
Pooja Jain | 68385f5 | 2016-08-04 16:48:36 +0530 | [diff] [blame] | 609 | where.append(" OR type="); |
Pooja Jain | f506388 | 2016-11-14 18:36:08 +0530 | [diff] [blame] | 610 | where.append(Calls.MISSED_IMS_TYPE); |
Pooja Jain | 68385f5 | 2016-08-04 16:48:36 +0530 | [diff] [blame] | 611 | where.append(" OR type="); |
| 612 | where.append(Calls.MISSED_WIFI_TYPE+")"); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 613 | where.append(" AND new=1"); |
Roshan Pius | ec0a146 | 2015-08-04 15:01:20 -0700 | [diff] [blame] | 614 | where.append(" AND is_read=0"); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 615 | |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 616 | Uri callsUri = |
| 617 | ContentProvider.maybeAddUserId(Calls.CONTENT_URI, userHandle.getIdentifier()); |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 618 | // start the query |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 619 | queryHandler.startQuery(0, null, callsUri, CALL_LOG_PROJECTION, |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 620 | where.toString(), null, Calls.DEFAULT_SORT_ORDER); |
| 621 | } |
Tony Mak | a993094 | 2016-01-15 10:57:14 +0000 | [diff] [blame] | 622 | |
| 623 | @Override |
| 624 | public void setCurrentUserHandle(UserHandle currentUserHandle) { |
| 625 | mCurrentUserHandle = currentUserHandle; |
| 626 | } |
| 627 | |
| 628 | private Context getContextForUser(UserHandle user) { |
| 629 | try { |
| 630 | return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, user); |
| 631 | } catch (NameNotFoundException e) { |
| 632 | // Default to mContext, not finding the package system is running as is unlikely. |
| 633 | return mContext; |
| 634 | } |
| 635 | } |
Ihab Awad | 8de7691 | 2015-02-17 12:25:52 -0800 | [diff] [blame] | 636 | } |