blob: 65f75941ac6f9d39b629e60393e9abc8fef0fd2e [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;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070028import android.net.Uri;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070029import android.os.SystemProperties;
Andrew Lee99d0ac22014-10-10 13:18:04 -070030import android.os.UserHandle;
31import android.os.UserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070032import android.preference.PreferenceManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070033import android.provider.ContactsContract.PhoneLookup;
34import android.provider.Settings;
Tyler Gunn4d45d1c2014-09-12 22:17:53 -070035import android.telecom.PhoneAccount;
Andrew Leed5165b02014-12-05 15:53:58 -080036import android.telecom.PhoneAccountHandle;
37import android.telecom.TelecomManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070038import android.telephony.PhoneNumberUtils;
39import android.telephony.ServiceState;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080040import android.telephony.SubscriptionInfo;
Andrew Leea82b8202014-11-21 16:18:28 -080041import android.telephony.SubscriptionManager;
Andrew Leed5165b02014-12-05 15:53:58 -080042import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070043import android.text.TextUtils;
44import android.util.Log;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070045import android.widget.Toast;
46
Santos Cordon7d4ddf62013-07-10 11:58:08 -070047import com.android.internal.telephony.Phone;
48import com.android.internal.telephony.PhoneBase;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070049import com.android.internal.telephony.TelephonyCapabilities;
Andrew Lee8d66d812014-11-24 14:54:02 -080050import com.android.phone.settings.VoicemailNotificationSettingsUtil;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051
Andrew Lee99d0ac22014-10-10 13:18:04 -070052import java.util.List;
53
Santos Cordon7d4ddf62013-07-10 11:58:08 -070054/**
55 * NotificationManager-related utility code for the Phone app.
56 *
57 * This is a singleton object which acts as the interface to the
58 * framework's NotificationManager, and is used to display status bar
59 * icons and control other status bar-related behavior.
60 *
61 * @see PhoneGlobals.notificationMgr
62 */
Chiao Cheng312b9c92013-09-16 15:40:53 -070063public class NotificationMgr {
Andrew Leea82b8202014-11-21 16:18:28 -080064 private static final String LOG_TAG = NotificationMgr.class.getSimpleName();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070065 private static final boolean DBG =
66 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
67 // Do not check in with VDBG = true, since that may write PII to the system log.
68 private static final boolean VDBG = false;
69
Santos Cordon7d4ddf62013-07-10 11:58:08 -070070 // notification types
Santos Cordonf68db2e2014-07-02 14:40:44 -070071 static final int MMI_NOTIFICATION = 1;
72 static final int NETWORK_SELECTION_NOTIFICATION = 2;
73 static final int VOICEMAIL_NOTIFICATION = 3;
74 static final int CALL_FORWARD_NOTIFICATION = 4;
75 static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
76 static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070077
78 /** The singleton NotificationMgr instance. */
79 private static NotificationMgr sInstance;
80
81 private PhoneGlobals mApp;
82 private Phone mPhone;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070083
84 private Context mContext;
85 private NotificationManager mNotificationManager;
86 private StatusBarManager mStatusBarManager;
Andrew Lee99d0ac22014-10-10 13:18:04 -070087 private UserManager mUserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070088 private Toast mToast;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080089 private SubscriptionManager mSubscriptionManager;
Andrew Leed5165b02014-12-05 15:53:58 -080090 private TelecomManager mTelecomManager;
91 private TelephonyManager mTelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070092
93 public StatusBarHelper statusBarHelper;
94
Santos Cordon7d4ddf62013-07-10 11:58:08 -070095 // used to track the notification of selected network unavailable
96 private boolean mSelectedUnavailableNotify = false;
97
Santos Cordon7d4ddf62013-07-10 11:58:08 -070098 /**
99 * Private constructor (this is a singleton).
Santos Cordonf68db2e2014-07-02 14:40:44 -0700100 * @see #init(PhoneGlobals)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700101 */
102 private NotificationMgr(PhoneGlobals app) {
103 mApp = app;
104 mContext = app;
105 mNotificationManager =
106 (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
107 mStatusBarManager =
108 (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700109 mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700110 mPhone = app.phone; // TODO: better style to use mCM.getDefaultPhone() everywhere instead
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700111 statusBarHelper = new StatusBarHelper();
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800112 mSubscriptionManager = SubscriptionManager.from(mContext);
Andrew Leed5165b02014-12-05 15:53:58 -0800113 mTelecomManager = TelecomManager.from(mContext);
114 mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700115 }
116
117 /**
118 * Initialize the singleton NotificationMgr instance.
119 *
120 * This is only done once, at startup, from PhoneApp.onCreate().
121 * From then on, the NotificationMgr instance is available via the
122 * PhoneApp's public "notificationMgr" field, which is why there's no
123 * getInstance() method here.
124 */
125 /* package */ static NotificationMgr init(PhoneGlobals app) {
126 synchronized (NotificationMgr.class) {
127 if (sInstance == null) {
128 sInstance = new NotificationMgr(app);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700129 } else {
130 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
131 }
132 return sInstance;
133 }
134 }
135
136 /**
137 * Helper class that's a wrapper around the framework's
138 * StatusBarManager.disable() API.
139 *
140 * This class is used to control features like:
141 *
142 * - Disabling the status bar "notification windowshade"
143 * while the in-call UI is up
144 *
145 * - Disabling notification alerts (audible or vibrating)
146 * while a phone call is active
147 *
148 * - Disabling navigation via the system bar (the "soft buttons" at
149 * the bottom of the screen on devices with no hard buttons)
150 *
151 * We control these features through a single point of control to make
152 * sure that the various StatusBarManager.disable() calls don't
153 * interfere with each other.
154 */
155 public class StatusBarHelper {
156 // Current desired state of status bar / system bar behavior
157 private boolean mIsNotificationEnabled = true;
158 private boolean mIsExpandedViewEnabled = true;
159 private boolean mIsSystemBarNavigationEnabled = true;
160
Andrew Leed5165b02014-12-05 15:53:58 -0800161 private StatusBarHelper() {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700162 }
163
164 /**
165 * Enables or disables auditory / vibrational alerts.
166 *
167 * (We disable these any time a voice call is active, regardless
168 * of whether or not the in-call UI is visible.)
169 */
170 public void enableNotificationAlerts(boolean enable) {
171 if (mIsNotificationEnabled != enable) {
172 mIsNotificationEnabled = enable;
173 updateStatusBar();
174 }
175 }
176
177 /**
178 * Enables or disables the expanded view of the status bar
179 * (i.e. the ability to pull down the "notification windowshade").
180 *
181 * (This feature is disabled by the InCallScreen while the in-call
182 * UI is active.)
183 */
184 public void enableExpandedView(boolean enable) {
185 if (mIsExpandedViewEnabled != enable) {
186 mIsExpandedViewEnabled = enable;
187 updateStatusBar();
188 }
189 }
190
191 /**
192 * Enables or disables the navigation via the system bar (the
193 * "soft buttons" at the bottom of the screen)
194 *
195 * (This feature is disabled while an incoming call is ringing,
196 * because it's easy to accidentally touch the system bar while
197 * pulling the phone out of your pocket.)
198 */
199 public void enableSystemBarNavigation(boolean enable) {
200 if (mIsSystemBarNavigationEnabled != enable) {
201 mIsSystemBarNavigationEnabled = enable;
202 updateStatusBar();
203 }
204 }
205
206 /**
207 * Updates the status bar to reflect the current desired state.
208 */
209 private void updateStatusBar() {
210 int state = StatusBarManager.DISABLE_NONE;
211
212 if (!mIsExpandedViewEnabled) {
213 state |= StatusBarManager.DISABLE_EXPAND;
214 }
215 if (!mIsNotificationEnabled) {
216 state |= StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
217 }
218 if (!mIsSystemBarNavigationEnabled) {
219 // Disable *all* possible navigation via the system bar.
220 state |= StatusBarManager.DISABLE_HOME;
221 state |= StatusBarManager.DISABLE_RECENT;
222 state |= StatusBarManager.DISABLE_BACK;
Christine Chenb685f172013-09-25 18:32:59 -0700223 state |= StatusBarManager.DISABLE_SEARCH;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700224 }
225
226 if (DBG) log("updateStatusBar: state = 0x" + Integer.toHexString(state));
227 mStatusBarManager.disable(state);
228 }
229 }
230
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700231 /** The projection to use when querying the phones table */
232 static final String[] PHONES_PROJECTION = new String[] {
233 PhoneLookup.NUMBER,
234 PhoneLookup.DISPLAY_NAME,
235 PhoneLookup._ID
236 };
237
238 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700239 * Updates the message waiting indicator (voicemail) notification.
240 *
241 * @param visible true if there are messages waiting
242 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800243 /* package */ void updateMwi(int subId, boolean visible) {
244 if (DBG) log("updateMwi(): subId " + subId + " update to " + visible);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700245
Andrew Leea82b8202014-11-21 16:18:28 -0800246 if (!PhoneGlobals.sVoiceCapable) {
247 // Do not show the message waiting indicator on devices which are not voice capable.
248 // These events *should* be blocked at the telephony layer for such devices.
249 Log.w(LOG_TAG, "Called updateMwi() on non-voice-capable device! Ignoring...");
250 return;
251 }
252
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700253 if (visible) {
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800254 Phone phone = PhoneGlobals.getPhone(subId);
255 if (phone == null) {
Andrew Leed5165b02014-12-05 15:53:58 -0800256 Log.w(LOG_TAG, "Found null phone for: " + subId);
257 return;
258 }
259
260 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
261 if (subInfo == null) {
262 Log.w(LOG_TAG, "Found null subscription info for: " + subId);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800263 return;
264 }
265
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700266 int resId = android.R.drawable.stat_notify_voicemail;
267
268 // This Notification can get a lot fancier once we have more
269 // information about the current voicemail messages.
270 // (For example, the current voicemail system can't tell
271 // us the caller-id or timestamp of a message, or tell us the
272 // message count.)
273
274 // But for now, the UI is ultra-simple: if the MWI indication
275 // is supposed to be visible, just show a single generic
276 // notification.
277
278 String notificationTitle = mContext.getString(R.string.notification_voicemail_title);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800279 String vmNumber = phone.getVoiceMailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700280 if (DBG) log("- got vm number: '" + vmNumber + "'");
281
Andrew Leea82b8202014-11-21 16:18:28 -0800282 // The voicemail number may be null because:
283 // (1) This phone has no voicemail number.
284 // (2) This phone has a voicemail number, but the SIM isn't ready yet. This may
285 // happen when the device first boots if we get a MWI notification when we
286 // register on the network before the SIM has loaded. In this case, the
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800287 // SubscriptionListener in CallNotifier will update this once the SIM is loaded.
288 if ((vmNumber == null) && !phone.getIccRecordsLoaded()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700289 if (DBG) log("- Null vm number: SIM records not loaded (yet)...");
Andrew Leea82b8202014-11-21 16:18:28 -0800290 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700291 }
292
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800293 if (TelephonyCapabilities.supportsVoiceMessageCount(phone)) {
294 int vmCount = phone.getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700295 String titleFormat = mContext.getString(R.string.notification_voicemail_title_count);
296 notificationTitle = String.format(titleFormat, vmCount);
297 }
298
299 String notificationText;
Andrew Leed5165b02014-12-05 15:53:58 -0800300 if (mTelephonyManager.getPhoneCount() > 1) {
301 notificationText = subInfo.getDisplayName().toString();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700302 } else {
Andrew Leed5165b02014-12-05 15:53:58 -0800303 if (TextUtils.isEmpty(vmNumber)) {
304 notificationText = mContext.getString(
305 R.string.notification_voicemail_no_vm_number);
306 } else {
307 notificationText = String.format(
308 mContext.getString(R.string.notification_voicemail_text_format),
309 PhoneNumberUtils.formatNumber(vmNumber));
310 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700311 }
312
Andrew Leed5165b02014-12-05 15:53:58 -0800313 // This pathway only applies to PSTN accounts; only SIMS have subscription ids.
314 PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(phone);
315 Intent intent = new Intent(
316 Intent.ACTION_CALL, Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null));
317 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800318 PendingIntent pendingIntent =
319 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
320 Uri ringtoneUri = VoicemailNotificationSettingsUtil.getRingtoneUri(phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700321
322 Notification.Builder builder = new Notification.Builder(mContext);
323 builder.setSmallIcon(resId)
324 .setWhen(System.currentTimeMillis())
Andrew Leed5165b02014-12-05 15:53:58 -0800325 .setColor(subInfo.getIconTint())
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700326 .setContentTitle(notificationTitle)
327 .setContentText(notificationText)
328 .setContentIntent(pendingIntent)
Yorke Leeacb5f742014-08-19 09:08:42 -0700329 .setSound(ringtoneUri)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700330 .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
331 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700332
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800333 if (VoicemailNotificationSettingsUtil.isVibrationEnabled(phone)) {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700334 builder.setDefaults(Notification.DEFAULT_VIBRATE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700335 }
Andrew Lee99d0ac22014-10-10 13:18:04 -0700336
337 final Notification notification = builder.build();
338 List<UserInfo> users = mUserManager.getUsers(true);
339 for (int i = 0; i < users.size(); i++) {
Yorke Lee047b1f92014-10-24 10:22:41 -0700340 final UserInfo user = users.get(i);
341 final UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700342 if (!mUserManager.hasUserRestriction(
Yorke Lee047b1f92014-10-24 10:22:41 -0700343 UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
344 && !user.isManagedProfile()) {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700345 mNotificationManager.notifyAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800346 Integer.toString(subId) /* tag */,
347 VOICEMAIL_NOTIFICATION,
348 notification,
349 userHandle);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700350 }
351 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700352 } else {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700353 mNotificationManager.cancelAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800354 Integer.toString(subId) /* tag */,
355 VOICEMAIL_NOTIFICATION,
356 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700357 }
358 }
359
360 /**
361 * Updates the message call forwarding indicator notification.
362 *
363 * @param visible true if there are messages waiting
364 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800365 /* package */ void updateCfi(int subId, boolean visible) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700366 if (DBG) log("updateCfi(): " + visible);
367 if (visible) {
368 // If Unconditional Call Forwarding (forward all calls) for VOICE
369 // is enabled, just show a notification. We'll default to expanded
370 // view for now, so the there is less confusion about the icon. If
371 // it is deemed too weird to have CF indications as expanded views,
372 // then we'll flip the flag back.
373
374 // TODO: We may want to take a look to see if the notification can
375 // display the target to forward calls to. This will require some
376 // effort though, since there are multiple layers of messages that
377 // will need to propagate that information.
378
Andrew Leed5165b02014-12-05 15:53:58 -0800379 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
380 if (subInfo == null) {
381 Log.w(LOG_TAG, "Found null subscription info for: " + subId);
382 return;
383 }
384
385 String notificationTitle;
386 if (mTelephonyManager.getPhoneCount() > 1) {
387 notificationTitle = subInfo.getDisplayName().toString();
388 } else {
389 notificationTitle = mContext.getString(R.string.labelCF);
390 }
391
Andrew Lee99d0ac22014-10-10 13:18:04 -0700392 Notification.Builder builder = new Notification.Builder(mContext)
393 .setSmallIcon(R.drawable.stat_sys_phone_call_forward)
Andrew Leed5165b02014-12-05 15:53:58 -0800394 .setColor(subInfo.getIconTint())
395 .setContentTitle(notificationTitle)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700396 .setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
397 .setShowWhen(false)
398 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700399
Andrew Lee99d0ac22014-10-10 13:18:04 -0700400 Intent intent = new Intent(Intent.ACTION_MAIN);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800401 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700402 intent.setClassName("com.android.phone", "com.android.phone.CallFeaturesSetting");
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800403 SubscriptionInfoHelper.addExtrasToIntent(
404 intent, mSubscriptionManager.getActiveSubscriptionInfo(subId));
405 PendingIntent contentIntent =
406 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700407
408 List<UserInfo> users = mUserManager.getUsers(true);
409 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800410 final UserInfo user = users.get(i);
411 if (user.isManagedProfile()) {
412 continue;
413 }
414 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700415 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800416 mNotificationManager.notifyAsUser(
417 Integer.toString(subId) /* tag */,
418 CALL_FORWARD_NOTIFICATION,
419 builder.build(),
420 userHandle);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700421 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700422 } else {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700423 mNotificationManager.cancelAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800424 Integer.toString(subId) /* tag */,
425 CALL_FORWARD_NOTIFICATION,
426 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700427 }
428 }
429
430 /**
431 * Shows the "data disconnected due to roaming" notification, which
432 * appears when you lose data connectivity because you're roaming and
433 * you have the "data roaming" feature turned off.
434 */
435 /* package */ void showDataDisconnectedRoaming() {
436 if (DBG) log("showDataDisconnectedRoaming()...");
437
438 // "Mobile network settings" screen / dialog
439 Intent intent = new Intent(mContext, com.android.phone.MobileNetworkSettings.class);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700440 PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700441
442 final CharSequence contentText = mContext.getText(R.string.roaming_reenable_message);
443
Andrew Lee99d0ac22014-10-10 13:18:04 -0700444 final Notification.Builder builder = new Notification.Builder(mContext)
445 .setSmallIcon(android.R.drawable.stat_sys_warning)
446 .setContentTitle(mContext.getText(R.string.roaming))
447 .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
448 .setContentText(contentText);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700449
Andrew Lee99d0ac22014-10-10 13:18:04 -0700450 List<UserInfo> users = mUserManager.getUsers(true);
451 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800452 final UserInfo user = users.get(i);
453 if (user.isManagedProfile()) {
454 continue;
455 }
456 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700457 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
458 final Notification notif =
459 new Notification.BigTextStyle(builder).bigText(contentText).build();
460 mNotificationManager.notifyAsUser(
461 null /* tag */, DATA_DISCONNECTED_ROAMING_NOTIFICATION, notif, userHandle);
462 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700463 }
464
465 /**
466 * Turns off the "data disconnected due to roaming" notification.
467 */
468 /* package */ void hideDataDisconnectedRoaming() {
469 if (DBG) log("hideDataDisconnectedRoaming()...");
470 mNotificationManager.cancel(DATA_DISCONNECTED_ROAMING_NOTIFICATION);
471 }
472
473 /**
474 * Display the network selection "no service" notification
475 * @param operator is the numeric operator number
476 */
477 private void showNetworkSelection(String operator) {
478 if (DBG) log("showNetworkSelection(" + operator + ")...");
479
Andrew Lee99d0ac22014-10-10 13:18:04 -0700480 Notification.Builder builder = new Notification.Builder(mContext)
481 .setSmallIcon(android.R.drawable.stat_sys_warning)
482 .setContentTitle(mContext.getString(R.string.notification_network_selection_title))
483 .setContentText(
484 mContext.getString(R.string.notification_network_selection_text, operator))
485 .setShowWhen(false)
486 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700487
488 // create the target network operators settings intent
489 Intent intent = new Intent(Intent.ACTION_MAIN);
490 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
491 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
492 // Use NetworkSetting to handle the selection intent
493 intent.setComponent(new ComponentName("com.android.phone",
494 "com.android.phone.NetworkSetting"));
Andrew Lee99d0ac22014-10-10 13:18:04 -0700495 PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700496
Andrew Lee99d0ac22014-10-10 13:18:04 -0700497 List<UserInfo> users = mUserManager.getUsers(true);
498 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800499 final UserInfo user = users.get(i);
500 if (user.isManagedProfile()) {
501 continue;
502 }
503 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700504 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
505 mNotificationManager.notifyAsUser(
506 null /* tag */,
507 SELECTED_OPERATOR_FAIL_NOTIFICATION,
508 builder.build(),
509 userHandle);
510 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700511 }
512
513 /**
514 * Turn off the network selection "no service" notification
515 */
516 private void cancelNetworkSelection() {
517 if (DBG) log("cancelNetworkSelection()...");
Andrew Lee99d0ac22014-10-10 13:18:04 -0700518 mNotificationManager.cancelAsUser(
519 null /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION, UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700520 }
521
522 /**
523 * Update notification about no service of user selected operator
524 *
525 * @param serviceState Phone service state
526 */
527 void updateNetworkSelection(int serviceState) {
528 if (TelephonyCapabilities.supportsNetworkSelection(mPhone)) {
529 // get the shared preference of network_selection.
530 // empty is auto mode, otherwise it is the operator alpha name
531 // in case there is no operator name, check the operator numeric
532 SharedPreferences sp =
533 PreferenceManager.getDefaultSharedPreferences(mContext);
534 String networkSelection =
535 sp.getString(PhoneBase.NETWORK_SELECTION_NAME_KEY, "");
536 if (TextUtils.isEmpty(networkSelection)) {
537 networkSelection =
538 sp.getString(PhoneBase.NETWORK_SELECTION_KEY, "");
539 }
540
541 if (DBG) log("updateNetworkSelection()..." + "state = " +
542 serviceState + " new network " + networkSelection);
543
544 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
545 && !TextUtils.isEmpty(networkSelection)) {
546 if (!mSelectedUnavailableNotify) {
547 showNetworkSelection(networkSelection);
548 mSelectedUnavailableNotify = true;
549 }
550 } else {
551 if (mSelectedUnavailableNotify) {
552 cancelNetworkSelection();
553 mSelectedUnavailableNotify = false;
554 }
555 }
556 }
557 }
558
559 /* package */ void postTransientNotification(int notifyId, CharSequence msg) {
560 if (mToast != null) {
561 mToast.cancel();
562 }
563
564 mToast = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
565 mToast.show();
566 }
567
568 private void log(String msg) {
569 Log.d(LOG_TAG, msg);
570 }
571}