blob: 54dfb75eda814b62e8385592cdacdf1265655d32 [file] [log] [blame]
Santos Cordon7d4ddf62013-07-10 11:58:08 -07001/*
2 * Copyright (C) 2006 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
17package com.android.phone;
18
19import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.app.StatusBarManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070023import android.content.ComponentName;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070024import android.content.Context;
25import android.content.Intent;
26import android.content.SharedPreferences;
Andrew Lee99d0ac22014-10-10 13:18:04 -070027import android.content.pm.UserInfo;
Nancy Chenb4a92702014-12-04 15:57:29 -080028import android.content.res.Resources;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070029import android.net.Uri;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070030import android.os.PersistableBundle;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070031import android.os.SystemProperties;
Andrew Lee99d0ac22014-10-10 13:18:04 -070032import android.os.UserHandle;
33import android.os.UserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070034import android.preference.PreferenceManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070035import android.provider.ContactsContract.PhoneLookup;
36import android.provider.Settings;
Tyler Gunn4d45d1c2014-09-12 22:17:53 -070037import android.telecom.PhoneAccount;
Andrew Leed5165b02014-12-05 15:53:58 -080038import android.telecom.PhoneAccountHandle;
39import android.telecom.TelecomManager;
Jonathan Basseri3649bdb2015-04-30 22:39:11 -070040import android.telephony.CarrierConfigManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.telephony.PhoneNumberUtils;
42import android.telephony.ServiceState;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080043import android.telephony.SubscriptionInfo;
Andrew Leea82b8202014-11-21 16:18:28 -080044import android.telephony.SubscriptionManager;
Andrew Leed5165b02014-12-05 15:53:58 -080045import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import android.text.TextUtils;
Tyler Gunn9c1071f2014-12-09 10:07:54 -080047import android.util.ArrayMap;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070048import android.util.Log;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049import android.widget.Toast;
50
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051import com.android.internal.telephony.Phone;
52import com.android.internal.telephony.PhoneBase;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053import com.android.internal.telephony.TelephonyCapabilities;
Andrew Leebf07f762015-04-07 19:05:50 -070054import com.android.phone.settings.VoicemailSettingsActivity;
Andrew Lee8d66d812014-11-24 14:54:02 -080055import com.android.phone.settings.VoicemailNotificationSettingsUtil;
Tyler Gunn9c1071f2014-12-09 10:07:54 -080056import com.android.phone.settings.VoicemailProviderSettingsUtil;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057
Tyler Gunn9c1071f2014-12-09 10:07:54 -080058import java.util.Iterator;
Andrew Lee99d0ac22014-10-10 13:18:04 -070059import java.util.List;
Tyler Gunn9c1071f2014-12-09 10:07:54 -080060import java.util.Map;
61import java.util.Set;
Andrew Lee99d0ac22014-10-10 13:18:04 -070062
Santos Cordon7d4ddf62013-07-10 11:58:08 -070063/**
64 * NotificationManager-related utility code for the Phone app.
65 *
66 * This is a singleton object which acts as the interface to the
67 * framework's NotificationManager, and is used to display status bar
68 * icons and control other status bar-related behavior.
69 *
70 * @see PhoneGlobals.notificationMgr
71 */
Chiao Cheng312b9c92013-09-16 15:40:53 -070072public class NotificationMgr {
Andrew Leea82b8202014-11-21 16:18:28 -080073 private static final String LOG_TAG = NotificationMgr.class.getSimpleName();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070074 private static final boolean DBG =
75 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
76 // Do not check in with VDBG = true, since that may write PII to the system log.
77 private static final boolean VDBG = false;
78
Santos Cordon7d4ddf62013-07-10 11:58:08 -070079 // notification types
Santos Cordonf68db2e2014-07-02 14:40:44 -070080 static final int MMI_NOTIFICATION = 1;
81 static final int NETWORK_SELECTION_NOTIFICATION = 2;
82 static final int VOICEMAIL_NOTIFICATION = 3;
83 static final int CALL_FORWARD_NOTIFICATION = 4;
84 static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
85 static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070086
87 /** The singleton NotificationMgr instance. */
88 private static NotificationMgr sInstance;
89
90 private PhoneGlobals mApp;
91 private Phone mPhone;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070092
93 private Context mContext;
94 private NotificationManager mNotificationManager;
95 private StatusBarManager mStatusBarManager;
Andrew Lee99d0ac22014-10-10 13:18:04 -070096 private UserManager mUserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070097 private Toast mToast;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080098 private SubscriptionManager mSubscriptionManager;
Andrew Leed5165b02014-12-05 15:53:58 -080099 private TelecomManager mTelecomManager;
100 private TelephonyManager mTelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700101
102 public StatusBarHelper statusBarHelper;
103
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700104 // used to track the notification of selected network unavailable
105 private boolean mSelectedUnavailableNotify = false;
106
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800107 // used to track whether the message waiting indicator is visible, per subscription id.
108 private ArrayMap<Integer, Boolean> mMwiVisible = new ArrayMap<Integer, Boolean>();
109
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700110 /**
111 * Private constructor (this is a singleton).
Santos Cordonf68db2e2014-07-02 14:40:44 -0700112 * @see #init(PhoneGlobals)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700113 */
114 private NotificationMgr(PhoneGlobals app) {
115 mApp = app;
116 mContext = app;
117 mNotificationManager =
118 (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
119 mStatusBarManager =
120 (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700121 mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
Stuart Scottdcf40a92014-12-09 10:45:01 -0800122 mPhone = app.mCM.getDefaultPhone();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700123 statusBarHelper = new StatusBarHelper();
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800124 mSubscriptionManager = SubscriptionManager.from(mContext);
Andrew Leed5165b02014-12-05 15:53:58 -0800125 mTelecomManager = TelecomManager.from(mContext);
126 mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700127 }
128
129 /**
130 * Initialize the singleton NotificationMgr instance.
131 *
132 * This is only done once, at startup, from PhoneApp.onCreate().
133 * From then on, the NotificationMgr instance is available via the
134 * PhoneApp's public "notificationMgr" field, which is why there's no
135 * getInstance() method here.
136 */
137 /* package */ static NotificationMgr init(PhoneGlobals app) {
138 synchronized (NotificationMgr.class) {
139 if (sInstance == null) {
140 sInstance = new NotificationMgr(app);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700141 } else {
142 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
143 }
144 return sInstance;
145 }
146 }
147
148 /**
149 * Helper class that's a wrapper around the framework's
150 * StatusBarManager.disable() API.
151 *
152 * This class is used to control features like:
153 *
154 * - Disabling the status bar "notification windowshade"
155 * while the in-call UI is up
156 *
157 * - Disabling notification alerts (audible or vibrating)
158 * while a phone call is active
159 *
160 * - Disabling navigation via the system bar (the "soft buttons" at
161 * the bottom of the screen on devices with no hard buttons)
162 *
163 * We control these features through a single point of control to make
164 * sure that the various StatusBarManager.disable() calls don't
165 * interfere with each other.
166 */
167 public class StatusBarHelper {
168 // Current desired state of status bar / system bar behavior
169 private boolean mIsNotificationEnabled = true;
170 private boolean mIsExpandedViewEnabled = true;
171 private boolean mIsSystemBarNavigationEnabled = true;
172
Andrew Leed5165b02014-12-05 15:53:58 -0800173 private StatusBarHelper() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700174 }
175
176 /**
177 * Enables or disables auditory / vibrational alerts.
178 *
179 * (We disable these any time a voice call is active, regardless
180 * of whether or not the in-call UI is visible.)
181 */
182 public void enableNotificationAlerts(boolean enable) {
183 if (mIsNotificationEnabled != enable) {
184 mIsNotificationEnabled = enable;
185 updateStatusBar();
186 }
187 }
188
189 /**
190 * Enables or disables the expanded view of the status bar
191 * (i.e. the ability to pull down the "notification windowshade").
192 *
193 * (This feature is disabled by the InCallScreen while the in-call
194 * UI is active.)
195 */
196 public void enableExpandedView(boolean enable) {
197 if (mIsExpandedViewEnabled != enable) {
198 mIsExpandedViewEnabled = enable;
199 updateStatusBar();
200 }
201 }
202
203 /**
204 * Enables or disables the navigation via the system bar (the
205 * "soft buttons" at the bottom of the screen)
206 *
207 * (This feature is disabled while an incoming call is ringing,
208 * because it's easy to accidentally touch the system bar while
209 * pulling the phone out of your pocket.)
210 */
211 public void enableSystemBarNavigation(boolean enable) {
212 if (mIsSystemBarNavigationEnabled != enable) {
213 mIsSystemBarNavigationEnabled = enable;
214 updateStatusBar();
215 }
216 }
217
218 /**
219 * Updates the status bar to reflect the current desired state.
220 */
221 private void updateStatusBar() {
222 int state = StatusBarManager.DISABLE_NONE;
223
224 if (!mIsExpandedViewEnabled) {
225 state |= StatusBarManager.DISABLE_EXPAND;
226 }
227 if (!mIsNotificationEnabled) {
228 state |= StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
229 }
230 if (!mIsSystemBarNavigationEnabled) {
231 // Disable *all* possible navigation via the system bar.
232 state |= StatusBarManager.DISABLE_HOME;
233 state |= StatusBarManager.DISABLE_RECENT;
234 state |= StatusBarManager.DISABLE_BACK;
Christine Chenb685f172013-09-25 18:32:59 -0700235 state |= StatusBarManager.DISABLE_SEARCH;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700236 }
237
238 if (DBG) log("updateStatusBar: state = 0x" + Integer.toHexString(state));
239 mStatusBarManager.disable(state);
240 }
241 }
242
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700243 /** The projection to use when querying the phones table */
244 static final String[] PHONES_PROJECTION = new String[] {
245 PhoneLookup.NUMBER,
246 PhoneLookup.DISPLAY_NAME,
247 PhoneLookup._ID
248 };
249
250 /**
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800251 * Re-creates the message waiting indicator (voicemail) notification if it is showing. Used to
252 * refresh the voicemail intent on the indicator when the user changes it via the voicemail
253 * settings screen. The voicemail notification sound is suppressed.
254 *
255 * @param subId The subscription Id.
256 */
257 /* package */ void refreshMwi(int subId) {
258 // In a single-sim device, subId can be -1 which means "no sub id". In this case we will
259 // reference the single subid stored in the mMwiVisible map.
260 if (subId == SubscriptionInfoHelper.NO_SUB_ID) {
261 if (mMwiVisible.keySet().size() == 1) {
262 Set<Integer> keySet = mMwiVisible.keySet();
263 Iterator<Integer> keyIt = keySet.iterator();
264 if (!keyIt.hasNext()) {
265 return;
266 }
267 subId = keyIt.next();
268 }
269 }
270 if (mMwiVisible.containsKey(subId)) {
271 boolean mwiVisible = mMwiVisible.get(subId);
272 if (mwiVisible) {
273 updateMwi(subId, mwiVisible, false /* enableNotificationSound */);
274 }
275 }
276 }
277
278 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700279 * Updates the message waiting indicator (voicemail) notification.
280 *
281 * @param visible true if there are messages waiting
282 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800283 /* package */ void updateMwi(int subId, boolean visible) {
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800284 updateMwi(subId, visible, true /* enableNotificationSound */);
285 }
286
287 /**
288 * Updates the message waiting indicator (voicemail) notification.
289 *
290 * @param subId the subId to update.
291 * @param visible true if there are messages waiting
292 * @param enableNotificationSound {@code true} if the notification sound should be played.
293 */
294 void updateMwi(int subId, boolean visible, boolean enableNotificationSound) {
Andrew Leea82b8202014-11-21 16:18:28 -0800295 if (!PhoneGlobals.sVoiceCapable) {
296 // Do not show the message waiting indicator on devices which are not voice capable.
297 // These events *should* be blocked at the telephony layer for such devices.
298 Log.w(LOG_TAG, "Called updateMwi() on non-voice-capable device! Ignoring...");
299 return;
300 }
301
Yorke Lee67a62a22014-12-15 18:46:17 -0800302 Log.i(LOG_TAG, "updateMwi(): subId " + subId + " update to " + visible);
Andrew Leef8ad78f2014-12-15 16:17:29 -0800303 mMwiVisible.put(subId, visible);
304
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700305 if (visible) {
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800306 Phone phone = PhoneGlobals.getPhone(subId);
307 if (phone == null) {
Andrew Leed5165b02014-12-05 15:53:58 -0800308 Log.w(LOG_TAG, "Found null phone for: " + subId);
309 return;
310 }
311
312 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
313 if (subInfo == null) {
314 Log.w(LOG_TAG, "Found null subscription info for: " + subId);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800315 return;
316 }
317
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700318 int resId = android.R.drawable.stat_notify_voicemail;
319
320 // This Notification can get a lot fancier once we have more
321 // information about the current voicemail messages.
322 // (For example, the current voicemail system can't tell
323 // us the caller-id or timestamp of a message, or tell us the
324 // message count.)
325
326 // But for now, the UI is ultra-simple: if the MWI indication
327 // is supposed to be visible, just show a single generic
328 // notification.
329
330 String notificationTitle = mContext.getString(R.string.notification_voicemail_title);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800331 String vmNumber = phone.getVoiceMailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700332 if (DBG) log("- got vm number: '" + vmNumber + "'");
333
Andrew Leea82b8202014-11-21 16:18:28 -0800334 // The voicemail number may be null because:
335 // (1) This phone has no voicemail number.
336 // (2) This phone has a voicemail number, but the SIM isn't ready yet. This may
337 // happen when the device first boots if we get a MWI notification when we
338 // register on the network before the SIM has loaded. In this case, the
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800339 // SubscriptionListener in CallNotifier will update this once the SIM is loaded.
340 if ((vmNumber == null) && !phone.getIccRecordsLoaded()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700341 if (DBG) log("- Null vm number: SIM records not loaded (yet)...");
Andrew Leea82b8202014-11-21 16:18:28 -0800342 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700343 }
344
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800345 if (TelephonyCapabilities.supportsVoiceMessageCount(phone)) {
346 int vmCount = phone.getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700347 String titleFormat = mContext.getString(R.string.notification_voicemail_title_count);
348 notificationTitle = String.format(titleFormat, vmCount);
349 }
350
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800351 // This pathway only applies to PSTN accounts; only SIMS have subscription ids.
352 PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(phone);
353
354 Intent intent;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700355 String notificationText;
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800356 if (TextUtils.isEmpty(vmNumber)) {
357 notificationText = mContext.getString(
358 R.string.notification_voicemail_no_vm_number);
359
360 // If the voicemail number if unknown, instead of calling voicemail, take the user
361 // to the voicemail settings.
362 notificationText = mContext.getString(
363 R.string.notification_voicemail_no_vm_number);
Andrew Leebf07f762015-04-07 19:05:50 -0700364 intent = new Intent(VoicemailSettingsActivity.ACTION_ADD_VOICEMAIL);
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800365 intent.putExtra(SubscriptionInfoHelper.SUB_ID_EXTRA, subId);
Andrew Leebf07f762015-04-07 19:05:50 -0700366 intent.setClass(mContext, VoicemailSettingsActivity.class);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700367 } else {
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800368 if (mTelephonyManager.getPhoneCount() > 1) {
369 notificationText = subInfo.getDisplayName().toString();
Andrew Leed5165b02014-12-05 15:53:58 -0800370 } else {
371 notificationText = String.format(
372 mContext.getString(R.string.notification_voicemail_text_format),
373 PhoneNumberUtils.formatNumber(vmNumber));
374 }
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800375 intent = new Intent(
376 Intent.ACTION_CALL, Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "",
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700377 null));
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800378 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700379 }
380
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800381 PendingIntent pendingIntent =
382 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800383 Uri ringtoneUri = null;
384
385 if (enableNotificationSound) {
386 ringtoneUri = VoicemailNotificationSettingsUtil.getRingtoneUri(mPhone);
387 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700388
Nancy Chenb4a92702014-12-04 15:57:29 -0800389 Resources res = mContext.getResources();
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700390 PersistableBundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700391 mPhone.getSubId());
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700392 Notification.Builder builder = new Notification.Builder(mContext);
393 builder.setSmallIcon(resId)
394 .setWhen(System.currentTimeMillis())
Andrew Leed5165b02014-12-05 15:53:58 -0800395 .setColor(subInfo.getIconTint())
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700396 .setContentTitle(notificationTitle)
397 .setContentText(notificationText)
398 .setContentIntent(pendingIntent)
Yorke Leeacb5f742014-08-19 09:08:42 -0700399 .setSound(ringtoneUri)
Nancy Chenb4a92702014-12-04 15:57:29 -0800400 .setColor(res.getColor(R.color.dialer_theme_color))
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700401 .setOngoing(carrierConfig.getBoolean(
402 CarrierConfigManager.BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700403
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800404 if (VoicemailNotificationSettingsUtil.isVibrationEnabled(phone)) {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700405 builder.setDefaults(Notification.DEFAULT_VIBRATE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700406 }
Andrew Lee99d0ac22014-10-10 13:18:04 -0700407
408 final Notification notification = builder.build();
409 List<UserInfo> users = mUserManager.getUsers(true);
410 for (int i = 0; i < users.size(); i++) {
Yorke Lee047b1f92014-10-24 10:22:41 -0700411 final UserInfo user = users.get(i);
412 final UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700413 if (!mUserManager.hasUserRestriction(
Yorke Lee047b1f92014-10-24 10:22:41 -0700414 UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700415 && !user.isManagedProfile()) {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700416 mNotificationManager.notifyAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800417 Integer.toString(subId) /* tag */,
418 VOICEMAIL_NOTIFICATION,
419 notification,
420 userHandle);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700421 }
422 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700423 } else {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700424 mNotificationManager.cancelAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800425 Integer.toString(subId) /* tag */,
426 VOICEMAIL_NOTIFICATION,
427 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700428 }
429 }
430
431 /**
432 * Updates the message call forwarding indicator notification.
433 *
434 * @param visible true if there are messages waiting
435 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800436 /* package */ void updateCfi(int subId, boolean visible) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700437 if (DBG) log("updateCfi(): " + visible);
438 if (visible) {
439 // If Unconditional Call Forwarding (forward all calls) for VOICE
440 // is enabled, just show a notification. We'll default to expanded
441 // view for now, so the there is less confusion about the icon. If
442 // it is deemed too weird to have CF indications as expanded views,
443 // then we'll flip the flag back.
444
445 // TODO: We may want to take a look to see if the notification can
446 // display the target to forward calls to. This will require some
447 // effort though, since there are multiple layers of messages that
448 // will need to propagate that information.
449
Andrew Leed5165b02014-12-05 15:53:58 -0800450 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
451 if (subInfo == null) {
452 Log.w(LOG_TAG, "Found null subscription info for: " + subId);
453 return;
454 }
455
456 String notificationTitle;
457 if (mTelephonyManager.getPhoneCount() > 1) {
458 notificationTitle = subInfo.getDisplayName().toString();
459 } else {
460 notificationTitle = mContext.getString(R.string.labelCF);
461 }
462
Andrew Lee99d0ac22014-10-10 13:18:04 -0700463 Notification.Builder builder = new Notification.Builder(mContext)
464 .setSmallIcon(R.drawable.stat_sys_phone_call_forward)
Andrew Leed5165b02014-12-05 15:53:58 -0800465 .setColor(subInfo.getIconTint())
466 .setContentTitle(notificationTitle)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700467 .setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
468 .setShowWhen(false)
469 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700470
Andrew Lee99d0ac22014-10-10 13:18:04 -0700471 Intent intent = new Intent(Intent.ACTION_MAIN);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800472 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700473 intent.setClassName("com.android.phone", "com.android.phone.CallFeaturesSetting");
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800474 SubscriptionInfoHelper.addExtrasToIntent(
475 intent, mSubscriptionManager.getActiveSubscriptionInfo(subId));
476 PendingIntent contentIntent =
477 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700478
479 List<UserInfo> users = mUserManager.getUsers(true);
480 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800481 final UserInfo user = users.get(i);
482 if (user.isManagedProfile()) {
483 continue;
484 }
485 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700486 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800487 mNotificationManager.notifyAsUser(
488 Integer.toString(subId) /* tag */,
489 CALL_FORWARD_NOTIFICATION,
490 builder.build(),
491 userHandle);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700492 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700493 } else {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700494 mNotificationManager.cancelAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800495 Integer.toString(subId) /* tag */,
496 CALL_FORWARD_NOTIFICATION,
497 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700498 }
499 }
500
501 /**
502 * Shows the "data disconnected due to roaming" notification, which
503 * appears when you lose data connectivity because you're roaming and
504 * you have the "data roaming" feature turned off.
505 */
506 /* package */ void showDataDisconnectedRoaming() {
507 if (DBG) log("showDataDisconnectedRoaming()...");
508
509 // "Mobile network settings" screen / dialog
510 Intent intent = new Intent(mContext, com.android.phone.MobileNetworkSettings.class);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700511 PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700512
513 final CharSequence contentText = mContext.getText(R.string.roaming_reenable_message);
514
Andrew Lee99d0ac22014-10-10 13:18:04 -0700515 final Notification.Builder builder = new Notification.Builder(mContext)
516 .setSmallIcon(android.R.drawable.stat_sys_warning)
517 .setContentTitle(mContext.getText(R.string.roaming))
518 .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
519 .setContentText(contentText);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700520
Andrew Lee99d0ac22014-10-10 13:18:04 -0700521 List<UserInfo> users = mUserManager.getUsers(true);
522 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800523 final UserInfo user = users.get(i);
524 if (user.isManagedProfile()) {
525 continue;
526 }
527 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700528 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
529 final Notification notif =
530 new Notification.BigTextStyle(builder).bigText(contentText).build();
531 mNotificationManager.notifyAsUser(
532 null /* tag */, DATA_DISCONNECTED_ROAMING_NOTIFICATION, notif, userHandle);
533 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700534 }
535
536 /**
537 * Turns off the "data disconnected due to roaming" notification.
538 */
539 /* package */ void hideDataDisconnectedRoaming() {
540 if (DBG) log("hideDataDisconnectedRoaming()...");
541 mNotificationManager.cancel(DATA_DISCONNECTED_ROAMING_NOTIFICATION);
542 }
543
544 /**
545 * Display the network selection "no service" notification
546 * @param operator is the numeric operator number
547 */
548 private void showNetworkSelection(String operator) {
549 if (DBG) log("showNetworkSelection(" + operator + ")...");
550
Andrew Lee99d0ac22014-10-10 13:18:04 -0700551 Notification.Builder builder = new Notification.Builder(mContext)
552 .setSmallIcon(android.R.drawable.stat_sys_warning)
553 .setContentTitle(mContext.getString(R.string.notification_network_selection_title))
554 .setContentText(
555 mContext.getString(R.string.notification_network_selection_text, operator))
556 .setShowWhen(false)
557 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700558
559 // create the target network operators settings intent
560 Intent intent = new Intent(Intent.ACTION_MAIN);
561 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
562 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
563 // Use NetworkSetting to handle the selection intent
564 intent.setComponent(new ComponentName("com.android.phone",
565 "com.android.phone.NetworkSetting"));
Andrew Lee99d0ac22014-10-10 13:18:04 -0700566 PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700567
Andrew Lee99d0ac22014-10-10 13:18:04 -0700568 List<UserInfo> users = mUserManager.getUsers(true);
569 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800570 final UserInfo user = users.get(i);
571 if (user.isManagedProfile()) {
572 continue;
573 }
574 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700575 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
576 mNotificationManager.notifyAsUser(
577 null /* tag */,
578 SELECTED_OPERATOR_FAIL_NOTIFICATION,
579 builder.build(),
580 userHandle);
581 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700582 }
583
584 /**
585 * Turn off the network selection "no service" notification
586 */
587 private void cancelNetworkSelection() {
588 if (DBG) log("cancelNetworkSelection()...");
Andrew Lee99d0ac22014-10-10 13:18:04 -0700589 mNotificationManager.cancelAsUser(
590 null /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION, UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700591 }
592
593 /**
594 * Update notification about no service of user selected operator
595 *
596 * @param serviceState Phone service state
597 */
598 void updateNetworkSelection(int serviceState) {
599 if (TelephonyCapabilities.supportsNetworkSelection(mPhone)) {
Amit Mahajana60be872015-01-15 16:05:08 -0800600 int subId = mPhone.getSubId();
601 if (SubscriptionManager.isValidSubscriptionId(subId)) {
602 // get the shared preference of network_selection.
603 // empty is auto mode, otherwise it is the operator alpha name
604 // in case there is no operator name, check the operator numeric
605 SharedPreferences sp =
606 PreferenceManager.getDefaultSharedPreferences(mContext);
607 String networkSelection =
608 sp.getString(PhoneBase.NETWORK_SELECTION_NAME_KEY + subId, "");
609 if (TextUtils.isEmpty(networkSelection)) {
610 networkSelection =
611 sp.getString(PhoneBase.NETWORK_SELECTION_KEY + subId, "");
612 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700613
Amit Mahajana60be872015-01-15 16:05:08 -0800614 if (DBG) log("updateNetworkSelection()..." + "state = " +
615 serviceState + " new network " + networkSelection);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700616
Amit Mahajana60be872015-01-15 16:05:08 -0800617 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
618 && !TextUtils.isEmpty(networkSelection)) {
619 if (!mSelectedUnavailableNotify) {
620 showNetworkSelection(networkSelection);
621 mSelectedUnavailableNotify = true;
622 }
623 } else {
624 if (mSelectedUnavailableNotify) {
625 cancelNetworkSelection();
626 mSelectedUnavailableNotify = false;
627 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700628 }
629 } else {
Amit Mahajana60be872015-01-15 16:05:08 -0800630 if (DBG) log("updateNetworkSelection()..." + "state = " +
631 serviceState + " not updating network due to invalid subId " + subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700632 }
633 }
634 }
635
636 /* package */ void postTransientNotification(int notifyId, CharSequence msg) {
637 if (mToast != null) {
638 mToast.cancel();
639 }
640
641 mToast = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
642 mToast.show();
643 }
644
645 private void log(String msg) {
646 Log.d(LOG_TAG, msg);
647 }
648}