diff options
-rw-r--r-- | AndroidManifest.xml | 9 | ||||
-rw-r--r-- | src/com/android/settings/sim/receivers/SimSlotChangeHandler.java | 224 | ||||
-rw-r--r-- | src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java | 143 |
3 files changed, 0 insertions, 376 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 443e8f60836..66f72075661 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3571,15 +3571,6 @@ android:value="com.android.settings.sound.MediaControlsSettings" /> </activity> - <receiver android:name=".sim.receivers.SimSlotChangeReceiver" - android:permission="com.qualcomm.permission.USE_QCRIL_MSG_TUNNEL" - android:exported="true"> - <intent-filter> - <action android:name="qualcomm.intent.action.ACTION_SLOT_STATUS_CHANGED_IND" /> - <action android:name="android.telephony.action.SIM_SLOT_STATUS_CHANGED" /> - </intent-filter> - </receiver> - <!-- This is the longest AndroidManifest.xml ever. --> </application> </manifest> diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java b/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java deleted file mode 100644 index ea659e1baf8..00000000000 --- a/src/com/android/settings/sim/receivers/SimSlotChangeHandler.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2020 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 static android.content.Context.MODE_PRIVATE; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Looper; -import android.os.SystemProperties; -import android.telephony.SubscriptionInfo; -import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; -import android.telephony.UiccSlotInfo; -import android.util.Log; - -import com.android.settings.network.SubscriptionUtil; - -import com.google.common.collect.ImmutableList; - -import java.util.List; -import java.util.stream.Collectors; - -import javax.annotation.Nullable; - -/** Perform actions after a slot change event is triggered. */ -public class SimSlotChangeHandler { - private static final String TAG = "SimSlotChangeHandler"; - - private static final String SYSTEM_PROPERTY_DEVICE_PROVISIONED = - "persist.sys.device_provisioned"; - - private static final String EUICC_PREFS = "euicc_prefs"; - private static final String KEY_REMOVABLE_SLOT_STATE = "removable_slot_state"; - - private static volatile SimSlotChangeHandler sSlotChangeHandler; - - /** Returns a SIM slot change handler singleton. */ - public static SimSlotChangeHandler get() { - if (sSlotChangeHandler == null) { - synchronized (SimSlotChangeHandler.class) { - if (sSlotChangeHandler == null) { - sSlotChangeHandler = new SimSlotChangeHandler(); - } - } - } - return sSlotChangeHandler; - } - - private SubscriptionManager mSubMgr; - private TelephonyManager mTelMgr; - private Context mContext; - private boolean mNotificationEnabled = true; - - void onSlotsStatusChange(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; - } - - int lastRemovableSlotState = getLastRemovableSimSlotState(mContext); - int currentRemovableSlotState = removableSlotInfo.getCardStateInfo(); - - // Sets the current removable slot state. - setRemovableSimSlotState(mContext, currentRemovableSlotState); - - if (lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT - && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT) { - handleSimInsert(removableSlotInfo); - return; - } - if (lastRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_PRESENT - && currentRemovableSlotState == UiccSlotInfo.CARD_STATE_INFO_ABSENT) { - handleSimRemove(removableSlotInfo); - return; - } - Log.i(TAG, "Do nothing on slot status changes."); - } - - private void init(Context context) { - mSubMgr = - (SubscriptionManager) - context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); - mTelMgr = context.getSystemService(TelephonyManager.class); - mContext = context; - } - - private void handleSimInsert(UiccSlotInfo removableSlotInfo) { - Log.i(TAG, "Detect SIM inserted."); - - if (!isSuwFinished()) { - // TODO: Store the action and handle it after SUW is finished. - Log.i(TAG, "Still in SUW. Handle SIM insertion after SUW is finished"); - return; - } - - if (removableSlotInfo.getIsActive()) { - Log.i(TAG, "The removable slot is already active. Do nothing."); - return; - } - - if (!hasActiveEsimSubscription()) { - if (mTelMgr.isMultiSimEnabled()) { - Log.i(TAG, "Enabled profile exists. DSDS condition satisfied."); - // TODO Display DSDS dialog to ask users whether to enable DSDS. - } else { - Log.i(TAG, "Enabled profile exists. DSDS condition not satisfied."); - // TODO Display Choose a number to use screen for subscription selection. - } - return; - } - - Log.i( - TAG, - "No enabled eSIM profile. Ready to switch to removable slot and show" - + " notification."); - // TODO Switch the slot to the removebale slot and show the notification. - } - - private void handleSimRemove(UiccSlotInfo removableSlotInfo) { - Log.i(TAG, "Detect SIM removed."); - - if (!isSuwFinished()) { - // TODO: Store the action and handle it after SUW is finished. - Log.i(TAG, "Still in SUW. Handle SIM removal after SUW is finished"); - return; - } - - List<SubscriptionInfo> groupedEmbeddedSubscriptions = getGroupedEmbeddedSubscriptions(); - - if (groupedEmbeddedSubscriptions.size() == 0 || !removableSlotInfo.getIsActive()) { - Log.i(TAG, "eSIM slot is active or no subscriptions exist. Do nothing."); - return; - } - - // If there is only 1 eSIM profile exists, we ask the user if they want to switch to that - // profile. - if (groupedEmbeddedSubscriptions.size() == 1) { - Log.i(TAG, "Only 1 eSIM profile found. Ask user's consent to switch."); - // TODO Display a dialog to ask users to switch. - 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 Display a dialog to ask user which SIM to switch. - } - - private int getLastRemovableSimSlotState(Context context) { - final SharedPreferences prefs = context.getSharedPreferences(EUICC_PREFS, MODE_PRIVATE); - return prefs.getInt(KEY_REMOVABLE_SLOT_STATE, UiccSlotInfo.CARD_STATE_INFO_ABSENT); - } - - private void setRemovableSimSlotState(Context context, int state) { - final SharedPreferences prefs = context.getSharedPreferences(EUICC_PREFS, MODE_PRIVATE); - prefs.edit().putInt(KEY_REMOVABLE_SLOT_STATE, state).apply(); - } - - @Nullable - private UiccSlotInfo getRemovableUiccSlotInfo() { - UiccSlotInfo[] slotInfos = mTelMgr.getUiccSlotsInfo(); - if (slotInfos == null) { - Log.e(TAG, "slotInfos is null. Unable to get slot infos."); - return null; - } - for (UiccSlotInfo slotInfo : slotInfos) { - if (slotInfo != null && slotInfo.isRemovable()) { - - return slotInfo; - } - } - return null; - } - - private boolean isSuwFinished() { - return "1".equals(SystemProperties.get(SYSTEM_PROPERTY_DEVICE_PROVISIONED, "0")); - } - - private boolean hasActiveEsimSubscription() { - List<SubscriptionInfo> activeSubs = SubscriptionUtil.getActiveSubscriptions(mSubMgr); - return activeSubs.stream().anyMatch(SubscriptionInfo::isEmbedded); - } - - private List<SubscriptionInfo> getGroupedEmbeddedSubscriptions() { - List<SubscriptionInfo> groupedSubscriptions = - SubscriptionUtil.getSelectableSubscriptionInfoList(mContext); - if (groupedSubscriptions == null) { - return ImmutableList.of(); - } - return ImmutableList.copyOf( - groupedSubscriptions.stream() - .filter(sub -> sub.isEmbedded()) - .collect(Collectors.toList())); - } - - private SimSlotChangeHandler() {} -} diff --git a/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java b/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java deleted file mode 100644 index 440d3a4f8ac..00000000000 --- a/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2020 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.telephony.TelephonyManager; -import android.telephony.UiccCardInfo; -import android.telephony.UiccSlotInfo; -import android.telephony.euicc.EuiccManager; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.Nullable; - -import com.android.settingslib.utils.ThreadUtils; - -import java.util.List; - -/** The receiver when the slot status changes. */ -public class SimSlotChangeReceiver extends BroadcastReceiver { - private static final String TAG = "SlotChangeReceiver"; - - private static final String SLOT_CHANGE_ACTION_QC = - "qualcomm.intent.action.ACTION_SLOT_STATUS_CHANGED_IND"; - - private final SimSlotChangeHandler mSlotChangeHandler = SimSlotChangeHandler.get(); - private final Object mLock = new Object(); - - @Override - public void onReceive(Context context, Intent intent) { - - String action = intent.getAction(); - if (!TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED.equals(action) - && !SLOT_CHANGE_ACTION_QC.equals(action)) { - Log.e(TAG, "Ignore slot changes due to unexpected action: " + action); - return; - } - - ThreadUtils.postOnBackgroundThread( - () -> { - synchronized (mLock) { - if (!shouldHandleSlotChange(context)) { - return; - } - mSlotChangeHandler.onSlotsStatusChange(context); - } - }); - } - - // Checks whether the slot event should be handled. - private boolean shouldHandleSlotChange(Context context) { - final EuiccManager euiccManager = context.getSystemService(EuiccManager.class); - if (euiccManager == null || !euiccManager.isEnabled()) { - Log.i(TAG, "Ignore slot changes because EuiccManager is disabled."); - return false; - } - - if (euiccManager.getOtaStatus() == EuiccManager.EUICC_OTA_IN_PROGRESS) { - Log.i(TAG, "Ignore slot changes because eSIM OTA is in progress."); - return false; - } - - if (!isSimSlotStateValid(context)) { - Log.i(TAG, "Ignore slot changes because SIM states are not valid."); - return false; - } - - return true; - } - - // Checks whether the SIM slot state is valid for slot change event. - private boolean isSimSlotStateValid(Context context) { - final TelephonyManager telMgr = context.getSystemService(TelephonyManager.class); - UiccSlotInfo[] slotInfos = telMgr.getUiccSlotsInfo(); - if (slotInfos == null) { - Log.e(TAG, "slotInfos is null. Unable to get slot infos."); - return false; - } - - boolean isAllCardStringsEmpty = true; - for (int i = 0; i < slotInfos.length; i++) { - UiccSlotInfo slotInfo = slotInfos[i]; - - if (slotInfo == null) { - return false; - } - - // After pSIM is inserted, there might be a short period that the status of both slots - // are not accurate. We drop the event if any of sim presence state is ERROR or - // RESTRICTED. - if (slotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_ERROR - || slotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) { - Log.i(TAG, "The SIM state is in an error. Drop the event. SIM info: " + slotInfo); - return false; - } - - UiccCardInfo cardInfo = findUiccCardInfoBySlot(telMgr, i); - if (cardInfo == null) { - continue; - } - if (!TextUtils.isEmpty(slotInfo.getCardId()) - || !TextUtils.isEmpty(cardInfo.getIccId())) { - isAllCardStringsEmpty = false; - } - } - - // We also drop the event if both the card strings are empty, which usually means it's - // between SIM slots switch the slot status is not stable at this moment. - if (isAllCardStringsEmpty) { - Log.i(TAG, "All UICC card strings are empty. Drop this event."); - return false; - } - - return true; - } - - @Nullable - private UiccCardInfo findUiccCardInfoBySlot(TelephonyManager telMgr, int physicalSlotIndex) { - List<UiccCardInfo> cardInfos = telMgr.getUiccCardsInfo(); - if (cardInfos == null) { - return null; - } - return cardInfos.stream() - .filter(info -> info.getSlotIndex() == physicalSlotIndex) - .findFirst() - .orElse(null); - } -} |