1 /* 2 * Copyright (C) 2017 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.annotation.TargetApi; 20 import android.app.Notification; 21 import android.app.PendingIntent; 22 import android.content.Context; 23 import android.os.Build.VERSION_CODES; 24 import android.os.PersistableBundle; 25 import android.support.annotation.NonNull; 26 import android.support.v4.os.BuildCompat; 27 import android.telecom.PhoneAccount; 28 import android.telecom.PhoneAccountHandle; 29 import android.telecom.TelecomManager; 30 import android.telephony.CarrierConfigManager; 31 import android.telephony.TelephonyManager; 32 import android.text.TextUtils; 33 import com.android.dialer.app.R; 34 import com.android.dialer.common.Assert; 35 import com.android.dialer.common.LogUtil; 36 import com.android.dialer.location.GeoUtil; 37 import com.android.dialer.notification.DialerNotificationManager; 38 import com.android.dialer.notification.NotificationChannelManager; 39 import com.android.dialer.phonenumberutil.PhoneNumberHelper; 40 import com.android.dialer.telecom.TelecomUtil; 41 import com.android.dialer.theme.base.ThemeComponent; 42 43 /** Shows a notification in the status bar for legacy vociemail. */ 44 @TargetApi(VERSION_CODES.O) 45 public final class LegacyVoicemailNotifier { 46 private static final String NOTIFICATION_TAG_PREFIX = "LegacyVoicemail_"; 47 private static final String NOTIFICATION_TAG = "LegacyVoicemail"; 48 private static final int NOTIFICATION_ID = 1; 49 50 /** 51 * Replicates how packages/services/Telephony/NotificationMgr.java handles legacy voicemail 52 * notification. The notification will not be stackable because no information is available for 53 * individual voicemails. 54 */ showNotification( @onNull Context context, @NonNull PhoneAccountHandle handle, int count, String voicemailNumber, PendingIntent callVoicemailIntent, PendingIntent voicemailSettingsIntent, boolean isRefresh)55 public static void showNotification( 56 @NonNull Context context, 57 @NonNull PhoneAccountHandle handle, 58 int count, 59 String voicemailNumber, 60 PendingIntent callVoicemailIntent, 61 PendingIntent voicemailSettingsIntent, 62 boolean isRefresh) { 63 LogUtil.enterBlock("LegacyVoicemailNotifier.showNotification"); 64 Assert.isNotNull(handle); 65 Assert.checkArgument(BuildCompat.isAtLeastO()); 66 67 TelephonyManager pinnedTelephonyManager = 68 context.getSystemService(TelephonyManager.class).createForPhoneAccountHandle(handle); 69 if (pinnedTelephonyManager == null) { 70 LogUtil.e("LegacyVoicemailNotifier.showNotification", "invalid PhoneAccountHandle"); 71 return; 72 } 73 74 Notification notification = 75 createNotification( 76 context, 77 pinnedTelephonyManager, 78 handle, 79 count, 80 voicemailNumber, 81 callVoicemailIntent, 82 voicemailSettingsIntent, 83 isRefresh); 84 DialerNotificationManager.notify( 85 context, getNotificationTag(context, handle), NOTIFICATION_ID, notification); 86 } 87 88 @NonNull createNotification( @onNull Context context, @NonNull TelephonyManager pinnedTelephonyManager, @NonNull PhoneAccountHandle handle, int count, String voicemailNumber, PendingIntent callVoicemailIntent, PendingIntent voicemailSettingsIntent, boolean isRefresh)89 private static Notification createNotification( 90 @NonNull Context context, 91 @NonNull TelephonyManager pinnedTelephonyManager, 92 @NonNull PhoneAccountHandle handle, 93 int count, 94 String voicemailNumber, 95 PendingIntent callVoicemailIntent, 96 PendingIntent voicemailSettingsIntent, 97 boolean isRefresh) { 98 String notificationTitle = 99 context 100 .getResources() 101 .getQuantityString(R.plurals.notification_voicemail_title, count, count); 102 PersistableBundle config = pinnedTelephonyManager.getCarrierConfig(); 103 boolean isOngoing; 104 if (config == null) { 105 isOngoing = false; 106 } else { 107 isOngoing = 108 config.getBoolean(CarrierConfigManager.KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL); 109 } 110 String contentText; 111 PendingIntent contentIntent; 112 if (!TextUtils.isEmpty(voicemailNumber) && callVoicemailIntent != null) { 113 contentText = getNotificationText(context, handle, voicemailNumber); 114 contentIntent = callVoicemailIntent; 115 } else { 116 contentText = context.getString(R.string.notification_voicemail_no_vm_number); 117 contentIntent = voicemailSettingsIntent; 118 } 119 120 Notification.Builder builder = 121 new Notification.Builder(context) 122 .setSmallIcon(android.R.drawable.stat_notify_voicemail) 123 .setColor(ThemeComponent.get(context).theme().getColorPrimary()) 124 .setWhen(System.currentTimeMillis()) 125 .setContentTitle(notificationTitle) 126 .setContentText(contentText) 127 .setContentIntent(contentIntent) 128 .setSound(pinnedTelephonyManager.getVoicemailRingtoneUri(handle)) 129 .setOngoing(isOngoing) 130 .setOnlyAlertOnce(isRefresh) 131 .setChannelId(NotificationChannelManager.getVoicemailChannelId(context, handle)) 132 .setDeleteIntent( 133 CallLogNotificationsService.createLegacyVoicemailDismissedPendingIntent( 134 context, handle)); 135 136 if (pinnedTelephonyManager.isVoicemailVibrationEnabled(handle)) { 137 builder.setDefaults(Notification.DEFAULT_VIBRATE); 138 } 139 140 return builder.build(); 141 } 142 143 @NonNull getNotificationText( @onNull Context context, PhoneAccountHandle handle, String voicemailNumber)144 private static String getNotificationText( 145 @NonNull Context context, PhoneAccountHandle handle, String voicemailNumber) { 146 if (TelecomUtil.getCallCapablePhoneAccounts(context).size() > 1) { 147 TelecomManager telecomManager = context.getSystemService(TelecomManager.class); 148 PhoneAccount phoneAccount = telecomManager.getPhoneAccount(handle); 149 if (phoneAccount != null) { 150 return phoneAccount.getShortDescription().toString(); 151 } 152 } 153 return String.format( 154 context.getString(R.string.notification_voicemail_text_format), 155 PhoneNumberHelper.formatNumber( 156 context, voicemailNumber, GeoUtil.getCurrentCountryIso(context))); 157 } 158 cancelNotification( @onNull Context context, @NonNull PhoneAccountHandle phoneAccountHandle)159 public static void cancelNotification( 160 @NonNull Context context, @NonNull PhoneAccountHandle phoneAccountHandle) { 161 LogUtil.enterBlock("LegacyVoicemailNotifier.cancelNotification"); 162 Assert.checkArgument(BuildCompat.isAtLeastO()); 163 Assert.isNotNull(phoneAccountHandle); 164 if ("null".equals(phoneAccountHandle.getId())) { 165 // while PhoneAccountHandle itself will never be null, telephony may still construct a "null" 166 // handle if the SIM is no longer available. Usually both SIM will be removed at the sames 167 // time, so just clear all notifications. 168 LogUtil.i( 169 "LegacyVoicemailNotifier.cancelNotification", 170 "'null' id, canceling all legacy voicemail notifications"); 171 DialerNotificationManager.cancelAll(context, NOTIFICATION_TAG); 172 } else { 173 DialerNotificationManager.cancel( 174 context, getNotificationTag(context, phoneAccountHandle), NOTIFICATION_ID); 175 } 176 } 177 178 @NonNull getNotificationTag( @onNull Context context, @NonNull PhoneAccountHandle phoneAccountHandle)179 private static String getNotificationTag( 180 @NonNull Context context, @NonNull PhoneAccountHandle phoneAccountHandle) { 181 if (context.getSystemService(TelephonyManager.class).getPhoneCount() <= 1) { 182 return NOTIFICATION_TAG; 183 } 184 return NOTIFICATION_TAG_PREFIX + phoneAccountHandle.getId(); 185 } 186 LegacyVoicemailNotifier()187 private LegacyVoicemailNotifier() {} 188 } 189