• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.network;
18 
19 import android.app.FragmentManager;
20 import android.os.Bundle;
21 import android.telephony.SubscriptionInfo;
22 import android.telephony.SubscriptionManager;
23 import android.util.Log;
24 
25 import com.android.settings.SidecarFragment;
26 import com.android.settings.network.telephony.EuiccOperationSidecar;
27 
28 /**
29  * This sidecar is responsible for switching to the removable slot. It disables the active eSIM
30  * profile before switching if there is one.
31  */
32 public class SwitchToRemovableSlotSidecar extends EuiccOperationSidecar
33         implements SidecarFragment.Listener {
34     private static final String TAG = "SwitchRemovableSidecar";
35     private static final String ACTION_DISABLE_SUBSCRIPTION_AND_SWITCH_SLOT =
36             "disable_subscription_and_switch_slot_sidecar";
37 
38     // Stateless members.
39     private SwitchToEuiccSubscriptionSidecar mSwitchToSubscriptionSidecar;
40     private int mPhysicalSlotId;
41     private SubscriptionInfo mRemovedSubInfo;
42 
43     /** Returns a SwitchToRemovableSlotSidecar sidecar instance. */
get(FragmentManager fm)44     public static SwitchToRemovableSlotSidecar get(FragmentManager fm) {
45         return SidecarFragment.get(fm, TAG, SwitchToRemovableSlotSidecar.class, null /* args */);
46     }
47 
48     @Override
onCreate(Bundle savedInstanceState)49     public void onCreate(Bundle savedInstanceState) {
50         super.onCreate(savedInstanceState);
51         mSwitchToSubscriptionSidecar =
52                 SwitchToEuiccSubscriptionSidecar.get(getChildFragmentManager());
53     }
54 
55     @Override
onResume()56     public void onResume() {
57         super.onResume();
58         mSwitchToSubscriptionSidecar.addListener(this);
59     }
60 
61     @Override
onPause()62     public void onPause() {
63         mSwitchToSubscriptionSidecar.removeListener(this);
64         super.onPause();
65     }
66 
67     @Override
getReceiverAction()68     protected String getReceiverAction() {
69         return ACTION_DISABLE_SUBSCRIPTION_AND_SWITCH_SLOT;
70     }
71 
72     @Override
onStateChange(SidecarFragment fragment)73     public void onStateChange(SidecarFragment fragment) {
74         if (fragment == mSwitchToSubscriptionSidecar) {
75             onSwitchToSubscriptionSidecarStateChange();
76         } else if (fragment == mSwitchSlotSidecar) {
77             onSwitchSlotSidecarStateChange();
78         } else {
79             Log.wtf(TAG, "Received state change from a sidecar not expected.");
80         }
81     }
82 
83     /**
84      * Starts switching to the removable slot.
85      *
86      * @param physicalSlotId removable physical SIM slot ID.
87      * @param removedSubInfo if the all of slots have sims, it should remove the one of active sim.
88      *                       If the removedSubInfo is null, then use the default value.
89      *                       The default value is the removable physical SIM slot and portId 0.
90      */
run(int physicalSlotId, SubscriptionInfo removedSubInfo)91     public void run(int physicalSlotId, SubscriptionInfo removedSubInfo) {
92         mPhysicalSlotId = physicalSlotId;
93         mRemovedSubInfo = removedSubInfo;
94         SubscriptionManager subscriptionManager =
95                 getContext().getSystemService(SubscriptionManager.class).createForAllUserProfiles();
96         if (!mTelephonyManager.isMultiSimEnabled()
97                 && SubscriptionUtil.getActiveSubscriptions(subscriptionManager).stream().anyMatch(
98                 SubscriptionInfo::isEmbedded)) {
99             // In SS mode, the esim is active, then inactivate the esim.
100             Log.i(TAG, "There is an active eSIM profile. Disable the profile first.");
101             // Use INVALID_SUBSCRIPTION_ID to disable the only active profile.
102             mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID, 0, null);
103         } else if (mTelephonyManager.isMultiSimEnabled() && mRemovedSubInfo != null) {
104             // In DSDS mode+MEP, if the replaced esim is active, then it should disable that esim
105             // profile before changing SimSlotMapping process.
106             // Use INVALID_SUBSCRIPTION_ID to disable the esim profile.
107             mSwitchToSubscriptionSidecar.run(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
108                     mRemovedSubInfo.getPortIndex(), null);
109         } else {
110             Log.i(TAG, "Start to switch to removable slot.");
111             mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, mRemovedSubInfo);
112         }
113     }
114 
onSwitchToSubscriptionSidecarStateChange()115     private void onSwitchToSubscriptionSidecarStateChange() {
116         switch (mSwitchToSubscriptionSidecar.getState()) {
117             case State.SUCCESS:
118                 mSwitchToSubscriptionSidecar.reset();
119                 Log.i(TAG,
120                         "Successfully disabled eSIM profile. Start to switch to Removable slot.");
121                 mSwitchSlotSidecar.runSwitchToRemovableSlot(mPhysicalSlotId, mRemovedSubInfo);
122                 break;
123             case State.ERROR:
124                 mSwitchToSubscriptionSidecar.reset();
125                 Log.i(TAG, "Failed to disable the active eSIM profile.");
126                 setState(State.ERROR, Substate.UNUSED);
127                 break;
128         }
129     }
130 
onSwitchSlotSidecarStateChange()131     private void onSwitchSlotSidecarStateChange() {
132         switch (mSwitchSlotSidecar.getState()) {
133             case State.SUCCESS:
134                 mSwitchSlotSidecar.reset();
135                 Log.i(TAG, "Successfully switched to removable slot.");
136                 setState(State.SUCCESS, Substate.UNUSED);
137                 break;
138             case State.ERROR:
139                 mSwitchSlotSidecar.reset();
140                 Log.i(TAG, "Failed to switch to removable slot.");
141                 setState(State.ERROR, Substate.UNUSED);
142                 break;
143         }
144     }
145 }
146