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