blob: 90b65951315349bb87b0f7b73345d98821f9c058 [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;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070036import android.telephony.PhoneNumberUtils;
37import android.telephony.ServiceState;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080038import android.telephony.SubscriptionInfo;
Andrew Leea82b8202014-11-21 16:18:28 -080039import android.telephony.SubscriptionManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070040import android.text.TextUtils;
41import android.util.Log;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070042import android.widget.Toast;
43
Santos Cordon7d4ddf62013-07-10 11:58:08 -070044import com.android.internal.telephony.Phone;
45import com.android.internal.telephony.PhoneBase;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070046import com.android.internal.telephony.TelephonyCapabilities;
Andrew Lee8d66d812014-11-24 14:54:02 -080047import com.android.phone.settings.VoicemailNotificationSettingsUtil;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070048
Andrew Lee99d0ac22014-10-10 13:18:04 -070049import java.util.List;
50
Santos Cordon7d4ddf62013-07-10 11:58:08 -070051/**
52 * NotificationManager-related utility code for the Phone app.
53 *
54 * This is a singleton object which acts as the interface to the
55 * framework's NotificationManager, and is used to display status bar
56 * icons and control other status bar-related behavior.
57 *
58 * @see PhoneGlobals.notificationMgr
59 */
Chiao Cheng312b9c92013-09-16 15:40:53 -070060public class NotificationMgr {
Andrew Leea82b8202014-11-21 16:18:28 -080061 private static final String LOG_TAG = NotificationMgr.class.getSimpleName();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070062 private static final boolean DBG =
63 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
64 // Do not check in with VDBG = true, since that may write PII to the system log.
65 private static final boolean VDBG = false;
66
Santos Cordon7d4ddf62013-07-10 11:58:08 -070067 // notification types
Santos Cordonf68db2e2014-07-02 14:40:44 -070068 static final int MMI_NOTIFICATION = 1;
69 static final int NETWORK_SELECTION_NOTIFICATION = 2;
70 static final int VOICEMAIL_NOTIFICATION = 3;
71 static final int CALL_FORWARD_NOTIFICATION = 4;
72 static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
73 static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070074
75 /** The singleton NotificationMgr instance. */
76 private static NotificationMgr sInstance;
77
78 private PhoneGlobals mApp;
79 private Phone mPhone;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070080
81 private Context mContext;
82 private NotificationManager mNotificationManager;
83 private StatusBarManager mStatusBarManager;
Andrew Lee99d0ac22014-10-10 13:18:04 -070084 private UserManager mUserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070085 private Toast mToast;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080086 private SubscriptionManager mSubscriptionManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070087
88 public StatusBarHelper statusBarHelper;
89
Santos Cordon7d4ddf62013-07-10 11:58:08 -070090 // used to track the notification of selected network unavailable
91 private boolean mSelectedUnavailableNotify = false;
92
Santos Cordon7d4ddf62013-07-10 11:58:08 -070093 /**
94 * Private constructor (this is a singleton).
Santos Cordonf68db2e2014-07-02 14:40:44 -070095 * @see #init(PhoneGlobals)
Santos Cordon7d4ddf62013-07-10 11:58:08 -070096 */
97 private NotificationMgr(PhoneGlobals app) {
98 mApp = app;
99 mContext = app;
100 mNotificationManager =
101 (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
102 mStatusBarManager =
103 (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700104 mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700105 mPhone = app.phone; // TODO: better style to use mCM.getDefaultPhone() everywhere instead
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700106 statusBarHelper = new StatusBarHelper();
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800107 mSubscriptionManager = SubscriptionManager.from(mContext);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700108 }
109
110 /**
111 * Initialize the singleton NotificationMgr instance.
112 *
113 * This is only done once, at startup, from PhoneApp.onCreate().
114 * From then on, the NotificationMgr instance is available via the
115 * PhoneApp's public "notificationMgr" field, which is why there's no
116 * getInstance() method here.
117 */
118 /* package */ static NotificationMgr init(PhoneGlobals app) {
119 synchronized (NotificationMgr.class) {
120 if (sInstance == null) {
121 sInstance = new NotificationMgr(app);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700122 } else {
123 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
124 }
125 return sInstance;
126 }
127 }
128
129 /**
130 * Helper class that's a wrapper around the framework's
131 * StatusBarManager.disable() API.
132 *
133 * This class is used to control features like:
134 *
135 * - Disabling the status bar "notification windowshade"
136 * while the in-call UI is up
137 *
138 * - Disabling notification alerts (audible or vibrating)
139 * while a phone call is active
140 *
141 * - Disabling navigation via the system bar (the "soft buttons" at
142 * the bottom of the screen on devices with no hard buttons)
143 *
144 * We control these features through a single point of control to make
145 * sure that the various StatusBarManager.disable() calls don't
146 * interfere with each other.
147 */
148 public class StatusBarHelper {
149 // Current desired state of status bar / system bar behavior
150 private boolean mIsNotificationEnabled = true;
151 private boolean mIsExpandedViewEnabled = true;
152 private boolean mIsSystemBarNavigationEnabled = true;
153
154 private StatusBarHelper () {
155 }
156
157 /**
158 * Enables or disables auditory / vibrational alerts.
159 *
160 * (We disable these any time a voice call is active, regardless
161 * of whether or not the in-call UI is visible.)
162 */
163 public void enableNotificationAlerts(boolean enable) {
164 if (mIsNotificationEnabled != enable) {
165 mIsNotificationEnabled = enable;
166 updateStatusBar();
167 }
168 }
169
170 /**
171 * Enables or disables the expanded view of the status bar
172 * (i.e. the ability to pull down the "notification windowshade").
173 *
174 * (This feature is disabled by the InCallScreen while the in-call
175 * UI is active.)
176 */
177 public void enableExpandedView(boolean enable) {
178 if (mIsExpandedViewEnabled != enable) {
179 mIsExpandedViewEnabled = enable;
180 updateStatusBar();
181 }
182 }
183
184 /**
185 * Enables or disables the navigation via the system bar (the
186 * "soft buttons" at the bottom of the screen)
187 *
188 * (This feature is disabled while an incoming call is ringing,
189 * because it's easy to accidentally touch the system bar while
190 * pulling the phone out of your pocket.)
191 */
192 public void enableSystemBarNavigation(boolean enable) {
193 if (mIsSystemBarNavigationEnabled != enable) {
194 mIsSystemBarNavigationEnabled = enable;
195 updateStatusBar();
196 }
197 }
198
199 /**
200 * Updates the status bar to reflect the current desired state.
201 */
202 private void updateStatusBar() {
203 int state = StatusBarManager.DISABLE_NONE;
204
205 if (!mIsExpandedViewEnabled) {
206 state |= StatusBarManager.DISABLE_EXPAND;
207 }
208 if (!mIsNotificationEnabled) {
209 state |= StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
210 }
211 if (!mIsSystemBarNavigationEnabled) {
212 // Disable *all* possible navigation via the system bar.
213 state |= StatusBarManager.DISABLE_HOME;
214 state |= StatusBarManager.DISABLE_RECENT;
215 state |= StatusBarManager.DISABLE_BACK;
Christine Chenb685f172013-09-25 18:32:59 -0700216 state |= StatusBarManager.DISABLE_SEARCH;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700217 }
218
219 if (DBG) log("updateStatusBar: state = 0x" + Integer.toHexString(state));
220 mStatusBarManager.disable(state);
221 }
222 }
223
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700224 /** The projection to use when querying the phones table */
225 static final String[] PHONES_PROJECTION = new String[] {
226 PhoneLookup.NUMBER,
227 PhoneLookup.DISPLAY_NAME,
228 PhoneLookup._ID
229 };
230
231 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700232 * Updates the message waiting indicator (voicemail) notification.
233 *
234 * @param visible true if there are messages waiting
235 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800236 /* package */ void updateMwi(int subId, boolean visible) {
237 if (DBG) log("updateMwi(): subId " + subId + " update to " + visible);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700238
Andrew Leea82b8202014-11-21 16:18:28 -0800239 if (!PhoneGlobals.sVoiceCapable) {
240 // Do not show the message waiting indicator on devices which are not voice capable.
241 // These events *should* be blocked at the telephony layer for such devices.
242 Log.w(LOG_TAG, "Called updateMwi() on non-voice-capable device! Ignoring...");
243 return;
244 }
245
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700246 if (visible) {
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800247 Phone phone = PhoneGlobals.getPhone(subId);
248 if (phone == null) {
249 Log.w(LOG_TAG, "Null phone returned for " + subId);
250 return;
251 }
252
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700253 int resId = android.R.drawable.stat_notify_voicemail;
254
255 // This Notification can get a lot fancier once we have more
256 // information about the current voicemail messages.
257 // (For example, the current voicemail system can't tell
258 // us the caller-id or timestamp of a message, or tell us the
259 // message count.)
260
261 // But for now, the UI is ultra-simple: if the MWI indication
262 // is supposed to be visible, just show a single generic
263 // notification.
264
265 String notificationTitle = mContext.getString(R.string.notification_voicemail_title);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800266 String vmNumber = phone.getVoiceMailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700267 if (DBG) log("- got vm number: '" + vmNumber + "'");
268
Andrew Leea82b8202014-11-21 16:18:28 -0800269 // The voicemail number may be null because:
270 // (1) This phone has no voicemail number.
271 // (2) This phone has a voicemail number, but the SIM isn't ready yet. This may
272 // happen when the device first boots if we get a MWI notification when we
273 // register on the network before the SIM has loaded. In this case, the
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800274 // SubscriptionListener in CallNotifier will update this once the SIM is loaded.
275 if ((vmNumber == null) && !phone.getIccRecordsLoaded()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700276 if (DBG) log("- Null vm number: SIM records not loaded (yet)...");
Andrew Leea82b8202014-11-21 16:18:28 -0800277 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700278 }
279
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800280 if (TelephonyCapabilities.supportsVoiceMessageCount(phone)) {
281 int vmCount = phone.getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700282 String titleFormat = mContext.getString(R.string.notification_voicemail_title_count);
283 notificationTitle = String.format(titleFormat, vmCount);
284 }
285
286 String notificationText;
287 if (TextUtils.isEmpty(vmNumber)) {
288 notificationText = mContext.getString(
289 R.string.notification_voicemail_no_vm_number);
290 } else {
291 notificationText = String.format(
292 mContext.getString(R.string.notification_voicemail_text_format),
293 PhoneNumberUtils.formatNumber(vmNumber));
294 }
295
296 Intent intent = new Intent(Intent.ACTION_CALL,
Jay Shrauner137458b2014-09-05 14:27:25 -0700297 Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null));
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800298 PendingIntent pendingIntent =
299 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
300 Uri ringtoneUri = VoicemailNotificationSettingsUtil.getRingtoneUri(phone);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700301
302 Notification.Builder builder = new Notification.Builder(mContext);
303 builder.setSmallIcon(resId)
304 .setWhen(System.currentTimeMillis())
305 .setContentTitle(notificationTitle)
306 .setContentText(notificationText)
307 .setContentIntent(pendingIntent)
Yorke Leeacb5f742014-08-19 09:08:42 -0700308 .setSound(ringtoneUri)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700309 .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
310 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700311
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800312 if (VoicemailNotificationSettingsUtil.isVibrationEnabled(phone)) {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700313 builder.setDefaults(Notification.DEFAULT_VIBRATE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700314 }
Andrew Lee99d0ac22014-10-10 13:18:04 -0700315
316 final Notification notification = builder.build();
317 List<UserInfo> users = mUserManager.getUsers(true);
318 for (int i = 0; i < users.size(); i++) {
Yorke Lee047b1f92014-10-24 10:22:41 -0700319 final UserInfo user = users.get(i);
320 final UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700321 if (!mUserManager.hasUserRestriction(
Yorke Lee047b1f92014-10-24 10:22:41 -0700322 UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
323 && !user.isManagedProfile()) {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700324 mNotificationManager.notifyAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800325 Integer.toString(subId) /* tag */,
326 VOICEMAIL_NOTIFICATION,
327 notification,
328 userHandle);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700329 }
330 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700331 } else {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700332 mNotificationManager.cancelAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800333 Integer.toString(subId) /* tag */,
334 VOICEMAIL_NOTIFICATION,
335 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700336 }
337 }
338
339 /**
340 * Updates the message call forwarding indicator notification.
341 *
342 * @param visible true if there are messages waiting
343 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800344 /* package */ void updateCfi(int subId, boolean visible) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700345 if (DBG) log("updateCfi(): " + visible);
346 if (visible) {
347 // If Unconditional Call Forwarding (forward all calls) for VOICE
348 // is enabled, just show a notification. We'll default to expanded
349 // view for now, so the there is less confusion about the icon. If
350 // it is deemed too weird to have CF indications as expanded views,
351 // then we'll flip the flag back.
352
353 // TODO: We may want to take a look to see if the notification can
354 // display the target to forward calls to. This will require some
355 // effort though, since there are multiple layers of messages that
356 // will need to propagate that information.
357
Andrew Lee99d0ac22014-10-10 13:18:04 -0700358 Notification.Builder builder = new Notification.Builder(mContext)
359 .setSmallIcon(R.drawable.stat_sys_phone_call_forward)
360 .setContentTitle(mContext.getString(R.string.labelCF))
361 .setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
362 .setShowWhen(false)
363 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700364
Andrew Lee99d0ac22014-10-10 13:18:04 -0700365 Intent intent = new Intent(Intent.ACTION_MAIN);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800366 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700367 intent.setClassName("com.android.phone", "com.android.phone.CallFeaturesSetting");
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800368 SubscriptionInfoHelper.addExtrasToIntent(
369 intent, mSubscriptionManager.getActiveSubscriptionInfo(subId));
370 PendingIntent contentIntent =
371 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700372
373 List<UserInfo> users = mUserManager.getUsers(true);
374 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800375 final UserInfo user = users.get(i);
376 if (user.isManagedProfile()) {
377 continue;
378 }
379 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700380 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800381 mNotificationManager.notifyAsUser(
382 Integer.toString(subId) /* tag */,
383 CALL_FORWARD_NOTIFICATION,
384 builder.build(),
385 userHandle);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700386 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700387 } else {
Andrew Lee99d0ac22014-10-10 13:18:04 -0700388 mNotificationManager.cancelAsUser(
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800389 Integer.toString(subId) /* tag */,
390 CALL_FORWARD_NOTIFICATION,
391 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700392 }
393 }
394
395 /**
396 * Shows the "data disconnected due to roaming" notification, which
397 * appears when you lose data connectivity because you're roaming and
398 * you have the "data roaming" feature turned off.
399 */
400 /* package */ void showDataDisconnectedRoaming() {
401 if (DBG) log("showDataDisconnectedRoaming()...");
402
403 // "Mobile network settings" screen / dialog
404 Intent intent = new Intent(mContext, com.android.phone.MobileNetworkSettings.class);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700405 PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700406
407 final CharSequence contentText = mContext.getText(R.string.roaming_reenable_message);
408
Andrew Lee99d0ac22014-10-10 13:18:04 -0700409 final Notification.Builder builder = new Notification.Builder(mContext)
410 .setSmallIcon(android.R.drawable.stat_sys_warning)
411 .setContentTitle(mContext.getText(R.string.roaming))
412 .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
413 .setContentText(contentText);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700414
Andrew Lee99d0ac22014-10-10 13:18:04 -0700415 List<UserInfo> users = mUserManager.getUsers(true);
416 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800417 final UserInfo user = users.get(i);
418 if (user.isManagedProfile()) {
419 continue;
420 }
421 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700422 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
423 final Notification notif =
424 new Notification.BigTextStyle(builder).bigText(contentText).build();
425 mNotificationManager.notifyAsUser(
426 null /* tag */, DATA_DISCONNECTED_ROAMING_NOTIFICATION, notif, userHandle);
427 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700428 }
429
430 /**
431 * Turns off the "data disconnected due to roaming" notification.
432 */
433 /* package */ void hideDataDisconnectedRoaming() {
434 if (DBG) log("hideDataDisconnectedRoaming()...");
435 mNotificationManager.cancel(DATA_DISCONNECTED_ROAMING_NOTIFICATION);
436 }
437
438 /**
439 * Display the network selection "no service" notification
440 * @param operator is the numeric operator number
441 */
442 private void showNetworkSelection(String operator) {
443 if (DBG) log("showNetworkSelection(" + operator + ")...");
444
Andrew Lee99d0ac22014-10-10 13:18:04 -0700445 Notification.Builder builder = new Notification.Builder(mContext)
446 .setSmallIcon(android.R.drawable.stat_sys_warning)
447 .setContentTitle(mContext.getString(R.string.notification_network_selection_title))
448 .setContentText(
449 mContext.getString(R.string.notification_network_selection_text, operator))
450 .setShowWhen(false)
451 .setOngoing(true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700452
453 // create the target network operators settings intent
454 Intent intent = new Intent(Intent.ACTION_MAIN);
455 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
456 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
457 // Use NetworkSetting to handle the selection intent
458 intent.setComponent(new ComponentName("com.android.phone",
459 "com.android.phone.NetworkSetting"));
Andrew Lee99d0ac22014-10-10 13:18:04 -0700460 PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700461
Andrew Lee99d0ac22014-10-10 13:18:04 -0700462 List<UserInfo> users = mUserManager.getUsers(true);
463 for (int i = 0; i < users.size(); i++) {
Yorke Lee3faa5942014-11-05 16:50:04 -0800464 final UserInfo user = users.get(i);
465 if (user.isManagedProfile()) {
466 continue;
467 }
468 UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700469 builder.setContentIntent(userHandle.isOwner() ? contentIntent : null);
470 mNotificationManager.notifyAsUser(
471 null /* tag */,
472 SELECTED_OPERATOR_FAIL_NOTIFICATION,
473 builder.build(),
474 userHandle);
475 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700476 }
477
478 /**
479 * Turn off the network selection "no service" notification
480 */
481 private void cancelNetworkSelection() {
482 if (DBG) log("cancelNetworkSelection()...");
Andrew Lee99d0ac22014-10-10 13:18:04 -0700483 mNotificationManager.cancelAsUser(
484 null /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION, UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700485 }
486
487 /**
488 * Update notification about no service of user selected operator
489 *
490 * @param serviceState Phone service state
491 */
492 void updateNetworkSelection(int serviceState) {
493 if (TelephonyCapabilities.supportsNetworkSelection(mPhone)) {
494 // get the shared preference of network_selection.
495 // empty is auto mode, otherwise it is the operator alpha name
496 // in case there is no operator name, check the operator numeric
497 SharedPreferences sp =
498 PreferenceManager.getDefaultSharedPreferences(mContext);
499 String networkSelection =
500 sp.getString(PhoneBase.NETWORK_SELECTION_NAME_KEY, "");
501 if (TextUtils.isEmpty(networkSelection)) {
502 networkSelection =
503 sp.getString(PhoneBase.NETWORK_SELECTION_KEY, "");
504 }
505
506 if (DBG) log("updateNetworkSelection()..." + "state = " +
507 serviceState + " new network " + networkSelection);
508
509 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
510 && !TextUtils.isEmpty(networkSelection)) {
511 if (!mSelectedUnavailableNotify) {
512 showNetworkSelection(networkSelection);
513 mSelectedUnavailableNotify = true;
514 }
515 } else {
516 if (mSelectedUnavailableNotify) {
517 cancelNetworkSelection();
518 mSelectedUnavailableNotify = false;
519 }
520 }
521 }
522 }
523
524 /* package */ void postTransientNotification(int notifyId, CharSequence msg) {
525 if (mToast != null) {
526 mToast.cancel();
527 }
528
529 mToast = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
530 mToast.show();
531 }
532
533 private void log(String msg) {
534 Log.d(LOG_TAG, msg);
535 }
536}