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