From 85109678b22bffe07c3a13e537ed933d7d9e63fb Mon Sep 17 00:00:00 2001 From: Jiashen Wang Date: Mon, 25 Jan 2021 19:49:26 -0800 Subject: [PATCH] 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 --- AndroidManifest.xml | 8 +++ res/values/strings.xml | 4 ++ .../settings/sim/SimActivationNotifier.java | 40 ++++++++++-- .../settings/sim/SimNotificationService.java | 3 + .../sim/receivers/SimSlotChangeHandler.java | 65 +++++++++++++++++-- .../sim/receivers/SuwFinishReceiver.java | 51 +++++++++++++++ 6 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 src/com/android/settings/sim/receivers/SuwFinishReceiver.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 81a5ea878f0..f3066ce33ff 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3661,6 +3661,14 @@ + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 09aea0e1f0b..d497e4e6cf1 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12142,6 +12142,10 @@ Switched to another carrier Your mobile network has changed + + Set up your other SIM + + Choose your active SIM or use 2 SIMs at once diff --git a/src/com/android/settings/sim/SimActivationNotifier.java b/src/com/android/settings/sim/SimActivationNotifier.java index a38816a6d1b..735cb463c3e 100644 --- a/src/com/android/settings/sim/SimActivationNotifier.java +++ b/src/com/android/settings/sim/SimActivationNotifier.java @@ -66,12 +66,15 @@ public class SimActivationNotifier { 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 @@ public class SimActivationNotifier { 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 @@ public class SimActivationNotifier { 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 @@ public class SimActivationNotifier { 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 @@ public class SimActivationNotifier { 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 0f52c8b70fd..42b5e58cd8b 100644 --- a/src/com/android/settings/sim/SimNotificationService.java +++ b/src/com/android/settings/sim/SimNotificationService.java @@ -71,6 +71,9 @@ public class SimNotificationService extends JobService { 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 c09242861ad..fe44389c6b6 100644 --- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java +++ b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java @@ -50,7 +50,13 @@ public class SimSlotChangeHandler { 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 @@ public class SimSlotChangeHandler { 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 @@ public class SimSlotChangeHandler { } 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 @@ public class SimSlotChangeHandler { } 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 @@ public class SimSlotChangeHandler { 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 00000000000..7facbe25f85 --- /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); + }); + } +}