1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.sim; 18 19 import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS; 20 import static android.provider.Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS; 21 import static android.provider.Settings.EXTRA_ENABLE_MMS_DATA_REQUEST_REASON; 22 import static android.provider.Settings.EXTRA_SUB_ID; 23 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE; 24 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL; 25 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA; 26 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS; 27 import static android.telephony.TelephonyManager.EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE; 28 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_NAMES; 29 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_WARNING_TYPE; 30 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA; 31 import static android.telephony.TelephonyManager.EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE; 32 import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID; 33 import static android.telephony.data.ApnSetting.TYPE_MMS; 34 35 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; 36 37 import android.app.Notification; 38 import android.app.NotificationChannel; 39 import android.app.NotificationManager; 40 import android.app.PendingIntent; 41 import android.content.BroadcastReceiver; 42 import android.content.Context; 43 import android.content.Intent; 44 import android.content.res.Resources; 45 import android.os.UserManager; 46 import android.provider.Settings; 47 import android.telephony.SubscriptionInfo; 48 import android.telephony.SubscriptionManager; 49 import android.telephony.TelephonyManager; 50 import android.util.Log; 51 52 import androidx.annotation.NonNull; 53 import androidx.annotation.WorkerThread; 54 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.settings.HelpTrampoline; 57 import com.android.settings.R; 58 import com.android.settings.network.SatelliteRepository; 59 import com.android.settings.network.SubscriptionUtil; 60 61 import com.google.common.util.concurrent.ListenableFuture; 62 63 import java.util.concurrent.ExecutionException; 64 import java.util.concurrent.Executor; 65 import java.util.concurrent.Executors; 66 import java.util.concurrent.TimeUnit; 67 import java.util.concurrent.TimeoutException; 68 69 public class SimSelectNotification extends BroadcastReceiver { 70 private static final String TAG = "SimSelectNotification"; 71 72 private static final int DEFAULT_TIMEOUT_MS = 1000; 73 74 @VisibleForTesting 75 public static final int SIM_SELECT_NOTIFICATION_ID = 1; 76 @VisibleForTesting 77 public static final int ENABLE_MMS_NOTIFICATION_ID = 2; 78 @VisibleForTesting 79 public static final int SIM_WARNING_NOTIFICATION_ID = 3; 80 81 @VisibleForTesting 82 public static final String SIM_SELECT_NOTIFICATION_CHANNEL = 83 "sim_select_notification_channel"; 84 85 @VisibleForTesting 86 public static final String ENABLE_MMS_NOTIFICATION_CHANNEL = 87 "enable_mms_notification_channel"; 88 89 @VisibleForTesting 90 public static final String SIM_WARNING_NOTIFICATION_CHANNEL = 91 "sim_warning_notification_channel"; 92 93 @Override onReceive(Context context, Intent intent)94 public void onReceive(Context context, Intent intent) { 95 UserManager userManager = context.getSystemService(UserManager.class); 96 if (userManager != null && !userManager.isMainUser()) { 97 Log.d(TAG, "The userId is not the main user"); 98 return; 99 } 100 if (!SubscriptionUtil.isSimHardwareVisible(context)) { 101 Log.w(TAG, "Received unexpected intent with null action."); 102 return; 103 } 104 String action = intent.getAction(); 105 106 if (action == null) { 107 Log.w(TAG, "Received unexpected intent with null action."); 108 return; 109 } 110 111 switch (action) { 112 case TelephonyManager.ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED: 113 PrimarySubscriptionListChangedService.scheduleJob(context, intent); 114 break; 115 case Settings.ACTION_ENABLE_MMS_DATA_REQUEST: 116 onEnableMmsDataRequest(context, intent); 117 break; 118 default: 119 Log.w(TAG, "Received unexpected intent " + intent.getAction()); 120 } 121 } 122 onEnableMmsDataRequest(Context context, Intent intent)123 private void onEnableMmsDataRequest(Context context, Intent intent) { 124 // Getting subId from extra. 125 int subId = intent.getIntExtra(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); 126 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 127 subId = SubscriptionManager.getDefaultSmsSubscriptionId(); 128 } 129 130 SubscriptionManager subscriptionManager = ((SubscriptionManager) context.getSystemService( 131 Context.TELEPHONY_SUBSCRIPTION_SERVICE)); 132 if (!subscriptionManager.isActiveSubscriptionId(subId)) { 133 Log.w(TAG, "onEnableMmsDataRequest invalid sub ID " + subId); 134 return; 135 } 136 final SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo(subId); 137 if (info == null) { 138 Log.w(TAG, "onEnableMmsDataRequest null SubscriptionInfo for sub ID " + subId); 139 return; 140 } 141 142 // Getting request reason from extra, which will determine the notification title. 143 CharSequence notificationTitle = null; 144 int requestReason = intent.getIntExtra(EXTRA_ENABLE_MMS_DATA_REQUEST_REASON, -1); 145 if (requestReason == ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS) { 146 notificationTitle = context.getResources().getText( 147 R.string.enable_receiving_mms_notification_title); 148 } else if (requestReason == ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS) { 149 notificationTitle = context.getResources().getText( 150 R.string.enable_sending_mms_notification_title); 151 } else { 152 Log.w(TAG, "onEnableMmsDataRequest invalid request reason " + requestReason); 153 return; 154 } 155 156 TelephonyManager tm = ((TelephonyManager) context.getSystemService( 157 Context.TELEPHONY_SERVICE)).createForSubscriptionId(subId); 158 159 if (tm.isDataEnabledForApn(TYPE_MMS)) { 160 Log.w(TAG, "onEnableMmsDataRequest MMS data already enabled on sub ID " + subId); 161 return; 162 } 163 164 CharSequence notificationSummary = context.getResources().getString( 165 R.string.enable_mms_notification_summary, 166 SubscriptionUtil.getUniqueSubscriptionDisplayName(info, context)); 167 168 cancelEnableMmsNotification(context); 169 170 createEnableMmsNotification(context, notificationTitle, notificationSummary, subId); 171 } 172 173 /** 174 * Handles changes to the primary subscription list, performing actions only 175 * if the device is not currently in a satellite session. This method is 176 * intended to be executed on a worker thread. 177 * 178 * @param context The application context 179 * @param intent The intent signaling a primary subscription change 180 */ 181 @WorkerThread onPrimarySubscriptionListChanged(@onNull Context context, @NonNull Intent intent)182 public static void onPrimarySubscriptionListChanged(@NonNull Context context, 183 @NonNull Intent intent) { 184 Log.d(TAG, "Checking satellite enabled status"); 185 Executor executor = Executors.newSingleThreadExecutor(); 186 ListenableFuture<Boolean> isSatelliteSessionStartedFuture = 187 new SatelliteRepository(context).requestIsSessionStarted(executor); 188 boolean isSatelliteSessionStarted = false; 189 try { 190 isSatelliteSessionStarted = 191 isSatelliteSessionStartedFuture.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS); 192 } catch (InterruptedException | ExecutionException | TimeoutException e) { 193 Log.w(TAG, "Can't get satellite session status", e); 194 } finally { 195 if (isSatelliteSessionStarted) { 196 Log.i(TAG, "Device is in a satellite session.g Unable to handle primary" 197 + " subscription list changes"); 198 } else { 199 Log.i(TAG, "Device is not in a satellite session. Handle primary" 200 + " subscription list changes"); 201 startSimSelectDialogIfNeeded(context, intent); 202 sendSimCombinationWarningIfNeeded(context, intent); 203 } 204 } 205 } 206 startSimSelectDialogIfNeeded(Context context, Intent intent)207 private static void startSimSelectDialogIfNeeded(Context context, Intent intent) { 208 int dialogType = intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, 209 EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE); 210 211 if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE) { 212 return; 213 } 214 215 // Cancel any previous notifications 216 cancelSimSelectNotification(context); 217 218 // If the dialog type is to dismiss. 219 if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DISMISS) { 220 SimDialogProhibitService.dismissDialog(context); 221 return; 222 } 223 224 // Create a notification to tell the user that some defaults are missing 225 createSimSelectNotification(context); 226 227 if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL) { 228 int subId = intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, 229 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 230 int slotIndex = SubscriptionManager.getSlotIndex(subId); 231 // If there is only one subscription, ask if user wants to use if for everything 232 Intent newIntent = new Intent(context, SimDialogActivity.class); 233 newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 234 newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, 235 SimDialogActivity.PREFERRED_PICK); 236 newIntent.putExtra(SimDialogActivity.PREFERRED_SIM, slotIndex); 237 context.startActivity(newIntent); 238 } else if (dialogType == EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA) { 239 // If there are multiple, ensure they pick default data 240 Intent newIntent = new Intent(context, SimDialogActivity.class); 241 newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 242 newIntent.putExtra(SimDialogActivity.DIALOG_TYPE_KEY, SimDialogActivity.DATA_PICK); 243 context.startActivity(newIntent); 244 } 245 } 246 sendSimCombinationWarningIfNeeded(Context context, Intent intent)247 private static void sendSimCombinationWarningIfNeeded(Context context, Intent intent) { 248 final int warningType = intent.getIntExtra(EXTRA_SIM_COMBINATION_WARNING_TYPE, 249 EXTRA_SIM_COMBINATION_WARNING_TYPE_NONE); 250 251 // Cancel any previous notifications 252 cancelSimCombinationWarningNotification(context); 253 254 if (warningType == EXTRA_SIM_COMBINATION_WARNING_TYPE_DUAL_CDMA) { 255 // Create a notification to tell the user that there's a sim combination warning. 256 createSimCombinationWarningNotification(context, intent); 257 } 258 } 259 createSimSelectNotification(Context context)260 private static void createSimSelectNotification(Context context) { 261 final Resources resources = context.getResources(); 262 263 NotificationChannel notificationChannel = new NotificationChannel( 264 SIM_SELECT_NOTIFICATION_CHANNEL, 265 resources.getText(R.string.sim_selection_channel_title), 266 NotificationManager.IMPORTANCE_LOW); 267 268 Notification.Builder builder = 269 new Notification.Builder(context, SIM_SELECT_NOTIFICATION_CHANNEL) 270 .setSmallIcon(R.drawable.ic_sim_alert) 271 .setColor(context.getColor(R.color.sim_noitification)) 272 .setContentTitle(resources.getText(R.string.sim_notification_title)) 273 .setContentText(resources.getText(R.string.sim_notification_summary)) 274 .setAutoCancel(true); 275 Intent resultIntent = new Intent(Settings.ACTION_WIRELESS_SETTINGS); 276 resultIntent.setPackage(SETTINGS_PACKAGE_NAME); 277 resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 278 PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, 279 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 280 builder.setContentIntent(resultPendingIntent); 281 NotificationManager notificationManager = 282 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 283 notificationManager.createNotificationChannel(notificationChannel); 284 notificationManager.notify(SIM_SELECT_NOTIFICATION_ID, builder.build()); 285 } 286 cancelSimSelectNotification(Context context)287 public static void cancelSimSelectNotification(Context context) { 288 NotificationManager notificationManager = 289 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 290 notificationManager.cancel(SIM_SELECT_NOTIFICATION_ID); 291 } 292 createEnableMmsNotification(Context context, CharSequence titleString, CharSequence notificationSummary, int subId)293 private void createEnableMmsNotification(Context context, CharSequence titleString, 294 CharSequence notificationSummary, int subId) { 295 final Resources resources = context.getResources(); 296 297 NotificationChannel notificationChannel = new NotificationChannel( 298 ENABLE_MMS_NOTIFICATION_CHANNEL, 299 resources.getText(R.string.enable_mms_notification_channel_title), 300 NotificationManager.IMPORTANCE_HIGH); 301 302 Notification.Builder builder = 303 new Notification.Builder(context, ENABLE_MMS_NOTIFICATION_CHANNEL) 304 .setSmallIcon(R.drawable.ic_settings_24dp) 305 .setColor(context.getColor(R.color.sim_noitification)) 306 .setContentTitle(titleString) 307 .setContentText(notificationSummary) 308 .setStyle(new Notification.BigTextStyle().bigText(notificationSummary)) 309 .setAutoCancel(true); 310 311 // Create the pending intent that will lead to the subscription setting page. 312 Intent resultIntent = new Intent(Settings.ACTION_MMS_MESSAGE_SETTING); 313 resultIntent.setPackage(SETTINGS_PACKAGE_NAME); 314 resultIntent.putExtra(Settings.EXTRA_SUB_ID, subId); 315 PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, 316 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 317 builder.setContentIntent(resultPendingIntent); 318 319 // Notify the notification. 320 NotificationManager notificationManager = 321 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 322 notificationManager.createNotificationChannel(notificationChannel); 323 notificationManager.notify(ENABLE_MMS_NOTIFICATION_ID, builder.build()); 324 } 325 cancelEnableMmsNotification(Context context)326 private void cancelEnableMmsNotification(Context context) { 327 NotificationManager notificationManager = 328 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 329 notificationManager.cancel(ENABLE_MMS_NOTIFICATION_ID); 330 } 331 createSimCombinationWarningNotification(Context context, Intent intent)332 private static void createSimCombinationWarningNotification(Context context, Intent intent) { 333 final Resources resources = context.getResources(); 334 final String simNames = intent.getStringExtra(EXTRA_SIM_COMBINATION_NAMES); 335 336 if (simNames == null) { 337 return; 338 } 339 340 CharSequence dualCdmaSimWarningSummary = resources.getString( 341 R.string.dual_cdma_sim_warning_notification_summary, simNames); 342 343 NotificationChannel notificationChannel = new NotificationChannel( 344 SIM_WARNING_NOTIFICATION_CHANNEL, 345 resources.getText(R.string.dual_cdma_sim_warning_notification_channel_title), 346 NotificationManager.IMPORTANCE_HIGH); 347 348 Notification.Builder builder = 349 new Notification.Builder(context, SIM_WARNING_NOTIFICATION_CHANNEL) 350 .setSmallIcon(R.drawable.ic_sim_alert) 351 .setColor(context.getColor(R.color.sim_noitification)) 352 .setContentTitle(resources.getText( 353 R.string.sim_combination_warning_notification_title)) 354 .setContentText(dualCdmaSimWarningSummary) 355 .setStyle(new Notification.BigTextStyle().bigText( 356 dualCdmaSimWarningSummary)) 357 .setAutoCancel(true); 358 359 // Create the pending intent that will lead to the helper page. 360 Intent resultIntent = new Intent(context, HelpTrampoline.class); 361 resultIntent.putExtra(Intent.EXTRA_TEXT, "help_uri_sim_combination_warning"); 362 363 PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, resultIntent, 364 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); 365 builder.setContentIntent(resultPendingIntent); 366 367 NotificationManager notificationManager = 368 context.getSystemService(NotificationManager.class); 369 notificationManager.createNotificationChannel(notificationChannel); 370 notificationManager.notify(SIM_WARNING_NOTIFICATION_ID, builder.build()); 371 } 372 cancelSimCombinationWarningNotification(Context context)373 public static void cancelSimCombinationWarningNotification(Context context) { 374 NotificationManager notificationManager = 375 context.getSystemService(NotificationManager.class); 376 notificationManager.cancel(SIM_WARNING_NOTIFICATION_ID); 377 } 378 } 379