Slot Change Receiver Migration

Implemented slot change cases when pSIM is inserted and removed.
Bug: 153811431
Bug: 170508680
Test: Manually tested

Change-Id: Ib0a96da1d7d702f7c64e75b929c73b8548f8e459
This commit is contained in:
Jiashen Wang
2021-01-18 19:14:00 -08:00
parent 0457af5347
commit b54d25ee13
17 changed files with 936 additions and 22 deletions

View File

@@ -0,0 +1,321 @@
/*
* 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;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.SidecarFragment;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.SwitchToEuiccSubscriptionSidecar;
import com.android.settings.network.SwitchToRemovableSlotSidecar;
import com.android.settings.network.UiccSlotUtil;
import com.google.android.setupdesign.GlifLayout;
import com.google.android.setupdesign.GlifRecyclerLayout;
import com.google.android.setupdesign.items.Dividable;
import com.google.android.setupdesign.items.IItem;
import com.google.android.setupdesign.items.Item;
import com.google.android.setupdesign.items.ItemGroup;
import com.google.android.setupdesign.items.RecyclerItemAdapter;
import com.google.android.setupdesign.view.HeaderRecyclerView;
import java.util.ArrayList;
import java.util.List;
/** Activity to show a list of profiles for user to choose. */
public class ChooseSimActivity extends Activity
implements RecyclerItemAdapter.OnItemSelectedListener, SidecarFragment.Listener {
// Whether there is a pSIM profile in the selection list.
public static final String KEY_HAS_PSIM = "has_psim";
// After the user selects eSIM profile, whether continue to show Mobile Network Settings screen
// to select other preferences.
// Note: KEY_NO_PSIM_CONTINUE_TO_SETTINGS and mNoPsimContinueToSettings are not used for now
// for UI changes. We may use them in the future.
public static final String KEY_NO_PSIM_CONTINUE_TO_SETTINGS = "no_psim_continue_to_settings";
private static final String TAG = "ChooseSimActivity";
private static final int INDEX_PSIM = -1;
private static final String STATE_SELECTED_INDEX = "selected_index";
private static final String STATE_IS_SWITCHING = "is_switching";
private boolean mHasPsim;
private boolean mNoPsimContinueToSettings;
private ArrayList<SubscriptionInfo> mEmbeddedSubscriptions = new ArrayList<>();
private SubscriptionInfo mRemovableSubscription = null;
private ItemGroup mItemGroup;
private SwitchToEuiccSubscriptionSidecar mSwitchToEuiccSubscriptionSidecar;
private SwitchToRemovableSlotSidecar mSwitchToRemovableSlotSidecar;
// Variables have states.
private int mSelectedItemIndex;
private boolean mIsSwitching;
/** Returns an intent of {@code ChooseSimActivity} */
public static Intent getIntent(Context context) {
return new Intent(context, ChooseSimActivity.class);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choose_sim_activity);
Intent intent = getIntent();
mHasPsim = intent.getBooleanExtra(KEY_HAS_PSIM, false);
mNoPsimContinueToSettings = intent.getBooleanExtra(KEY_NO_PSIM_CONTINUE_TO_SETTINGS, false);
updateSubscriptions();
if (mEmbeddedSubscriptions.size() == 0) {
Log.e(TAG, "Unable to find available eSIM subscriptions.");
finish();
return;
}
if (savedInstanceState != null) {
mSelectedItemIndex = savedInstanceState.getInt(STATE_SELECTED_INDEX);
mIsSwitching = savedInstanceState.getBoolean(STATE_IS_SWITCHING);
}
GlifLayout layout = findViewById(R.id.glif_layout);
TextView textView = findViewById(R.id.subtitle);
int subscriptionCount = mEmbeddedSubscriptions.size();
if (mHasPsim) { // Choose a number to use
subscriptionCount++;
}
layout.setHeaderText(getString(R.string.choose_sim_title));
textView.setText(getString(R.string.choose_sim_text, subscriptionCount));
displaySubscriptions();
mSwitchToRemovableSlotSidecar = SwitchToRemovableSlotSidecar.get(getFragmentManager());
mSwitchToEuiccSubscriptionSidecar =
SwitchToEuiccSubscriptionSidecar.get(getFragmentManager());
}
@Override
public void onResume() {
super.onResume();
mSwitchToRemovableSlotSidecar.addListener(this);
mSwitchToEuiccSubscriptionSidecar.addListener(this);
}
@Override
public void onPause() {
mSwitchToEuiccSubscriptionSidecar.removeListener(this);
mSwitchToRemovableSlotSidecar.removeListener(this);
super.onPause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(STATE_SELECTED_INDEX, mSelectedItemIndex);
outState.putBoolean(STATE_IS_SWITCHING, mIsSwitching);
super.onSaveInstanceState(outState);
}
@Override
public void onItemSelected(IItem item) {
if (mIsSwitching) {
// If we already selected an item, do not try to switch to another one.
return;
}
mIsSwitching = true;
Item subItem = (Item) item;
subItem.setSummary(getString(R.string.choose_sim_activating));
mSelectedItemIndex = subItem.getId();
if (mSelectedItemIndex == INDEX_PSIM) {
Log.i(TAG, "Ready to switch to pSIM slot.");
mSwitchToRemovableSlotSidecar.run(UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID);
} else {
Log.i(TAG, "Ready to switch to eSIM subscription with index: " + mSelectedItemIndex);
mSwitchToEuiccSubscriptionSidecar.run(
mEmbeddedSubscriptions.get(mSelectedItemIndex).getSubscriptionId());
}
}
@Override
public void onStateChange(SidecarFragment fragment) {
if (fragment == mSwitchToRemovableSlotSidecar) {
switch (mSwitchToRemovableSlotSidecar.getState()) {
case SidecarFragment.State.SUCCESS:
mSwitchToRemovableSlotSidecar.reset();
Log.i(TAG, "Switch slot successfully.");
SubscriptionManager subMgr = getSystemService(SubscriptionManager.class);
if (subMgr.canDisablePhysicalSubscription()) {
SubscriptionInfo removableSub =
SubscriptionUtil.getFirstRemovableSubscription(this);
if (removableSub != null) {
subMgr.setUiccApplicationsEnabled(
removableSub.getSubscriptionId(), true);
}
}
finish();
break;
case SidecarFragment.State.ERROR:
mSwitchToRemovableSlotSidecar.reset();
Log.e(TAG, "Failed to switch slot in ChooseSubscriptionsActivity.");
handleEnableRemovableSimError();
// We don't call finish() and just stay on this page.
break;
}
} else if (fragment == mSwitchToEuiccSubscriptionSidecar) {
switch (mSwitchToEuiccSubscriptionSidecar.getState()) {
case SidecarFragment.State.SUCCESS:
mSwitchToEuiccSubscriptionSidecar.reset();
if (mNoPsimContinueToSettings) {
// Currently, there shouldn't be a case that mNoPsimContinueToSettings is
// true. If this can be true in the future, we should finish() this page
// and direct to Settings page here.
Log.e(
TAG,
"mNoPsimContinueToSettings is true which is not supported for"
+ " now.");
} else {
Log.i(TAG, "User finished selecting eSIM profile.");
finish();
}
break;
case SidecarFragment.State.ERROR:
mSwitchToEuiccSubscriptionSidecar.reset();
Log.e(TAG, "Failed to switch subscription in ChooseSubscriptionsActivity.");
Item item = (Item) mItemGroup.getItemAt(mSelectedItemIndex);
item.setEnabled(false);
item.setSummary(getString(R.string.choose_sim_could_not_activate));
mIsSwitching = false;
// We don't call finish() and just stay on this page.
break;
}
}
}
private void displaySubscriptions() {
View rootView = findViewById(android.R.id.content);
GlifRecyclerLayout layout = rootView.findViewById(R.id.recycler_list);
RecyclerItemAdapter adapter = (RecyclerItemAdapter) layout.getAdapter();
adapter.setOnItemSelectedListener(this);
mItemGroup = (ItemGroup) adapter.getRootItemHierarchy();
// Display pSIM profile.
if (mHasPsim) {
Item item = new DisableableItem();
// Title
CharSequence title = null;
if (mRemovableSubscription != null) {
title =
SubscriptionUtil.getUniqueSubscriptionDisplayName(
mRemovableSubscription.getSubscriptionId(), this);
}
item.setTitle(TextUtils.isEmpty(title) ? getString(R.string.sim_card_label) : title);
if (mIsSwitching && mSelectedItemIndex == INDEX_PSIM) {
item.setSummary(getString(R.string.choose_sim_activating));
} else {
// Phone number
String phoneNumber =
SubscriptionUtil.getFormattedPhoneNumber(this, mRemovableSubscription);
item.setSummary(TextUtils.isEmpty(phoneNumber) ? "" : phoneNumber);
}
// pSIM profile has index -1.
item.setId(INDEX_PSIM);
mItemGroup.addChild(item);
}
// Display all eSIM profiles.
int index = 0;
for (SubscriptionInfo sub : mEmbeddedSubscriptions) {
Item item = new DisableableItem();
CharSequence title =
SubscriptionUtil.getUniqueSubscriptionDisplayName(
sub.getSubscriptionId(), this);
item.setTitle(TextUtils.isEmpty(title) ? sub.getDisplayName() : title);
if (mIsSwitching && mSelectedItemIndex == index) {
item.setSummary(getString(R.string.choose_sim_activating));
} else {
String phoneNumber = SubscriptionUtil.getFormattedPhoneNumber(this, sub);
item.setSummary(TextUtils.isEmpty(phoneNumber) ? "" : phoneNumber);
}
item.setId(index++);
mItemGroup.addChild(item);
}
// This removes the unused header artifact from GlifRecyclerLayout.
HeaderRecyclerView rv = (HeaderRecyclerView) layout.getRecyclerView();
rv.getHeader().setVisibility(View.GONE);
}
private void updateSubscriptions() {
List<SubscriptionInfo> subscriptions =
SubscriptionUtil.getSelectableSubscriptionInfoList(this);
if (subscriptions != null) {
for (SubscriptionInfo sub : subscriptions) {
if (sub == null) {
continue;
}
if (sub.isEmbedded()) {
mEmbeddedSubscriptions.add(sub);
} else {
mRemovableSubscription = sub;
}
}
}
}
private void handleEnableRemovableSimError() {
// mSelectedItemIndex will be -1 if pSIM is selected. Since pSIM is always be
// listed at index 0, we change the itemIndex to 0 if pSIM is selected.
int itemIndex = mSelectedItemIndex == INDEX_PSIM ? 0 : mSelectedItemIndex;
Item item = (Item) mItemGroup.getItemAt(itemIndex);
item.setEnabled(false);
item.setSummary(getString(R.string.choose_sim_could_not_activate));
mIsSwitching = false;
}
class DisableableItem extends Item implements Dividable {
@Override
public boolean isDividerAllowedAbove() {
return true;
}
@Override
public boolean isDividerAllowedBelow() {
return true;
}
@Override
public void onBindView(View view) {
super.onBindView(view);
TextView title = view.findViewById(R.id.sud_items_title);
TextView summary = view.findViewById(R.id.sud_items_summary);
title.setEnabled(isEnabled());
summary.setEnabled(isEnabled());
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* 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;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.settings.R;
import com.android.settings.SidecarFragment;
import com.android.settings.network.EnableMultiSimSidecar;
import com.android.settings.network.telephony.ConfirmDialogFragment;
import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
/** Activity to show the enabling DSDS dialog. */
public class DsdsDialogActivity extends SubscriptionActionDialogActivity
implements SidecarFragment.Listener, ConfirmDialogFragment.OnConfirmListener {
private static final String TAG = "DsdsDialogActivity";
// Dialog tags
private static final int DIALOG_TAG_ENABLE_DSDS_CONFIRMATION = 1;
private static final int DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION = 2;
// Number of SIMs for DSDS
private static final int NUM_OF_SIMS_FOR_DSDS = 2;
private EnableMultiSimSidecar mEnableMultiSimSidecar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mEnableMultiSimSidecar = EnableMultiSimSidecar.get(getFragmentManager());
if (savedInstanceState == null) {
showEnableDsdsConfirmDialog();
}
}
@Override
protected void onResume() {
super.onResume();
mEnableMultiSimSidecar.addListener(this);
}
@Override
protected void onPause() {
mEnableMultiSimSidecar.removeListener(this);
super.onPause();
}
@Override
public void onStateChange(SidecarFragment fragment) {
if (fragment == mEnableMultiSimSidecar) {
switch (fragment.getState()) {
case SidecarFragment.State.SUCCESS:
mEnableMultiSimSidecar.reset();
Log.i(TAG, "Enabled DSDS successfully");
dismissProgressDialog();
finish();
break;
case SidecarFragment.State.ERROR:
mEnableMultiSimSidecar.reset();
Log.e(TAG, "Failed to enable DSDS");
dismissProgressDialog();
showErrorDialog(
getString(R.string.dsds_activation_failure_title),
getString(R.string.dsds_activation_failure_body_msg2));
break;
}
}
}
@Override
public void onConfirm(int tag, boolean confirmed) {
if (!confirmed) {
Log.i(TAG, "User cancel the dialog to enable DSDS.");
startChooseSimActivity();
return;
}
TelephonyManager telephonyManager = getSystemService(TelephonyManager.class);
switch (tag) {
case DIALOG_TAG_ENABLE_DSDS_CONFIRMATION:
if (telephonyManager.doesSwitchMultiSimConfigTriggerReboot()) {
Log.i(TAG, "Device does not support reboot free DSDS.");
showRebootConfirmDialog();
return;
}
Log.i(TAG, "Enabling DSDS without rebooting.");
showProgressDialog(
getString(R.string.sim_action_enabling_sim_without_carrier_name));
mEnableMultiSimSidecar.run(NUM_OF_SIMS_FOR_DSDS);
break;
case DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION:
Log.i(TAG, "User confirmed reboot to enable DSDS.");
SimActivationNotifier.setShowSimSettingsNotification(this, true);
telephonyManager.switchMultiSimConfig(NUM_OF_SIMS_FOR_DSDS);
break;
default:
Log.e(TAG, "Unrecognized confirmation dialog tag: " + tag);
break;
}
}
private void showEnableDsdsConfirmDialog() {
ConfirmDialogFragment.show(
this,
ConfirmDialogFragment.OnConfirmListener.class,
DIALOG_TAG_ENABLE_DSDS_CONFIRMATION,
getString(R.string.sim_action_enable_dsds_title),
getString(R.string.sim_action_enable_dsds_text),
getString(R.string.sim_action_continue),
getString(R.string.sim_action_no_thanks));
}
private void showRebootConfirmDialog() {
ConfirmDialogFragment.show(
this,
ConfirmDialogFragment.OnConfirmListener.class,
DIALOG_TAG_ENABLE_DSDS_REBOOT_CONFIRMATION,
getString(R.string.sim_action_restart_title),
getString(R.string.sim_action_enable_dsds_text),
getString(R.string.sim_action_reboot),
getString(R.string.cancel));
}
private void startChooseSimActivity() {
Intent intent = ChooseSimActivity.getIntent(this);
intent.putExtra(ChooseSimActivity.KEY_HAS_PSIM, true);
startActivity(intent);
finish();
}
}

View File

@@ -26,8 +26,10 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -40,6 +42,8 @@ import com.android.settings.network.SubscriptionUtil;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nullable;
/**
* This class manages the notification of SIM activation notification including creating and
* canceling the notifications.
@@ -48,21 +52,26 @@ public class SimActivationNotifier {
private static final String TAG = "SimActivationNotifier";
private static final String SIM_SETUP_CHANNEL_ID = "sim_setup";
private static final String SWITCH_SLOT_CHANNEL_ID = "carrier_switching";
private static final String SIM_PREFS = "sim_prefs";
private static final String KEY_SHOW_SIM_SETTINGS_NOTIFICATION =
"show_sim_settings_notification";
public static final int SIM_ACTIVATION_NOTIFICATION_ID = 1;
public static final int SWITCH_TO_REMOVABLE_SLOT_NOTIFICATION_ID = 2;
/** Notification types */
@Retention(RetentionPolicy.SOURCE)
@IntDef(
value = {
NotificationType.NETWORK_CONFIG,
NotificationType.SWITCH_TO_REMOVABLE_SLOT,
})
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;
}
private final Context mContext;
@@ -104,13 +113,7 @@ public class SimActivationNotifier {
/** Sends a push notification for the SIM activation. It should be called after DSDS reboot. */
public void sendNetworkConfigNotification() {
SubscriptionManager subscriptionManager =
mContext.getSystemService(SubscriptionManager.class);
SubscriptionInfo activeRemovableSub =
SubscriptionUtil.getActiveSubscriptions(subscriptionManager).stream()
.filter(sub -> !sub.isEmbedded())
.findFirst()
.orElse(null);
SubscriptionInfo activeRemovableSub = getActiveRemovableSub();
if (activeRemovableSub == null) {
Log.e(TAG, "No removable subscriptions found. Do not show notification.");
@@ -143,4 +146,65 @@ public class SimActivationNotifier {
.setAutoCancel(true);
mNotificationManager.notify(SIM_ACTIVATION_NOTIFICATION_ID, builder.build());
}
/** Sends a push notification for switching to the removable slot. */
public void sendSwitchedToRemovableSlotNotification() {
String carrierName = getActiveCarrierName();
Intent clickIntent = new Intent(mContext, Settings.MobileNetworkListActivity.class);
TaskStackBuilder stackBuilder =
TaskStackBuilder.create(mContext).addNextIntent(clickIntent);
PendingIntent contentIntent =
stackBuilder.getPendingIntent(
0 /* requestCode */, PendingIntent.FLAG_UPDATE_CURRENT);
String titleText =
TextUtils.isEmpty(carrierName)
? mContext.getString(
R.string.switch_to_removable_notification_no_carrier_name)
: mContext.getString(
R.string.switch_to_removable_notification, carrierName);
Notification.Builder builder =
new Notification.Builder(mContext, SWITCH_SLOT_CHANNEL_ID)
.setContentTitle(titleText)
.setContentText(
mContext.getString(R.string.network_changed_notification_text))
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_sim_alert)
.setColor(
mContext.getResources()
.getColor(
R.color.homepage_generic_icon_background,
null /* theme */))
.setAutoCancel(true);
mNotificationManager.notify(SWITCH_TO_REMOVABLE_SLOT_NOTIFICATION_ID, builder.build());
}
@Nullable
private SubscriptionInfo getActiveRemovableSub() {
SubscriptionManager subscriptionManager =
mContext.getSystemService(SubscriptionManager.class);
return SubscriptionUtil.getActiveSubscriptions(subscriptionManager).stream()
.filter(sub -> !sub.isEmbedded())
.findFirst()
.orElse(null);
}
@Nullable
private String getActiveCarrierName() {
CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
TelephonyManager telManager = mContext.getSystemService(TelephonyManager.class);
String telName = telManager.getSimOperatorName();
if (configManager != null && configManager.getConfig() != null) {
boolean override =
configManager
.getConfig()
.getBoolean(CarrierConfigManager.KEY_CARRIER_NAME_OVERRIDE_BOOL);
String configName =
configManager
.getConfig()
.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING);
return override || TextUtils.isEmpty(telName) ? configName : telName;
}
return telName;
}
}

