From 8845af8a140bc1ab03827a6ce49fb5e0081fca5f Mon Sep 17 00:00:00 2001 From: Bonian Chen Date: Thu, 2 Jan 2020 18:59:24 +0800 Subject: [PATCH] [Settings] Replacing accessing of PhoneConstants$DataState 1. Replaced by PhoneStateListner#onPreciseDataConnectionStateChanged(). 2. Remove usage of hidden API SubscriptionManager#getPhoneId() Bug: 147080692 Test: manual Change-Id: I6e7c9910ed63e027fc02c1835853175745b31b66 --- .../android/settings/network/ApnSettings.java | 70 ++++--- .../settings/network/SubscriptionUtil.java | 195 +++++++++++++++++- 2 files changed, 229 insertions(+), 36 deletions(-) diff --git a/src/com/android/settings/network/ApnSettings.java b/src/com/android/settings/network/ApnSettings.java index 94d7bca6fe8..eb6c9b1181c 100755 --- a/src/com/android/settings/network/ApnSettings.java +++ b/src/com/android/settings/network/ApnSettings.java @@ -38,6 +38,8 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Telephony; import android.telephony.CarrierConfigManager; +import android.telephony.PhoneStateListener; +import android.telephony.PreciseDataConnectionState; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -52,8 +54,6 @@ import android.widget.Toast; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; import com.android.settings.R; import com.android.settings.RestrictedSettingsFragment; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; @@ -107,6 +107,7 @@ public class ApnSettings extends RestrictedSettingsFragment private static boolean mRestoreDefaultApnMode; private UserManager mUserManager; + private TelephonyManager mTelephonyManager; private RestoreApnUiHandler mRestoreApnUiHandler; private RestoreApnProcessHandler mRestoreApnProcessHandler; private HandlerThread mRestoreDefaultApnThread; @@ -130,32 +131,35 @@ public class ApnSettings extends RestrictedSettingsFragment super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); } + private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { + @Override + public void onPreciseDataConnectionStateChanged( + PreciseDataConnectionState dataConnectionState) { + if (dataConnectionState.getState() == TelephonyManager.DATA_CONNECTED) { + if (!mRestoreDefaultApnMode) { + fillList(); + } else { + showDialog(DIALOG_RESTORE_DEFAULTAPN); + } + } + } + }; + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals( - TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { - PhoneConstants.DataState state = getMobileDataState(intent); - switch (state) { - case CONNECTED: - if (!mRestoreDefaultApnMode) { - fillList(); - } else { - showDialog(DIALOG_RESTORE_DEFAULTAPN); - } - break; - } - } else if(intent.getAction().equals( TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED)) { if (!mRestoreDefaultApnMode) { int extraSubId = intent.getIntExtra(TelephonyManager.EXTRA_SUBSCRIPTION_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); - if (SubscriptionManager.isValidSubscriptionId(extraSubId) && - mPhoneId == SubscriptionManager.getPhoneId(extraSubId) && - extraSubId != mSubId) { + if (SubscriptionManager.isValidSubscriptionId(extraSubId) + && mPhoneId == SubscriptionUtil.getPhoneId(context, extraSubId) + && extraSubId != mSubId) { // subscription has changed mSubId = extraSubId; mSubscriptionInfo = getSubscriptionInfo(mSubId); + restartPhoneStateListener(mSubId); } fillList(); } @@ -163,13 +167,22 @@ public class ApnSettings extends RestrictedSettingsFragment } }; - private static PhoneConstants.DataState getMobileDataState(Intent intent) { - String str = intent.getStringExtra(PhoneConstants.STATE_KEY); - if (str != null) { - return Enum.valueOf(PhoneConstants.DataState.class, str); - } else { - return PhoneConstants.DataState.DISCONNECTED; + private void restartPhoneStateListener(int subId) { + if (mRestoreDefaultApnMode) { + return; } + + final TelephonyManager updatedTelephonyManager = + mTelephonyManager.createForSubscriptionId(subId); + + // restart monitoring when subscription has been changed + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_NONE); + + mTelephonyManager = updatedTelephonyManager; + + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE); } @Override @@ -183,14 +196,14 @@ public class ApnSettings extends RestrictedSettingsFragment final Activity activity = getActivity(); mSubId = activity.getIntent().getIntExtra(SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mPhoneId = SubscriptionManager.getPhoneId(mSubId); + mPhoneId = SubscriptionUtil.getPhoneId(activity, mSubId); mIntentFilter = new IntentFilter( - TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - mIntentFilter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED); + TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED); setIfOnlyAvailableForAdmins(true); mSubscriptionInfo = getSubscriptionInfo(mSubId); + mTelephonyManager = activity.getSystemService(TelephonyManager.class); CarrierConfigManager configManager = (CarrierConfigManager) getSystemService(Context.CARRIER_CONFIG_SERVICE); @@ -235,6 +248,8 @@ public class ApnSettings extends RestrictedSettingsFragment getActivity().registerReceiver(mReceiver, mIntentFilter); + restartPhoneStateListener(mSubId); + if (!mRestoreDefaultApnMode) { fillList(); } @@ -249,6 +264,9 @@ public class ApnSettings extends RestrictedSettingsFragment } getActivity().unregisterReceiver(mReceiver); + + mTelephonyManager.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_NONE); } @Override diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java index 9007c0b4cc9..f0c1583887f 100644 --- a/src/com/android/settings/network/SubscriptionUtil.java +++ b/src/com/android/settings/network/SubscriptionUtil.java @@ -16,15 +16,18 @@ package com.android.settings.network; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT; import static com.android.internal.util.CollectionUtils.emptyIfNull; import android.content.Context; +import android.os.ParcelUuid; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.UiccSlotInfo; +import android.text.TextUtils; import androidx.annotation.VisibleForTesting; @@ -66,6 +69,12 @@ public class SubscriptionUtil { slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT; } + /** + * Get all of the subscriptions which is available to display to the user. + * + * @param context {@code Context} + * @return list of {@code SubscriptionInfo} + */ public static List getAvailableSubscriptions(Context context) { if (sAvailableResultsForTesting != null) { return sAvailableResultsForTesting; @@ -73,12 +82,12 @@ public class SubscriptionUtil { final SubscriptionManager subMgr = context.getSystemService(SubscriptionManager.class); final TelephonyManager telMgr = context.getSystemService(TelephonyManager.class); - List subscriptions = + final List subscriptions = new ArrayList<>(emptyIfNull(subMgr.getSelectableSubscriptionInfoList())); // Look for inactive but present physical SIMs that are missing from the selectable list. final List missing = new ArrayList<>(); - UiccSlotInfo[] slotsInfo = telMgr.getUiccSlotsInfo(); + final UiccSlotInfo[] slotsInfo = telMgr.getUiccSlotsInfo(); for (int i = 0; slotsInfo != null && i < slotsInfo.length; i++) { final UiccSlotInfo slotInfo = slotsInfo[i]; if (isInactiveInsertedPSim(slotInfo)) { @@ -92,20 +101,164 @@ public class SubscriptionUtil { } } } - if (!missing.isEmpty()) { - for (SubscriptionInfo info : subMgr.getAllSubscriptionInfoList()) { - for (UiccSlotInfo slotInfo : missing) { - if (info.getSimSlotIndex() == slotInfo.getLogicalSlotIdx() && - info.getCardString().equals(slotInfo.getCardId())) { - subscriptions.add(info); - break; - } + if (missing.isEmpty()) { + return subscriptions; + } + for (SubscriptionInfo info : subMgr.getAllSubscriptionInfoList()) { + for (UiccSlotInfo slotInfo : missing) { + if (info.getSimSlotIndex() == slotInfo.getLogicalSlotIdx() + && info.getCardString().equals(slotInfo.getCardId())) { + subscriptions.add(info); + break; } } } return subscriptions; } + /** + * Get subscription which is available to be displayed to the user + * per subscription id. + * + * @param context {@code Context} + * @param subscriptionManager The ProxySubscriptionManager for accessing subcription + * information + * @param subId The id of subscription to be retrieved + * @return {@code SubscriptionInfo} based on the given subscription id. Null of subscription + * is invalid or not allowed to be displayed to the user. + */ + public static SubscriptionInfo getAvailableSubscription(Context context, + ProxySubscriptionManager subscriptionManager, int subId) { + final SubscriptionInfo subInfo = subscriptionManager.getAccessibleSubscriptionInfo(subId); + if (subInfo == null) { + return null; + } + + final ParcelUuid groupUuid = subInfo.getGroupUuid(); + + if (groupUuid != null) { + if (isPrimarySubscriptionWithinSameUuid(getUiccSlotsInfo(context), groupUuid, + subscriptionManager.getAccessibleSubscriptionsInfo(), subId)) { + return subInfo; + } + return null; + } + + if (subInfo.isEmbedded()) { + return subInfo; + } + + // Look for physical SIM which presented in slots no mater active or not. + final UiccSlotInfo[] slotsInfo = getUiccSlotsInfo(context); + if (slotsInfo == null) { + return null; + } + for (UiccSlotInfo slotInfo : slotsInfo) { + if ((!slotInfo.getIsEuicc()) + && (slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT) + && (slotInfo.getLogicalSlotIdx() == subInfo.getSimSlotIndex()) + && TextUtils.equals(slotInfo.getCardId(), subInfo.getCardString())) { + return subInfo; + } + } + return null; + } + + private static UiccSlotInfo [] getUiccSlotsInfo(Context context) { + final TelephonyManager telMgr = context.getSystemService(TelephonyManager.class); + return telMgr.getUiccSlotsInfo(); + } + + private static boolean isPrimarySubscriptionWithinSameUuid(UiccSlotInfo[] slotsInfo, + ParcelUuid groupUuid, List subscriptions, int subId) { + // only interested in subscriptions with this group UUID + final ArrayList physicalSubInfoList = + new ArrayList(); + final ArrayList nonOpportunisticSubInfoList = + new ArrayList(); + final ArrayList activeSlotSubInfoList = + new ArrayList(); + final ArrayList inactiveSlotSubInfoList = + new ArrayList(); + for (SubscriptionInfo subInfo : subscriptions) { + if (groupUuid.equals(subInfo.getGroupUuid())) { + if (!subInfo.isEmbedded()) { + physicalSubInfoList.add(subInfo); + } else { + if (!subInfo.isOpportunistic()) { + nonOpportunisticSubInfoList.add(subInfo); + } + if (subInfo.getSimSlotIndex() + != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + activeSlotSubInfoList.add(subInfo); + } else { + inactiveSlotSubInfoList.add(subInfo); + } + } + } + } + + // find any physical SIM which is currently inserted within logical slot + // and which is our target subscription + if ((slotsInfo != null) && (physicalSubInfoList.size() > 0)) { + final SubscriptionInfo subInfo = searchForSubscriptionId(physicalSubInfoList, subId); + if (subInfo == null) { + return false; + } + // verify if subscription is inserted within slot + for (UiccSlotInfo slotInfo : slotsInfo) { + if ((slotInfo != null) && (!slotInfo.getIsEuicc()) + && (slotInfo.getCardStateInfo() == CARD_STATE_INFO_PRESENT) + && (slotInfo.getLogicalSlotIdx() == subInfo.getSimSlotIndex()) + && TextUtils.equals(slotInfo.getCardId(), subInfo.getCardString())) { + return true; + } + } + return false; + } + + // When all of the eSIM profiles are opprtunistic and no physical SIM, + // first opportunistic subscriptions with same group UUID can be primary. + if (nonOpportunisticSubInfoList.size() <= 0) { + if (physicalSubInfoList.size() > 0) { + return false; + } + if (activeSlotSubInfoList.size() > 0) { + return (activeSlotSubInfoList.get(0).getSubscriptionId() == subId); + } + return (inactiveSlotSubInfoList.get(0).getSubscriptionId() == subId); + } + + // Allow non-opportunistic + active eSIM subscription as primary + int numberOfActiveNonOpportunisticSubs = 0; + boolean isTargetNonOpportunistic = false; + for (SubscriptionInfo subInfo : nonOpportunisticSubInfoList) { + final boolean isTargetSubInfo = (subInfo.getSubscriptionId() == subId); + if (subInfo.getSimSlotIndex() != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { + if (isTargetSubInfo) { + return true; + } + numberOfActiveNonOpportunisticSubs++; + } else { + isTargetNonOpportunistic |= isTargetSubInfo; + } + } + if (numberOfActiveNonOpportunisticSubs > 0) { + return false; + } + return isTargetNonOpportunistic; + } + + private static SubscriptionInfo searchForSubscriptionId(List subInfoList, + int subscriptionId) { + for (SubscriptionInfo subInfo : subInfoList) { + if (subInfo.getSubscriptionId() == subscriptionId) { + return subInfo; + } + } + return null; + } + public static String getDisplayName(SubscriptionInfo info) { final CharSequence name = info.getDisplayName(); if (name != null) { @@ -113,4 +266,26 @@ public class SubscriptionUtil { } return ""; } + + /** + * Whether Settings should show a "Use SIM" toggle in pSIM detailed page. + */ + public static boolean showToggleForPhysicalSim(SubscriptionManager subMgr) { + return subMgr.canDisablePhysicalSubscription(); + } + + /** + * Get phoneId or logical slot index for a subId if active, or INVALID_PHONE_INDEX if inactive. + */ + public static int getPhoneId(Context context, int subId) { + final SubscriptionManager subManager = context.getSystemService(SubscriptionManager.class); + if (subManager == null) { + return INVALID_SIM_SLOT_INDEX; + } + final SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId); + if (info == null) { + return INVALID_SIM_SLOT_INDEX; + } + return info.getSimSlotIndex(); + } }