blob: ca99f98de9c0b2aea480608b90bbbc2afc97a6e6 [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
Ta-wei Yenafca2d62017-07-18 17:20:59 -070019import static android.Manifest.permission.READ_PHONE_STATE;
20
Santos Cordon7d4ddf62013-07-10 11:58:08 -070021import android.app.Notification;
22import android.app.NotificationManager;
23import android.app.PendingIntent;
24import android.app.StatusBarManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070025import android.content.ComponentName;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070026import android.content.Context;
27import android.content.Intent;
28import android.content.SharedPreferences;
Ta-wei Yen5bb19562016-11-16 11:05:37 -080029import android.content.pm.ResolveInfo;
Andrew Lee99d0ac22014-10-10 13:18:04 -070030import android.content.pm.UserInfo;
Nancy Chenb4a92702014-12-04 15:57:29 -080031import android.content.res.Resources;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070032import android.net.Uri;
irisykyang25202462018-11-13 14:49:54 +080033import android.os.Handler;
34import android.os.Message;
Jonathan Basseric31f1f32015-05-12 10:13:03 -070035import android.os.PersistableBundle;
irisykyang25202462018-11-13 14:49:54 +080036import android.os.SystemClock;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070037import android.os.SystemProperties;
Andrew Lee99d0ac22014-10-10 13:18:04 -070038import android.os.UserHandle;
39import android.os.UserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070040import android.preference.PreferenceManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070041import android.provider.ContactsContract.PhoneLookup;
Jeff Davidson6d9bf522017-11-03 14:51:13 -070042import android.provider.Settings;
Ta-wei Yen5bb19562016-11-16 11:05:37 -080043import android.telecom.DefaultDialerManager;
Tyler Gunn4d45d1c2014-09-12 22:17:53 -070044import android.telecom.PhoneAccount;
Andrew Leed5165b02014-12-05 15:53:58 -080045import android.telecom.PhoneAccountHandle;
46import android.telecom.TelecomManager;
Jonathan Basseri3649bdb2015-04-30 22:39:11 -070047import android.telephony.CarrierConfigManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070048import android.telephony.PhoneNumberUtils;
49import android.telephony.ServiceState;
Andrew Lee2fcb6c32014-12-04 14:52:35 -080050import android.telephony.SubscriptionInfo;
Andrew Leea82b8202014-11-21 16:18:28 -080051import android.telephony.SubscriptionManager;
Andrew Leed5165b02014-12-05 15:53:58 -080052import android.telephony.TelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070053import android.text.TextUtils;
Tyler Gunn9c1071f2014-12-09 10:07:54 -080054import android.util.ArrayMap;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070055import android.util.Log;
irisykyang25202462018-11-13 14:49:54 +080056import android.util.SparseArray;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070057import android.widget.Toast;
Ta-wei Yenb29425b2016-09-21 17:28:14 -070058
Santos Cordon7d4ddf62013-07-10 11:58:08 -070059import com.android.internal.telephony.Phone;
Jayachandran C2ef9a482017-05-12 22:07:47 -070060import com.android.internal.telephony.PhoneFactory;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070061import com.android.internal.telephony.TelephonyCapabilities;
fionaxu8b7620d2017-05-01 16:22:17 -070062import com.android.internal.telephony.util.NotificationChannelController;
Andrew Leebf07f762015-04-07 19:05:50 -070063import com.android.phone.settings.VoicemailSettingsActivity;
Ta-wei Yenb29425b2016-09-21 17:28:14 -070064
Tyler Gunn9c1071f2014-12-09 10:07:54 -080065import java.util.Iterator;
Andrew Lee99d0ac22014-10-10 13:18:04 -070066import java.util.List;
Tyler Gunn9c1071f2014-12-09 10:07:54 -080067import java.util.Set;
Andrew Lee99d0ac22014-10-10 13:18:04 -070068
Santos Cordon7d4ddf62013-07-10 11:58:08 -070069/**
70 * NotificationManager-related utility code for the Phone app.
71 *
72 * This is a singleton object which acts as the interface to the
73 * framework's NotificationManager, and is used to display status bar
74 * icons and control other status bar-related behavior.
75 *
76 * @see PhoneGlobals.notificationMgr
77 */
Chiao Cheng312b9c92013-09-16 15:40:53 -070078public class NotificationMgr {
Andrew Leea82b8202014-11-21 16:18:28 -080079 private static final String LOG_TAG = NotificationMgr.class.getSimpleName();
Santos Cordon7d4ddf62013-07-10 11:58:08 -070080 private static final boolean DBG =
81 (PhoneGlobals.DBG_LEVEL >= 1) && (SystemProperties.getInt("ro.debuggable", 0) == 1);
82 // Do not check in with VDBG = true, since that may write PII to the system log.
83 private static final boolean VDBG = false;
84
Ta-wei Yenb29425b2016-09-21 17:28:14 -070085 private static final String MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX =
86 "mwi_should_check_vvm_configuration_state_";
87
Santos Cordon7d4ddf62013-07-10 11:58:08 -070088 // notification types
Santos Cordonf68db2e2014-07-02 14:40:44 -070089 static final int MMI_NOTIFICATION = 1;
90 static final int NETWORK_SELECTION_NOTIFICATION = 2;
91 static final int VOICEMAIL_NOTIFICATION = 3;
92 static final int CALL_FORWARD_NOTIFICATION = 4;
93 static final int DATA_DISCONNECTED_ROAMING_NOTIFICATION = 5;
94 static final int SELECTED_OPERATOR_FAIL_NOTIFICATION = 6;
Santos Cordon7d4ddf62013-07-10 11:58:08 -070095
irisykyang25202462018-11-13 14:49:54 +080096 // Event for network selection notification.
97 private static final int EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION = 1;
98
99 private static final long NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS = 10000L;
100 private static final int NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES = 10;
101
102 private static final int STATE_UNKNOWN_SERVICE = -1;
103
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700104 /** The singleton NotificationMgr instance. */
105 private static NotificationMgr sInstance;
106
107 private PhoneGlobals mApp;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700108
109 private Context mContext;
110 private NotificationManager mNotificationManager;
111 private StatusBarManager mStatusBarManager;
Andrew Lee99d0ac22014-10-10 13:18:04 -0700112 private UserManager mUserManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700113 private Toast mToast;
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800114 private SubscriptionManager mSubscriptionManager;
Andrew Leed5165b02014-12-05 15:53:58 -0800115 private TelecomManager mTelecomManager;
116 private TelephonyManager mTelephonyManager;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700117
irisykyang25202462018-11-13 14:49:54 +0800118 // used to track the notification of selected network unavailable, per subscription id.
119 private SparseArray<Boolean> mSelectedUnavailableNotify = new SparseArray<>();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700120
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800121 // used to track whether the message waiting indicator is visible, per subscription id.
122 private ArrayMap<Integer, Boolean> mMwiVisible = new ArrayMap<Integer, Boolean>();
123
irisykyang25202462018-11-13 14:49:54 +0800124 // those flags are used to track whether to show network selection notification or not.
125 private SparseArray<Integer> mPreviousServiceState = new SparseArray<>();
126 private SparseArray<Long> mOOSTimestamp = new SparseArray<>();
127 private SparseArray<Integer> mPendingEventCounter = new SparseArray<>();
128 // maps each subId to selected network operator name.
129 private SparseArray<String> mSelectedNetworkOperatorName = new SparseArray<>();
130
131 private final Handler mHandler = new Handler() {
132 @Override
133 public void handleMessage(Message msg) {
134 switch (msg.what) {
135 case EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION:
136 int subId = (int) msg.obj;
137 TelephonyManager telephonyManager =
138 mTelephonyManager.createForSubscriptionId(subId);
139 if (telephonyManager.getServiceState() != null) {
140 shouldShowNotification(telephonyManager.getServiceState().getState(),
141 subId);
142 }
143 break;
144 }
145 }
146 };
147
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700148 /**
149 * Private constructor (this is a singleton).
Santos Cordonf68db2e2014-07-02 14:40:44 -0700150 * @see #init(PhoneGlobals)
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700151 */
152 private NotificationMgr(PhoneGlobals app) {
153 mApp = app;
154 mContext = app;
155 mNotificationManager =
156 (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
157 mStatusBarManager =
158 (StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700159 mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800160 mSubscriptionManager = SubscriptionManager.from(mContext);
Andrew Leed5165b02014-12-05 15:53:58 -0800161 mTelecomManager = TelecomManager.from(mContext);
162 mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700163 }
164
165 /**
166 * Initialize the singleton NotificationMgr instance.
167 *
168 * This is only done once, at startup, from PhoneApp.onCreate().
169 * From then on, the NotificationMgr instance is available via the
170 * PhoneApp's public "notificationMgr" field, which is why there's no
171 * getInstance() method here.
172 */
173 /* package */ static NotificationMgr init(PhoneGlobals app) {
174 synchronized (NotificationMgr.class) {
175 if (sInstance == null) {
176 sInstance = new NotificationMgr(app);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700177 } else {
178 Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance);
179 }
180 return sInstance;
181 }
182 }
183
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700184 /** The projection to use when querying the phones table */
185 static final String[] PHONES_PROJECTION = new String[] {
186 PhoneLookup.NUMBER,
187 PhoneLookup.DISPLAY_NAME,
188 PhoneLookup._ID
189 };
190
191 /**
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800192 * Re-creates the message waiting indicator (voicemail) notification if it is showing. Used to
193 * refresh the voicemail intent on the indicator when the user changes it via the voicemail
194 * settings screen. The voicemail notification sound is suppressed.
195 *
196 * @param subId The subscription Id.
197 */
198 /* package */ void refreshMwi(int subId) {
199 // In a single-sim device, subId can be -1 which means "no sub id". In this case we will
200 // reference the single subid stored in the mMwiVisible map.
Ta-wei Yena1390d42017-12-04 15:11:33 -0800201 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800202 if (mMwiVisible.keySet().size() == 1) {
203 Set<Integer> keySet = mMwiVisible.keySet();
204 Iterator<Integer> keyIt = keySet.iterator();
205 if (!keyIt.hasNext()) {
206 return;
207 }
208 subId = keyIt.next();
209 }
210 }
211 if (mMwiVisible.containsKey(subId)) {
212 boolean mwiVisible = mMwiVisible.get(subId);
213 if (mwiVisible) {
Kazuya Ohshiro263737d2017-10-06 19:42:03 +0900214 mApp.notifier.updatePhoneStateListeners(true);
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800215 }
216 }
217 }
218
Ta-wei Yenb29425b2016-09-21 17:28:14 -0700219 public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
220 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
221 Log.e(LOG_TAG, "setShouldCheckVisualVoicemailConfigurationForMwi: invalid subId"
222 + subId);
223 return;
224 }
225
226 PreferenceManager.getDefaultSharedPreferences(mContext).edit()
227 .putBoolean(MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX + subId, enabled)
228 .apply();
229 }
230
231 private boolean shouldCheckVisualVoicemailConfigurationForMwi(int subId) {
232 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
233 Log.e(LOG_TAG, "shouldCheckVisualVoicemailConfigurationForMwi: invalid subId" + subId);
234 return true;
235 }
236 return PreferenceManager
237 .getDefaultSharedPreferences(mContext)
238 .getBoolean(MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX + subId, true);
239 }
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800240 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700241 * Updates the message waiting indicator (voicemail) notification.
242 *
243 * @param visible true if there are messages waiting
244 */
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800245 /* package */ void updateMwi(int subId, boolean visible) {
Ta-wei Yen282a9702017-05-30 17:32:29 -0700246 updateMwi(subId, visible, false /* isRefresh */);
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800247 }
248
249 /**
250 * Updates the message waiting indicator (voicemail) notification.
251 *
252 * @param subId the subId to update.
253 * @param visible true if there are messages waiting
Ta-wei Yen282a9702017-05-30 17:32:29 -0700254 * @param isRefresh {@code true} if the notification is a refresh and the user should not be
255 * notified again.
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800256 */
Ta-wei Yen282a9702017-05-30 17:32:29 -0700257 void updateMwi(int subId, boolean visible, boolean isRefresh) {
Andrew Leea82b8202014-11-21 16:18:28 -0800258 if (!PhoneGlobals.sVoiceCapable) {
259 // Do not show the message waiting indicator on devices which are not voice capable.
260 // These events *should* be blocked at the telephony layer for such devices.
261 Log.w(LOG_TAG, "Called updateMwi() on non-voice-capable device! Ignoring...");
262 return;
263 }
264
Nancy Chen2cf7f292015-05-15 11:00:10 -0700265 Phone phone = PhoneGlobals.getPhone(subId);
Yorke Lee67a62a22014-12-15 18:46:17 -0800266 Log.i(LOG_TAG, "updateMwi(): subId " + subId + " update to " + visible);
Andrew Leef8ad78f2014-12-15 16:17:29 -0800267 mMwiVisible.put(subId, visible);
268
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700269 if (visible) {
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800270 if (phone == null) {
Andrew Leed5165b02014-12-05 15:53:58 -0800271 Log.w(LOG_TAG, "Found null phone for: " + subId);
272 return;
273 }
274
275 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
276 if (subInfo == null) {
277 Log.w(LOG_TAG, "Found null subscription info for: " + subId);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800278 return;
279 }
280
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700281 int resId = android.R.drawable.stat_notify_voicemail;
Kazuya Ohshiro263737d2017-10-06 19:42:03 +0900282 if (mTelephonyManager.getPhoneCount() > 1) {
283 resId = (phone.getPhoneId() == 0) ? R.drawable.stat_notify_voicemail_sub1
284 : R.drawable.stat_notify_voicemail_sub2;
285 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700286
287 // This Notification can get a lot fancier once we have more
288 // information about the current voicemail messages.
289 // (For example, the current voicemail system can't tell
290 // us the caller-id or timestamp of a message, or tell us the
291 // message count.)
292
293 // But for now, the UI is ultra-simple: if the MWI indication
294 // is supposed to be visible, just show a single generic
295 // notification.
296
297 String notificationTitle = mContext.getString(R.string.notification_voicemail_title);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800298 String vmNumber = phone.getVoiceMailNumber();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700299 if (DBG) log("- got vm number: '" + vmNumber + "'");
300
Andrew Leea82b8202014-11-21 16:18:28 -0800301 // The voicemail number may be null because:
302 // (1) This phone has no voicemail number.
303 // (2) This phone has a voicemail number, but the SIM isn't ready yet. This may
304 // happen when the device first boots if we get a MWI notification when we
305 // register on the network before the SIM has loaded. In this case, the
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800306 // SubscriptionListener in CallNotifier will update this once the SIM is loaded.
307 if ((vmNumber == null) && !phone.getIccRecordsLoaded()) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700308 if (DBG) log("- Null vm number: SIM records not loaded (yet)...");
Andrew Leea82b8202014-11-21 16:18:28 -0800309 return;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700310 }
311
Bryce Lee5dc90842015-08-11 07:57:14 -0700312 Integer vmCount = null;
313
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800314 if (TelephonyCapabilities.supportsVoiceMessageCount(phone)) {
Bryce Lee5dc90842015-08-11 07:57:14 -0700315 vmCount = phone.getVoiceMessageCount();
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700316 String titleFormat = mContext.getString(R.string.notification_voicemail_title_count);
317 notificationTitle = String.format(titleFormat, vmCount);
318 }
319
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800320 // This pathway only applies to PSTN accounts; only SIMS have subscription ids.
321 PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(phone);
322
323 Intent intent;
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700324 String notificationText;
Bryce Lee5dc90842015-08-11 07:57:14 -0700325 boolean isSettingsIntent = TextUtils.isEmpty(vmNumber);
326
327 if (isSettingsIntent) {
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800328 notificationText = mContext.getString(
329 R.string.notification_voicemail_no_vm_number);
330
331 // If the voicemail number if unknown, instead of calling voicemail, take the user
332 // to the voicemail settings.
333 notificationText = mContext.getString(
334 R.string.notification_voicemail_no_vm_number);
Andrew Leebf07f762015-04-07 19:05:50 -0700335 intent = new Intent(VoicemailSettingsActivity.ACTION_ADD_VOICEMAIL);
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800336 intent.putExtra(SubscriptionInfoHelper.SUB_ID_EXTRA, subId);
Andrew Leebf07f762015-04-07 19:05:50 -0700337 intent.setClass(mContext, VoicemailSettingsActivity.class);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700338 } else {
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800339 if (mTelephonyManager.getPhoneCount() > 1) {
340 notificationText = subInfo.getDisplayName().toString();
Andrew Leed5165b02014-12-05 15:53:58 -0800341 } else {
342 notificationText = String.format(
343 mContext.getString(R.string.notification_voicemail_text_format),
344 PhoneNumberUtils.formatNumber(vmNumber));
345 }
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800346 intent = new Intent(
347 Intent.ACTION_CALL, Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "",
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700348 null));
Tyler Gunn9c1071f2014-12-09 10:07:54 -0800349 intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700350 }
351
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800352 PendingIntent pendingIntent =
353 PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700354
Nancy Chenb4a92702014-12-04 15:57:29 -0800355 Resources res = mContext.getResources();
Jonathan Basseric31f1f32015-05-12 10:13:03 -0700356 PersistableBundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(
Ta-wei Yen9b37a872016-05-27 12:16:58 -0700357 subId);
fionaxu8b7620d2017-05-01 16:22:17 -0700358 Notification.Builder builder = new Notification.Builder(mContext);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700359 builder.setSmallIcon(resId)
360 .setWhen(System.currentTimeMillis())
Andrew Leed5165b02014-12-05 15:53:58 -0800361 .setColor(subInfo.getIconTint())
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700362 .setContentTitle(notificationTitle)
363 .setContentText(notificationText)
364 .setContentIntent(pendingIntent)
Nancy Chenb4a92702014-12-04 15:57:29 -0800365 .setColor(res.getColor(R.color.dialer_theme_color))
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700366 .setOngoing(carrierConfig.getBoolean(
fionaxu75b66a72017-04-19 19:01:56 -0700367 CarrierConfigManager.KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL))
Jordan Liu575c0d02019-07-09 16:29:48 -0700368 .setChannelId(NotificationChannelController.CHANNEL_ID_VOICE_MAIL)
Ta-wei Yen282a9702017-05-30 17:32:29 -0700369 .setOnlyAlertOnce(isRefresh);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700370
Andrew Lee99d0ac22014-10-10 13:18:04 -0700371 final Notification notification = builder.build();
372 List<UserInfo> users = mUserManager.getUsers(true);
373 for (int i = 0; i < users.size(); i++) {
Yorke Lee047b1f92014-10-24 10:22:41 -0700374 final UserInfo user = users.get(i);
375 final UserHandle userHandle = user.getUserHandle();
Andrew Lee99d0ac22014-10-10 13:18:04 -0700376 if (!mUserManager.hasUserRestriction(
Yorke Lee047b1f92014-10-24 10:22:41 -0700377 UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
Jonathan Basseri3649bdb2015-04-30 22:39:11 -0700378 && !user.isManagedProfile()) {
Ta-wei Yena71a38b2017-02-24 18:19:27 -0800379 if (!maybeSendVoicemailNotificationUsingDefaultDialer(phone, vmCount, vmNumber,
Ta-wei Yen282a9702017-05-30 17:32:29 -0700380 pendingIntent, isSettingsIntent, userHandle, isRefresh)) {
Bryce Lee5dc90842015-08-11 07:57:14 -0700381 mNotificationManager.notifyAsUser(
382 Integer.toString(subId) /* tag */,
383 VOICEMAIL_NOTIFICATION,
384 notification,
385 userHandle);
386 }
Andrew Lee99d0ac22014-10-10 13:18:04 -0700387 }
388 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700389 } else {
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800390 List<UserInfo> users = mUserManager.getUsers(true /* excludeDying */);
391 for (int i = 0; i < users.size(); i++) {
392 final UserInfo user = users.get(i);
393 final UserHandle userHandle = user.getUserHandle();
394 if (!mUserManager.hasUserRestriction(
395 UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
396 && !user.isManagedProfile()) {
Ta-wei Yena71a38b2017-02-24 18:19:27 -0800397 if (!maybeSendVoicemailNotificationUsingDefaultDialer(phone, 0, null, null,
Ta-wei Yen282a9702017-05-30 17:32:29 -0700398 false, userHandle, isRefresh)) {
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800399 mNotificationManager.cancelAsUser(
400 Integer.toString(subId) /* tag */,
401 VOICEMAIL_NOTIFICATION,
402 userHandle);
403 }
404 }
Bryce Lee5dc90842015-08-11 07:57:14 -0700405 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700406 }
407 }
408
409 /**
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800410 * Sends a broadcast with the voicemail notification information to the default dialer. This
411 * method is also used to indicate to the default dialer when to clear the
412 * notification. A pending intent can be passed to the default dialer to indicate an action to
Bryce Lee5dc90842015-08-11 07:57:14 -0700413 * be taken as it would by a notification produced in this class.
Ta-wei Yena71a38b2017-02-24 18:19:27 -0800414 * @param phone The phone the notification is sent from
Bryce Lee5dc90842015-08-11 07:57:14 -0700415 * @param count The number of pending voicemail messages to indicate on the notification. A
416 * Value of 0 is passed here to indicate that the notification should be cleared.
417 * @param number The voicemail phone number if specified.
418 * @param pendingIntent The intent that should be passed as the action to be taken.
419 * @param isSettingsIntent {@code true} to indicate the pending intent is to launch settings.
420 * otherwise, {@code false} to indicate the intent launches voicemail.
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800421 * @param userHandle The user to receive the notification. Each user can have their own default
422 * dialer.
423 * @return {@code true} if the default was notified of the notification.
Bryce Lee5dc90842015-08-11 07:57:14 -0700424 */
Ta-wei Yena71a38b2017-02-24 18:19:27 -0800425 private boolean maybeSendVoicemailNotificationUsingDefaultDialer(Phone phone, Integer count,
426 String number, PendingIntent pendingIntent, boolean isSettingsIntent,
Ta-wei Yen282a9702017-05-30 17:32:29 -0700427 UserHandle userHandle, boolean isRefresh) {
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800428
429 if (shouldManageNotificationThroughDefaultDialer(userHandle)) {
430 Intent intent = getShowVoicemailIntentForDefaultDialer(userHandle);
Bryce Lee5dc90842015-08-11 07:57:14 -0700431 intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Bryce Lee5dc90842015-08-11 07:57:14 -0700432 intent.setAction(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION);
Ta-wei Yena71a38b2017-02-24 18:19:27 -0800433 intent.putExtra(TelephonyManager.EXTRA_PHONE_ACCOUNT_HANDLE,
434 PhoneUtils.makePstnPhoneAccountHandle(phone));
Ta-wei Yenafca2d62017-07-18 17:20:59 -0700435 intent.putExtra(TelephonyManager.EXTRA_IS_REFRESH, isRefresh);
Bryce Lee5dc90842015-08-11 07:57:14 -0700436 if (count != null) {
437 intent.putExtra(TelephonyManager.EXTRA_NOTIFICATION_COUNT, count);
438 }
439
440 // Additional information about the voicemail notification beyond the count is only
441 // present when the count not specified or greater than 0. The value of 0 represents
442 // clearing the notification, which does not require additional information.
443 if (count == null || count > 0) {
444 if (!TextUtils.isEmpty(number)) {
445 intent.putExtra(TelephonyManager.EXTRA_VOICEMAIL_NUMBER, number);
446 }
447
448 if (pendingIntent != null) {
449 intent.putExtra(isSettingsIntent
450 ? TelephonyManager.EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT
451 : TelephonyManager.EXTRA_CALL_VOICEMAIL_INTENT,
452 pendingIntent);
453 }
454 }
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800455 mContext.sendBroadcastAsUser(intent, userHandle, READ_PHONE_STATE);
Bryce Lee5dc90842015-08-11 07:57:14 -0700456 return true;
457 }
458
459 return false;
460 }
461
Ta-wei Yen5bb19562016-11-16 11:05:37 -0800462 private Intent getShowVoicemailIntentForDefaultDialer(UserHandle userHandle) {
463 String dialerPackage = DefaultDialerManager
464 .getDefaultDialerApplication(mContext, userHandle.getIdentifier());
465 return new Intent(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION)
466 .setPackage(dialerPackage);
467 }
468
469 private boolean shouldManageNotificationThroughDefaultDialer(UserHandle userHandle) {
470 Intent intent = getShowVoicemailIntentForDefaultDialer(userHandle);
471 if (intent == null) {
472 return false;
473 }
474
475 List<ResolveInfo> receivers = mContext.getPackageManager()
476 .queryBroadcastReceivers(intent, 0);
477 return receivers.size() > 0;
478 }
479
Bryce Lee5dc90842015-08-11 07:57:14 -0700480 /**
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700481 * Updates the message call forwarding indicator notification.
482 *
Srikanth Chintala4baf0b92017-11-14 15:52:47 +0530483 * @param visible true if call forwarding enabled
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700484 */
Srikanth Chintala4baf0b92017-11-14 15:52:47 +0530485
486 /* package */ void updateCfi(int subId, boolean visible) {
487 updateCfi(subId, visible, false /* isRefresh */);
488 }
489
490 /**
491 * Updates the message call forwarding indicator notification.
492 *
493 * @param visible true if call forwarding enabled
494 */
495 /* package */ void updateCfi(int subId, boolean visible, boolean isRefresh) {
Tyler Gunna584e2c2017-09-19 11:40:12 -0700496 logi("updateCfi: subId= " + subId + ", visible=" + (visible ? "Y" : "N"));
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700497 if (visible) {
498 // If Unconditional Call Forwarding (forward all calls) for VOICE
499 // is enabled, just show a notification. We'll default to expanded
500 // view for now, so the there is less confusion about the icon. If
501 // it is deemed too weird to have CF indications as expanded views,
502 // then we'll flip the flag back.
503
504 // TODO: We may want to take a look to see if the notification can
505 // display the target to forward calls to. This will require some
506 // effort though, since there are multiple layers of messages that
507 // will need to propagate that information.
508
Andrew Leed5165b02014-12-05 15:53:58 -0800509 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
510 if (subInfo == null) {
511 Log.w(LOG_TAG, "Found null subscription info for: " + subId);
512 return;
513 }
514
515 String notificationTitle;
Kazuya Ohshiro263737d2017-10-06 19:42:03 +0900516 int resId = R.drawable.stat_sys_phone_call_forward;
Andrew Leed5165b02014-12-05 15:53:58 -0800517 if (mTelephonyManager.getPhoneCount() > 1) {
Kazuya Ohshiro263737d2017-10-06 19:42:03 +0900518 int slotId = SubscriptionManager.getSlotIndex(subId);
519 resId = (slotId == 0) ? R.drawable.stat_sys_phone_call_forward_sub1
520 : R.drawable.stat_sys_phone_call_forward_sub2;
Andrew Leed5165b02014-12-05 15:53:58 -0800521 notificationTitle = subInfo.getDisplayName().toString();
522 } else {
523 notificationTitle = mContext.getString(R.string.labelCF);
524 }
525
fionaxu8b7620d2017-05-01 16:22:17 -0700526 Notification.Builder builder = new Notification.Builder(mContext)
Kazuya Ohshiro263737d2017-10-06 19:42:03 +0900527 .setSmallIcon(resId)
Andrew Leed5165b02014-12-05 15:53:58 -0800528 .setColor(subInfo.getIconTint())
529 .setContentTitle(notificationTitle)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700530 .setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
531 .setShowWhen(false)
fionaxu75b66a72017-04-19 19:01:56 -0700532 .setOngoing(true)
Jordan Liu575c0d02019-07-09 16:29:48 -0700533 .setChannelId(NotificationChannelController.CHANNEL_ID_CALL_FORWARD)
Srikanth Chintala4baf0b92017-11-14 15:52:47 +0530534 .setOnlyAlertOnce(isRefresh);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700535
Andrew Lee99d0ac22014-10-10 13:18:04 -0700536 Intent intent = new Intent(Intent.ACTION_MAIN);
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800537 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Andrew Lee99d0ac22014-10-10 13:18:04 -0700538 intent.setClassName("com.android.phone", "com.android.phone.CallFeaturesSetting");
Andrew Lee2fcb6c32014-12-04 14:52:35 -0800539 SubscriptionInfoHelper.addExtrasToIntent(
540 intent, mSubscriptionManager.getActiveSubscriptionInfo(subId));
fionaxu96ceebd2017-08-24 12:12:32 -0700541 builder.setContentIntent(PendingIntent.getActivity(mContext, subId /* requestCode */,
542 intent, 0));
543 mNotificationManager.notifyAsUser(
544 Integer.toString(subId) /* tag */,
545 CALL_FORWARD_NOTIFICATION,
546 builder.build(),
547 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700548 } else {
Kazuya Ohshiro263737d2017-10-06 19:42:03 +0900549 List<UserInfo> users = mUserManager.getUsers(true);
550 for (UserInfo user : users) {
551 if (user.isManagedProfile()) {
552 continue;
553 }
554 UserHandle userHandle = user.getUserHandle();
555 mNotificationManager.cancelAsUser(
556 Integer.toString(subId) /* tag */,
557 CALL_FORWARD_NOTIFICATION,
558 userHandle);
559 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700560 }
561 }
562
563 /**
564 * Shows the "data disconnected due to roaming" notification, which
565 * appears when you lose data connectivity because you're roaming and
Pengquan Meng8783d932017-10-16 14:57:40 -0700566 * you have the "data roaming" feature turned off for the given {@code subId}.
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700567 */
Pengquan Meng8783d932017-10-16 14:57:40 -0700568 /* package */ void showDataDisconnectedRoaming(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700569 if (DBG) log("showDataDisconnectedRoaming()...");
570
571 // "Mobile network settings" screen / dialog
Nazanin Bakhshi682c77d2019-05-02 17:22:27 -0700572 Intent intent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
Jeff Davidson6d9bf522017-11-03 14:51:13 -0700573 intent.putExtra(Settings.EXTRA_SUB_ID, subId);
Pengquan Meng8783d932017-10-16 14:57:40 -0700574 PendingIntent contentIntent = PendingIntent.getActivity(mContext, subId, intent, 0);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700575
576 final CharSequence contentText = mContext.getText(R.string.roaming_reenable_message);
577
fionaxu8b7620d2017-05-01 16:22:17 -0700578 final Notification.Builder builder = new Notification.Builder(mContext)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700579 .setSmallIcon(android.R.drawable.stat_sys_warning)
fionaxuba6bdef2018-03-13 14:18:34 -0700580 .setContentTitle(mContext.getText(R.string.roaming_notification_title))
Andrew Lee99d0ac22014-10-10 13:18:04 -0700581 .setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
fionaxu75b66a72017-04-19 19:01:56 -0700582 .setContentText(contentText)
Jordan Liu575c0d02019-07-09 16:29:48 -0700583 .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS)
fionaxu96ceebd2017-08-24 12:12:32 -0700584 .setContentIntent(contentIntent);
585 final Notification notif =
586 new Notification.BigTextStyle(builder).bigText(contentText).build();
587 mNotificationManager.notifyAsUser(
588 null /* tag */, DATA_DISCONNECTED_ROAMING_NOTIFICATION, notif, UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700589 }
590
591 /**
592 * Turns off the "data disconnected due to roaming" notification.
593 */
594 /* package */ void hideDataDisconnectedRoaming() {
595 if (DBG) log("hideDataDisconnectedRoaming()...");
596 mNotificationManager.cancel(DATA_DISCONNECTED_ROAMING_NOTIFICATION);
597 }
598
599 /**
600 * Display the network selection "no service" notification
601 * @param operator is the numeric operator number
Jayachandran C2ef9a482017-05-12 22:07:47 -0700602 * @param subId is the subscription ID
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700603 */
Jayachandran C2ef9a482017-05-12 22:07:47 -0700604 private void showNetworkSelection(String operator, int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700605 if (DBG) log("showNetworkSelection(" + operator + ")...");
606
Youming Ye0509b532018-09-14 16:21:17 -0700607 if (!TextUtils.isEmpty(operator)) {
608 operator = String.format(" (%s)", operator);
609 }
fionaxu8b7620d2017-05-01 16:22:17 -0700610 Notification.Builder builder = new Notification.Builder(mContext)
Andrew Lee99d0ac22014-10-10 13:18:04 -0700611 .setSmallIcon(android.R.drawable.stat_sys_warning)
612 .setContentTitle(mContext.getString(R.string.notification_network_selection_title))
613 .setContentText(
614 mContext.getString(R.string.notification_network_selection_text, operator))
615 .setShowWhen(false)
fionaxu75b66a72017-04-19 19:01:56 -0700616 .setOngoing(true)
Jordan Liu575c0d02019-07-09 16:29:48 -0700617 .setChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700618
619 // create the target network operators settings intent
620 Intent intent = new Intent(Intent.ACTION_MAIN);
621 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
622 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Malcolm Chen34d4fa52017-06-05 19:02:16 -0700623 // Use MobileNetworkSettings to handle the selection intent
Wei Liube964582015-08-21 11:57:00 -0700624 intent.setComponent(new ComponentName(
Malcolm Chen34d4fa52017-06-05 19:02:16 -0700625 mContext.getString(R.string.mobile_network_settings_package),
626 mContext.getString(R.string.mobile_network_settings_class)));
Jayachandran C2ef9a482017-05-12 22:07:47 -0700627 intent.putExtra(GsmUmtsOptions.EXTRA_SUB_ID, subId);
fionaxu96ceebd2017-08-24 12:12:32 -0700628 builder.setContentIntent(PendingIntent.getActivity(mContext, 0, intent, 0));
629 mNotificationManager.notifyAsUser(
irisykyang25202462018-11-13 14:49:54 +0800630 Integer.toString(subId) /* tag */,
fionaxu96ceebd2017-08-24 12:12:32 -0700631 SELECTED_OPERATOR_FAIL_NOTIFICATION,
632 builder.build(),
633 UserHandle.ALL);
irisykyang25202462018-11-13 14:49:54 +0800634 mSelectedUnavailableNotify.put(subId, true);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700635 }
636
637 /**
638 * Turn off the network selection "no service" notification
639 */
irisykyang25202462018-11-13 14:49:54 +0800640 private void cancelNetworkSelection(int subId) {
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700641 if (DBG) log("cancelNetworkSelection()...");
Andrew Lee99d0ac22014-10-10 13:18:04 -0700642 mNotificationManager.cancelAsUser(
irisykyang25202462018-11-13 14:49:54 +0800643 Integer.toString(subId) /* tag */, SELECTED_OPERATOR_FAIL_NOTIFICATION,
644 UserHandle.ALL);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700645 }
646
647 /**
648 * Update notification about no service of user selected operator
649 *
650 * @param serviceState Phone service state
Jayachandran C2ef9a482017-05-12 22:07:47 -0700651 * @param subId The subscription ID
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700652 */
Jayachandran C2ef9a482017-05-12 22:07:47 -0700653 void updateNetworkSelection(int serviceState, int subId) {
654 int phoneId = SubscriptionManager.getPhoneId(subId);
655 Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
656 PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
657 if (TelephonyCapabilities.supportsNetworkSelection(phone)) {
Amit Mahajana60be872015-01-15 16:05:08 -0800658 if (SubscriptionManager.isValidSubscriptionId(subId)) {
fionaxu996a1c32018-04-13 15:00:37 -0700659 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
660 String selectedNetworkOperatorName =
661 sp.getString(Phone.NETWORK_SELECTION_NAME_KEY + subId, "");
662 // get the shared preference of network_selection.
663 // empty is auto mode, otherwise it is the operator alpha name
664 // in case there is no operator name, check the operator numeric
665 if (TextUtils.isEmpty(selectedNetworkOperatorName)) {
666 selectedNetworkOperatorName =
667 sp.getString(Phone.NETWORK_SELECTION_KEY + subId, "");
668 }
669 boolean isManualSelection;
fionaxud6aac662018-03-14 16:44:29 -0700670 // if restoring manual selection is controlled by framework, then get network
671 // selection from shared preference, otherwise get from real network indicators.
672 boolean restoreSelection = !mContext.getResources().getBoolean(
673 com.android.internal.R.bool.skip_restoring_network_selection);
fionaxud6aac662018-03-14 16:44:29 -0700674 if (restoreSelection) {
fionaxud6aac662018-03-14 16:44:29 -0700675 isManualSelection = !TextUtils.isEmpty(selectedNetworkOperatorName);
676 } else {
fionaxud6aac662018-03-14 16:44:29 -0700677 isManualSelection = phone.getServiceStateTracker().mSS.getIsManualSelection();
Amit Mahajana60be872015-01-15 16:05:08 -0800678 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700679
fionaxud6aac662018-03-14 16:44:29 -0700680 if (DBG) {
681 log("updateNetworkSelection()..." + "state = " + serviceState + " new network "
682 + (isManualSelection ? selectedNetworkOperatorName : ""));
683 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700684
irisykyang25202462018-11-13 14:49:54 +0800685 if (isManualSelection) {
686 mSelectedNetworkOperatorName.put(subId, selectedNetworkOperatorName);
687 shouldShowNotification(serviceState, subId);
Amit Mahajana60be872015-01-15 16:05:08 -0800688 } else {
irisykyang25202462018-11-13 14:49:54 +0800689 dismissNetworkSelectionNotification(subId);
690 clearUpNetworkSelectionNotificationParam(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700691 }
692 } else {
Amit Mahajana60be872015-01-15 16:05:08 -0800693 if (DBG) log("updateNetworkSelection()..." + "state = " +
694 serviceState + " not updating network due to invalid subId " + subId);
irisykyang25202462018-11-13 14:49:54 +0800695 dismissNetworkSelectionNotificationForInactiveSubId();
696 }
697 }
698 }
699
700 private void dismissNetworkSelectionNotification(int subId) {
701 if (mSelectedUnavailableNotify.get(subId, false)) {
702 cancelNetworkSelection(subId);
703 mSelectedUnavailableNotify.remove(subId);
704 }
705 }
706
707 private void dismissNetworkSelectionNotificationForInactiveSubId() {
708 for (int i = 0; i < mSelectedUnavailableNotify.size(); i++) {
709 int subId = mSelectedUnavailableNotify.keyAt(i);
710 if (!mSubscriptionManager.isActiveSubId(subId)) {
711 dismissNetworkSelectionNotification(subId);
712 clearUpNetworkSelectionNotificationParam(subId);
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700713 }
714 }
715 }
716
717 /* package */ void postTransientNotification(int notifyId, CharSequence msg) {
718 if (mToast != null) {
719 mToast.cancel();
720 }
721
722 mToast = Toast.makeText(mContext, msg, Toast.LENGTH_LONG);
723 mToast.show();
724 }
725
726 private void log(String msg) {
727 Log.d(LOG_TAG, msg);
728 }
Tyler Gunna584e2c2017-09-19 11:40:12 -0700729
730 private void logi(String msg) {
731 Log.i(LOG_TAG, msg);
732 }
irisykyang25202462018-11-13 14:49:54 +0800733
734 /**
735 * In case network selection notification shows up repeatedly under
736 * unstable network condition. The logic is to check whether or not
737 * the service state keeps in no service condition for at least
738 * {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS}.
739 * And checking {@link #NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES} times.
740 * To avoid the notification showing up for the momentary state.
741 */
742 private void shouldShowNotification(int serviceState, int subId) {
743 if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
744 if (mPreviousServiceState.get(subId, STATE_UNKNOWN_SERVICE)
745 != ServiceState.STATE_OUT_OF_SERVICE) {
746 mOOSTimestamp.put(subId, getTimeStamp());
747 }
748 if ((getTimeStamp() - mOOSTimestamp.get(subId, 0L)
749 >= NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS)
750 || mPendingEventCounter.get(subId, 0)
751 > NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIMES) {
752 showNetworkSelection(mSelectedNetworkOperatorName.get(subId), subId);
753 clearUpNetworkSelectionNotificationParam(subId);
754 } else {
755 startPendingNetworkSelectionNotification(subId);
756 }
757 } else {
758 dismissNetworkSelectionNotification(subId);
759 }
760 mPreviousServiceState.put(subId, serviceState);
761 if (DBG) {
762 log("shouldShowNotification()..." + " subId = " + subId
763 + " serviceState = " + serviceState
764 + " mOOSTimestamp = " + mOOSTimestamp
765 + " mPendingEventCounter = " + mPendingEventCounter);
766 }
767 }
768
769 private void startPendingNetworkSelectionNotification(int subId) {
770 if (!mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
771 if (DBG) {
772 log("startPendingNetworkSelectionNotification: subId = " + subId);
773 }
774 mHandler.sendMessageDelayed(
775 mHandler.obtainMessage(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId),
776 NETWORK_SELECTION_NOTIFICATION_MAX_PENDING_TIME_IN_MS);
777 mPendingEventCounter.put(subId, mPendingEventCounter.get(subId, 0) + 1);
778 }
779 }
780
781 private void clearUpNetworkSelectionNotificationParam(int subId) {
782 if (mHandler.hasMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId)) {
783 mHandler.removeMessages(EVENT_PENDING_NETWORK_SELECTION_NOTIFICATION, subId);
784 }
785 mPreviousServiceState.remove(subId);
786 mOOSTimestamp.remove(subId);
787 mPendingEventCounter.remove(subId);
788 mSelectedNetworkOperatorName.remove(subId);
789 }
790
791 private static long getTimeStamp() {
792 return SystemClock.elapsedRealtime();
793 }
Santos Cordon7d4ddf62013-07-10 11:58:08 -0700794}