View File

@@ -35,6 +35,7 @@ public class SimNotificationService extends JobService {
/**
* Schedules a service to send SIM push notifications.
*
* @param context
* @param notificationType indicates which SIM notification to send.
*/
@@ -67,6 +68,9 @@ public class SimNotificationService extends JobService {
SimActivationNotifier.setShowSimSettingsNotification(this, false);
new SimActivationNotifier(this).sendNetworkConfigNotification();
break;
case SimActivationNotifier.NotificationType.SWITCH_TO_REMOVABLE_SLOT:
new SimActivationNotifier(this).sendSwitchedToRemovableSlotNotification();
break;
default:
Log.e(TAG, "Invalid notification type: " + notificationType);
break;

View File

@@ -0,0 +1,119 @@
/*
* 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;
import android.os.Bundle;
import android.telephony.SubscriptionInfo;
import android.util.Log;
import com.android.settings.R;
import com.android.settings.SidecarFragment;
import com.android.settings.network.SwitchToEuiccSubscriptionSidecar;
import com.android.settings.network.telephony.AlertDialogFragment;
import com.android.settings.network.telephony.ConfirmDialogFragment;
import com.android.settings.network.telephony.SubscriptionActionDialogActivity;
/**
* Starts a confirm dialog asking the user to switch to the eSIM slot/subscription. The caller needs
* to pass in the current enabled eSIM subscription, which is also the subscription to switch to.
*/
public class SwitchToEsimConfirmDialogActivity extends SubscriptionActionDialogActivity
implements SidecarFragment.Listener, ConfirmDialogFragment.OnConfirmListener {
public static final String KEY_SUB_TO_ENABLE = "sub_to_enable";
private static final String TAG = "SwitchToEsimConfirmDialogActivity";
private static final int TAG_CONFIRM = 1;
private SubscriptionInfo mSubToEnabled = null;
private SwitchToEuiccSubscriptionSidecar mSwitchToEuiccSubscriptionSidecar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSubToEnabled = getIntent().getParcelableExtra(KEY_SUB_TO_ENABLE);
mSwitchToEuiccSubscriptionSidecar =
SwitchToEuiccSubscriptionSidecar.get(getFragmentManager());
if (mSubToEnabled == null) {
Log.e(TAG, "Cannot find SIM to enable.");
finish();
return;
}
if (savedInstanceState == null) {
ConfirmDialogFragment.show(
this,
ConfirmDialogFragment.OnConfirmListener.class,
TAG_CONFIRM,
getString(R.string.switch_sim_dialog_title, mSubToEnabled.getDisplayName()),
getString(R.string.switch_sim_dialog_text, mSubToEnabled.getDisplayName()),
getString(R.string.okay),
getString(R.string.cancel));
}
}
@Override
public void onResume() {
super.onResume();
mSwitchToEuiccSubscriptionSidecar.addListener(this);
}
@Override
public void onPause() {
mSwitchToEuiccSubscriptionSidecar.removeListener(this);
super.onPause();
}
@Override
public void onStateChange(SidecarFragment fragment) {
if (fragment == mSwitchToEuiccSubscriptionSidecar) {
switch (mSwitchToEuiccSubscriptionSidecar.getState()) {
case SidecarFragment.State.SUCCESS:
mSwitchToEuiccSubscriptionSidecar.reset();
Log.i(TAG, "Successfully switched to eSIM slot.");
dismissProgressDialog();
finish();
break;
case SidecarFragment.State.ERROR:
mSwitchToEuiccSubscriptionSidecar.reset();
Log.e(TAG, "Failed switching to eSIM slot.");
dismissProgressDialog();
finish();
break;
}
}
}
@Override
public void onConfirm(int tag, boolean confirmed) {
if (!confirmed) {
AlertDialogFragment.show(
this,
getString(R.string.switch_sim_dialog_no_switch_title),
getString(R.string.switch_sim_dialog_no_switch_text));
return;
}
Log.i(TAG, "User confirmed to switch to embedded slot.");
mSwitchToEuiccSubscriptionSidecar.run(mSubToEnabled.getSubscriptionId());
showProgressDialog(
getString(
R.string.sim_action_switch_sub_dialog_progress,
mSubToEnabled.getDisplayName()));
}
}

View File

@@ -19,6 +19,7 @@ package com.android.settings.sim.receivers;
import static android.content.Context.MODE_PRIVATE;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Looper;
import android.provider.Settings;
@@ -29,6 +30,13 @@ import android.telephony.UiccSlotInfo;
import android.util.Log;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.UiccSlotUtil;
import com.android.settings.network.UiccSlotsException;
import com.android.settings.sim.ChooseSimActivity;
import com.android.settings.sim.DsdsDialogActivity;
import com.android.settings.sim.SimActivationNotifier;
import com.android.settings.sim.SimNotificationService;
import com.android.settings.sim.SwitchToEsimConfirmDialogActivity;
import com.google.common.collect.ImmutableList;
@@ -121,14 +129,13 @@ public class SimSlotChangeHandler {
return;
}
if (!hasActiveEsimSubscription()) {
if (mTelMgr.isMultiSimEnabled()) {
if (hasActiveEsimSubscription()) {
if (mTelMgr.isMultiSimSupported() == TelephonyManager.MULTISIM_ALLOWED) {
Log.i(TAG, "Enabled profile exists. DSDS condition satisfied.");
// TODO(b/170508680): Display DSDS dialog to ask users whether to enable DSDS.
startDsdsDialogActivity();
} else {
Log.i(TAG, "Enabled profile exists. DSDS condition not satisfied.");
// TODO(b/170508680): Display Choose a number to use screen for subscription
// selection.
startChooseSimActivity(true);
}
return;
}
@@ -137,7 +144,15 @@ public class SimSlotChangeHandler {
TAG,
"No enabled eSIM profile. Ready to switch to removable slot and show"
+ " notification.");
// TODO(b/170508680): Switch the slot to the removebale slot and show the notification.
try {
UiccSlotUtil.switchToRemovableSlot(
UiccSlotUtil.INVALID_PHYSICAL_SLOT_ID, mContext.getApplicationContext());
} catch (UiccSlotsException e) {
Log.e(TAG, "Failed to switch to removable slot.");
return;
}
SimNotificationService.scheduleSimNotification(
mContext, SimActivationNotifier.NotificationType.SWITCH_TO_REMOVABLE_SLOT);
}
private void handleSimRemove(UiccSlotInfo removableSlotInfo) {
@@ -160,14 +175,14 @@ public class SimSlotChangeHandler {
// profile.
if (groupedEmbeddedSubscriptions.size() == 1) {
Log.i(TAG, "Only 1 eSIM profile found. Ask user's consent to switch.");
// TODO(b/170508680): Display a dialog to ask users to switch.
startSwitchSlotConfirmDialogActivity(groupedEmbeddedSubscriptions.get(0));
return;
}
// If there are more than 1 eSIM profiles installed, we show a screen to let users to choose
// the number they want to use.
Log.i(TAG, "Multiple eSIM profiles found. Ask user which subscription to use.");
// TODO(b/170508680): Display a dialog to ask user which SIM to switch.
startChooseSimActivity(false);
}
private int getLastRemovableSimSlotState(Context context) {
@@ -225,5 +240,25 @@ public class SimSlotChangeHandler {
.collect(Collectors.toList()));
}
private void startChooseSimActivity(boolean psimInserted) {
Intent intent = ChooseSimActivity.getIntent(mContext);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(ChooseSimActivity.KEY_HAS_PSIM, psimInserted);
mContext.startActivity(intent);
}
private void startSwitchSlotConfirmDialogActivity(SubscriptionInfo subscriptionInfo) {
Intent intent = new Intent(mContext, SwitchToEsimConfirmDialogActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(SwitchToEsimConfirmDialogActivity.KEY_SUB_TO_ENABLE, subscriptionInfo);
mContext.startActivity(intent);
}
private void startDsdsDialogActivity() {
Intent intent = new Intent(mContext, DsdsDialogActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
private SimSlotChangeHandler() {}
}

View File

@@ -48,14 +48,16 @@ public class SimSlotChangeReceiver extends BroadcastReceiver {
return;
}
final PendingResult pendingResult = goAsync();
ThreadUtils.postOnBackgroundThread(
() -> {
synchronized (mLock) {
if (!shouldHandleSlotChange(context)) {
return;
}
mSlotChangeHandler.onSlotsStatusChange(context);
mSlotChangeHandler.onSlotsStatusChange(context.getApplicationContext());
}
ThreadUtils.postOnMainThread(pendingResult::finish);
});
}