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