Post SUW Slot Change Receiver Migration
Implement the case when user inserts / removes pSIM during the SUW.
Bug: 153811431
Bug: 170508680
Test: Manually tested
Change-Id: Iccc3a2fd416ccfb57c3b4f9dc7b32c0b7681c90b
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 81a5ea8..f3066ce 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3662,6 +3662,14 @@
</receiver>
<receiver
+ android:name=".sim.receivers.SuwFinishReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="com.google.android.setupwizard.SETUP_WIZARD_FINISHED" />
+ </intent-filter>
+ </receiver>
+
+ <receiver
android:name=".sim.receivers.SimCompleteBootReceiver"
android:exported="true">
<intent-filter>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 09aea0e..d497e4e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -12142,6 +12142,10 @@
<string name="switch_to_removable_notification_no_carrier_name">Switched to another carrier</string>
<!-- Message in a push notification indicating that the user's phone has connected to a different mobile network. [CHAR LIMIT=NONE] -->
<string name="network_changed_notification_text">Your mobile network has changed</string>
+ <!-- Title on a push notification indicating that the user's device is capable of DSDS. [CHAR LIMIT=NONE] -->
+ <string name="dsds_notification_after_suw_title">Set up your other SIM</string>
+ <!-- Message in a push notification indicating that the user's device is capable of DSDS. [CHAR LIMIT=NONE] -->
+ <string name="dsds_notification_after_suw_text">Choose your active SIM or use 2 SIMs at once</string>
<!-- Strings for choose SIM activity -->
<!-- The title text of choose SIM activity. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/sim/SimActivationNotifier.java b/src/com/android/settings/sim/SimActivationNotifier.java
index a38816a..735cb46 100644
--- a/src/com/android/settings/sim/SimActivationNotifier.java
+++ b/src/com/android/settings/sim/SimActivationNotifier.java
@@ -66,12 +66,15 @@
value = {
NotificationType.NETWORK_CONFIG,
NotificationType.SWITCH_TO_REMOVABLE_SLOT,
+ NotificationType.ENABLE_DSDS,
})
public @interface NotificationType {
// The notification to remind users to config network Settings.
int NETWORK_CONFIG = 1;
// The notification to notify users that the device is switched to the removable slot.
int SWITCH_TO_REMOVABLE_SLOT = 2;
+ // The notification to notify users that the device is capable of DSDS.
+ int ENABLE_DSDS = 3;
}
private final Context mContext;
@@ -120,8 +123,8 @@
return;
}
- CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
- activeRemovableSub, mContext);
+ CharSequence displayName =
+ SubscriptionUtil.getUniqueSubscriptionDisplayName(activeRemovableSub, mContext);
String carrierName =
TextUtils.isEmpty(displayName)
? mContext.getString(R.string.sim_card_label)
@@ -135,7 +138,8 @@
TaskStackBuilder.create(mContext).addNextIntent(clickIntent);
PendingIntent contentIntent =
stackBuilder.getPendingIntent(
- 0 /* requestCode */, PendingIntent.FLAG_UPDATE_CURRENT);
+ 0 /* requestCode */,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Notification.Builder builder =
new Notification.Builder(mContext, SIM_SETUP_CHANNEL_ID)
@@ -155,7 +159,8 @@
TaskStackBuilder.create(mContext).addNextIntent(clickIntent);
PendingIntent contentIntent =
stackBuilder.getPendingIntent(
- 0 /* requestCode */, PendingIntent.FLAG_UPDATE_CURRENT);
+ 0 /* requestCode */,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
String titleText =
TextUtils.isEmpty(carrierName)
? mContext.getString(
@@ -178,6 +183,33 @@
mNotificationManager.notify(SWITCH_TO_REMOVABLE_SLOT_NOTIFICATION_ID, builder.build());
}
+ /** Sends a push notification for enabling DSDS. */
+ public void sendEnableDsdsNotification() {
+ Intent parentIntent = new Intent(mContext, Settings.MobileNetworkListActivity.class);
+
+ Intent clickIntent = new Intent(mContext, DsdsDialogActivity.class);
+
+ TaskStackBuilder stackBuilder =
+ TaskStackBuilder.create(mContext)
+ .addNextIntentWithParentStack(parentIntent)
+ .addNextIntent(clickIntent);
+ PendingIntent contentIntent =
+ stackBuilder.getPendingIntent(
+ 0 /* requestCode */,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+
+ Notification.Builder builder =
+ new Notification.Builder(mContext, SIM_SETUP_CHANNEL_ID)
+ .setContentTitle(
+ mContext.getString(R.string.dsds_notification_after_suw_title))
+ .setContentText(
+ mContext.getString(R.string.dsds_notification_after_suw_text))
+ .setContentIntent(contentIntent)
+ .setSmallIcon(R.drawable.ic_sim_alert)
+ .setAutoCancel(true);
+ mNotificationManager.notify(SIM_ACTIVATION_NOTIFICATION_ID, builder.build());
+ }
+
@Nullable
private SubscriptionInfo getActiveRemovableSub() {
SubscriptionManager subscriptionManager =
diff --git a/src/com/android/settings/sim/SimNotificationService.java b/src/com/android/settings/sim/SimNotificationService.java
index 0f52c8b..42b5e58 100644
--- a/src/com/android/settings/sim/SimNotificationService.java
+++ b/src/com/android/settings/sim/SimNotificationService.java
@@ -71,6 +71,9 @@
case SimActivationNotifier.NotificationType.SWITCH_TO_REMOVABLE_SLOT:
new SimActivationNotifier(this).sendSwitchedToRemovableSlotNotification();
break;
+ case SimActivationNotifier.NotificationType.ENABLE_DSDS:
+ new SimActivationNotifier(this).sendEnableDsdsNotification();
+ break;
default:
Log.e(TAG, "Invalid notification type: " + notificationType);
break;
diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
index c092428..fe44389 100644
--- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
+++ b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java
@@ -50,7 +50,13 @@
private static final String TAG = "SimSlotChangeHandler";
private static final String EUICC_PREFS = "euicc_prefs";
+ // Shared preference keys
private static final String KEY_REMOVABLE_SLOT_STATE = "removable_slot_state";
+ private static final String KEY_SUW_PSIM_ACTION = "suw_psim_action";
+ // User's last removable SIM insertion / removal action during SUW.
+ private static final int LAST_USER_ACTION_IN_SUW_NONE = 0;
+ private static final int LAST_USER_ACTION_IN_SUW_INSERT = 1;
+ private static final int LAST_USER_ACTION_IN_SUW_REMOVE = 2;
private static volatile SimSlotChangeHandler sSlotChangeHandler;
@@ -107,6 +113,47 @@
Log.i(TAG, "Do nothing on slot status changes.");
}
+ void onSuwFinish(Context context) {
+ init(context);
+
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ throw new IllegalStateException("Cannot be called from main thread.");
+ }
+
+ if (mTelMgr.getActiveModemCount() > 1) {
+ Log.i(TAG, "The device is already in DSDS mode. Do nothing.");
+ return;
+ }
+
+ UiccSlotInfo removableSlotInfo = getRemovableUiccSlotInfo();
+ if (removableSlotInfo == null) {
+ Log.e(TAG, "Unable to find the removable slot. Do nothing.");
+ return;
+ }
+
+ boolean embeddedSimExist = getGroupedEmbeddedSubscriptions().size() != 0;
+ int removableSlotAction = getSuwRemovableSlotAction(mContext);
+ setSuwRemovableSlotAction(mContext, LAST_USER_ACTION_IN_SUW_NONE);
+
+ if (embeddedSimExist
+ && removableSlotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_PRESENT) {
+ if (mTelMgr.isMultiSimSupported() == TelephonyManager.MULTISIM_ALLOWED) {
+ Log.i(TAG, "DSDS condition satisfied. Show notification.");
+ SimNotificationService.scheduleSimNotification(
+ mContext, SimActivationNotifier.NotificationType.ENABLE_DSDS);
+ } else if (removableSlotAction == LAST_USER_ACTION_IN_SUW_INSERT) {
+ Log.i(
+ TAG,
+ "Both removable SIM and eSIM are present. DSDS condition doesn't"
+ + " satisfied. User inserted pSIM during SUW. Show choose SIM"
+ + " screen.");
+ startChooseSimActivity(true);
+ }
+ } else if (removableSlotAction == LAST_USER_ACTION_IN_SUW_REMOVE) {
+ handleSimRemove(removableSlotInfo);
+ }
+ }
+
private void init(Context context) {
mSubMgr =
(SubscriptionManager)
@@ -116,11 +163,11 @@
}
private void handleSimInsert(UiccSlotInfo removableSlotInfo) {
- Log.i(TAG, "Detect SIM inserted.");
+ Log.i(TAG, "Handle SIM inserted.");
if (!isSuwFinished(mContext)) {
- // TODO(b/170508680): Store the action and handle it after SUW is finished.
Log.i(TAG, "Still in SUW. Handle SIM insertion after SUW is finished");
+ setSuwRemovableSlotAction(mContext, LAST_USER_ACTION_IN_SUW_INSERT);
return;
}
@@ -156,11 +203,11 @@
}
private void handleSimRemove(UiccSlotInfo removableSlotInfo) {
- Log.i(TAG, "Detect SIM removed.");
+ Log.i(TAG, "Handle SIM removed.");
if (!isSuwFinished(mContext)) {
- // TODO(b/170508680): Store the action and handle it after SUW is finished.
Log.i(TAG, "Still in SUW. Handle SIM removal after SUW is finished");
+ setSuwRemovableSlotAction(mContext, LAST_USER_ACTION_IN_SUW_REMOVE);
return;
}
@@ -195,6 +242,16 @@
prefs.edit().putInt(KEY_REMOVABLE_SLOT_STATE, state).apply();
}
+ private int getSuwRemovableSlotAction(Context context) {
+ final SharedPreferences prefs = context.getSharedPreferences(EUICC_PREFS, MODE_PRIVATE);
+ return prefs.getInt(KEY_SUW_PSIM_ACTION, LAST_USER_ACTION_IN_SUW_NONE);
+ }
+
+ private void setSuwRemovableSlotAction(Context context, int action) {
+ final SharedPreferences prefs = context.getSharedPreferences(EUICC_PREFS, MODE_PRIVATE);
+ prefs.edit().putInt(KEY_SUW_PSIM_ACTION, action).apply();
+ }
+
@Nullable
private UiccSlotInfo getRemovableUiccSlotInfo() {
UiccSlotInfo[] slotInfos = mTelMgr.getUiccSlotsInfo();
diff --git a/src/com/android/settings/sim/receivers/SuwFinishReceiver.java b/src/com/android/settings/sim/receivers/SuwFinishReceiver.java
new file mode 100644
index 0000000..7facbe2
--- /dev/null
+++ b/src/com/android/settings/sim/receivers/SuwFinishReceiver.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.sim.receivers;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settingslib.utils.ThreadUtils;
+
+/** The receiver when SUW is finished. */
+public class SuwFinishReceiver extends BroadcastReceiver {
+ private static final String TAG = "SuwFinishReceiver";
+
+ private final SimSlotChangeHandler mSlotChangeHandler = SimSlotChangeHandler.get();
+ private final Object mLock = new Object();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!context.getResources().getBoolean(R.bool.config_handle_sim_slot_change)) {
+ Log.i(TAG, "The flag is off. Ignore SUW finish event.");
+ return;
+ }
+
+ final BroadcastReceiver.PendingResult pendingResult = goAsync();
+ ThreadUtils.postOnBackgroundThread(
+ () -> {
+ synchronized (mLock) {
+ Log.i(TAG, "Detected SUW finished. Checking slot events.");
+ mSlotChangeHandler.onSuwFinish(context.getApplicationContext());
+ }
+ ThreadUtils.postOnMainThread(pendingResult::finish);
+ });
+ }
+}