Loading src/java/com/android/internal/telephony/PhoneSwitcher.java +4 −0 Original line number Diff line number Diff line Loading @@ -758,11 +758,15 @@ public class PhoneSwitcher extends Handler { int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId) ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID; // Currently we assume multi-SIM devices will only support one Internet PDN connection. So // if Internet PDN is established on the non-preferred phone, it will interrupt // Internet connection on the preferred phone. So we only accept Internet request with // preferred data subscription or no specified subscription. // One exception is, if it's restricted request (doesn't have NET_CAPABILITY_NOT_RESTRICTED) // it will be accepted, which is used temporary data usage from system. if (netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) && subId != preferredDataSubId && subId != mValidator.getSubIdInValidation()) { // Returning INVALID_PHONE_INDEX will result in netRequest not being handled. return INVALID_PHONE_INDEX; Loading src/java/com/android/internal/telephony/ServiceStateTracker.java +18 −4 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ import android.telephony.PhysicalChannelConfig; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; Loading Loading @@ -1995,11 +1996,16 @@ public class ServiceStateTracker extends Handler { NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); NetworkRegistrationInfo wwanPsRegState = serviceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); // Check if any APN is preferred on IWLAN. boolean isIwlanPreferred = mTransportManager.isAnyApnPreferredOnIwlan(); serviceState.setIwlanPreferred(isIwlanPreferred); if (wlanPsRegState != null && wlanPsRegState.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN && wlanPsRegState.getRegistrationState() == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { == NetworkRegistrationInfo.REGISTRATION_STATE_HOME && isIwlanPreferred) { serviceState.setDataRegState(ServiceState.STATE_IN_SERVICE); } else if (wwanPsRegState != null) { // If the device is not camped on IWLAN, then we use cellular PS registration state Loading Loading @@ -4007,17 +4013,25 @@ public class ServiceStateTracker extends Handler { loge("cannot setNotification on invalid subid mSubId=" + mSubId); return; } Context context = mPhone.getContext(); SubscriptionInfo info = mSubscriptionController .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName()); //if subscription is part of a group and non-primary, suppress all notifications if (info == null || (info.isOpportunistic() && info.getGroupUuid() != null)) { log("cannot setNotification on invisible subid mSubId=" + mSubId); return; } // Needed because sprout RIL sends these when they shouldn't? boolean isSetNotification = mPhone.getContext().getResources().getBoolean( boolean isSetNotification = context.getResources().getBoolean( com.android.internal.R.bool.config_user_notification_of_restrictied_mobile_access); if (!isSetNotification) { if (DBG) log("Ignore all the notifications"); return; } Context context = mPhone.getContext(); boolean autoCancelCsRejectNotification = false; PersistableBundle bundle = getCarrierConfig(); Loading src/java/com/android/internal/telephony/SubscriptionController.java +16 −4 Original line number Diff line number Diff line Loading @@ -1560,10 +1560,14 @@ public class SubscriptionController extends ISub.Stub { final long identity = Binder.clearCallingIdentity(); try { validateSubId(subId); for (SubscriptionInfo subInfo : mCacheActiveSubInfoList) { List<SubscriptionInfo> allSubInfo = getSubInfo(null, null); // if there is no sub in the db, return 0 since subId does not exist in db if (allSubInfo == null || allSubInfo.isEmpty()) return 0; for (SubscriptionInfo subInfo : allSubInfo) { if (subInfo.getSubscriptionId() == subId && getNameSourcePriority(subInfo.getNameSource()) > getNameSourcePriority(nameSource)) { && (getNameSourcePriority(subInfo.getNameSource()) > getNameSourcePriority(nameSource) || (displayName != null && displayName.equals(subInfo.getDisplayName())))) { return 0; } } Loading Loading @@ -2930,8 +2934,10 @@ public class SubscriptionController extends ISub.Stub { Binder.restoreCallingIdentity(identity); } // If the group does not exist, then by default the UUID is up for grabs so no need to // restrict management of a group (that someone may be attempting to create). if (ArrayUtils.isEmpty(infoList)) { throw new IllegalArgumentException("No subscription in group " + groupUuid); return true; } // If the calling package is the group owner, skip carrier permission check and return Loading Loading @@ -2973,6 +2979,12 @@ public class SubscriptionController extends ISub.Stub { throw new IllegalArgumentException("Invalid groupUuid"); } // TODO: Revisit whether we need this restriction in R. There's no technical need for it, // but we don't want to change the API behavior at this time. if (getSubscriptionsInGroup(groupUuid, callingPackage).isEmpty()) { throw new IllegalArgumentException("Cannot add subscriptions to a non-existent group!"); } // Makes sure calling package matches caller UID. mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); // If it doesn't have modify phone state permission, or carrier privilege permission, Loading src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +104 −37 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ import com.android.internal.telephony.uicc.UiccSlot; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -113,12 +112,26 @@ public class SubscriptionInfoUpdater extends Handler { private EuiccManager mEuiccManager; @UnsupportedAppUsage private IPackageManager mPackageManager; private Handler mBackgroundHandler; // The current foreground user ID. @UnsupportedAppUsage private int mCurrentlyActiveUserId; private CarrierServiceBindHelper mCarrierServiceBindHelper; /** * Runnable with a boolean parameter. This is used in * updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback). */ private interface UpdateEmbeddedSubsCallback { /** * Callback of the Runnable. * @param hasChanges Whether there is any subscription info change. If yes, we need to * notify the listeners. */ void run(boolean hasChanges); } // TODO: The SubscriptionController instance should be passed in here from PhoneFactory // rather than invoking the static getter all over the place. public SubscriptionInfoUpdater( Loading @@ -130,8 +143,8 @@ public class SubscriptionInfoUpdater extends Handler { @VisibleForTesting public SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci, IPackageManager packageMgr) { super(looper); logd("Constructor invoked"); mBackgroundHandler = new Handler(looper); mContext = context; mPhone = phone; Loading Loading @@ -228,6 +241,7 @@ public class SubscriptionInfoUpdater extends Handler { @Override public void handleMessage(Message msg) { List<Integer> cardIds = new ArrayList<>(); switch (msg.what) { case EVENT_GET_NETWORK_SELECTION_MODE_DONE: { AsyncResult ar = (AsyncResult)msg.obj; Loading Loading @@ -279,6 +293,12 @@ public class SubscriptionInfoUpdater extends Handler { break; case EVENT_SIM_READY: cardIds.add(getCardIdFromPhoneId(msg.arg1)); updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } }); broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null); broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT); broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); Loading @@ -289,22 +309,27 @@ public class SubscriptionInfoUpdater extends Handler { break; case EVENT_SIM_NOT_READY: handleSimNotReady(msg.arg1); int cardId = getCardIdFromPhoneId(msg.arg1); // an eUICC with no active subscriptions never becomes ready, so we need to trigger // the embedded subscriptions update here if (updateEmbeddedSubscriptions(cardId)) { cardIds.add(getCardIdFromPhoneId(msg.arg1)); updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } }); handleSimNotReady(msg.arg1); break; case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS: if (updateEmbeddedSubscriptions(msg.arg1)) { cardIds.add(msg.arg1); updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } if (msg.obj != null) { ((Runnable) msg.obj).run(); } }); break; default: Loading Loading @@ -353,7 +378,7 @@ public class SubscriptionInfoUpdater extends Handler { logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId); } updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason); broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT); Loading Loading @@ -387,7 +412,7 @@ public class SubscriptionInfoUpdater extends Handler { // phase, the subscription list is accessible. Treating NOT_READY // as equivalent to ABSENT, once the rest of the system can handle it. mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, false /* updateEmbeddedSubs */); } broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY, Loading Loading @@ -419,7 +444,7 @@ public class SubscriptionInfoUpdater extends Handler { } mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId()); updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); List<SubscriptionInfo> subscriptionInfos = SubscriptionController.getInstance() .getSubInfoUsingSlotIndexPrivileged(slotId); if (subscriptionInfos == null || subscriptionInfos.isEmpty()) { Loading Loading @@ -541,7 +566,7 @@ public class SubscriptionInfoUpdater extends Handler { logd("SIM" + (slotId + 1) + " hot plug out, absentAndInactive=" + absentAndInactive); } mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); // Do not broadcast if the SIM is absent and inactive, because the logical slotId here is // no longer correct if (absentAndInactive == 0) { Loading @@ -558,7 +583,7 @@ public class SubscriptionInfoUpdater extends Handler { logd("SIM" + (slotId + 1) + " Error "); } mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR); Loading @@ -567,7 +592,8 @@ public class SubscriptionInfoUpdater extends Handler { updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); } synchronized private void updateSubscriptionInfoByIccId(int slotIndex) { private synchronized void updateSubscriptionInfoByIccId(int slotIndex, boolean updateEmbeddedSubs) { logd("updateSubscriptionInfoByIccId:+ Start"); if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { loge("[updateSubscriptionInfoByIccId]- invalid slotIndex=" + slotIndex); Loading Loading @@ -621,20 +647,30 @@ public class SubscriptionInfoUpdater extends Handler { } else { logd("bypass reset default data sub if inactive"); } setSubInfoInitialized(); } UiccController uiccController = UiccController.getInstance(); UiccSlot[] uiccSlots = uiccController.getUiccSlots(); if (uiccSlots != null) { Arrays.stream(uiccSlots) .filter(uiccSlot -> uiccSlot != null && uiccSlot.getUiccCard() != null) .map(uiccSlot -> uiccController.convertToPublicCardId( uiccSlot.getUiccCard().getCardId())) .forEach(cardId -> updateEmbeddedSubscriptions(cardId)); if (uiccSlots != null && updateEmbeddedSubs) { List<Integer> cardIds = new ArrayList<>(); for (UiccSlot uiccSlot : uiccSlots) { if (uiccSlot != null && uiccSlot.getUiccCard() != null) { int cardId = uiccController.convertToPublicCardId( uiccSlot.getUiccCard().getCardId()); cardIds.add(cardId); } setSubInfoInitialized(); } updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); }); } SubscriptionController.getInstance().notifySubscriptionInfoChanged(); logd("updateSubscriptionInfoByIccId:- SubscriptionInfo update complete"); if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); } private static void setSubInfoInitialized() { Loading @@ -655,25 +691,56 @@ public class SubscriptionInfoUpdater extends Handler { } /** * Update the cached list of embedded subscription for the eUICC with the given card ID * {@code cardId}. * Updates the cached list of embedded subscription for the eUICC with the given list of card * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is * executed in background thread. The callback {@code callback} is executed after the cache is * refreshed. The callback is executed in main thread. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback callback) { mBackgroundHandler.post(() -> { List<GetEuiccProfileInfoListResult> results = new ArrayList<>(); for (int cardId : cardIds) { GetEuiccProfileInfoListResult result = EuiccController.get().blockingGetEuiccProfileInfoList(cardId); if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId); results.add(result); } // The runnable will be executed in the main thread. this.post(() -> { boolean hasChanges = false; for (GetEuiccProfileInfoListResult result : results) { if (updateEmbeddedSubscriptionsCache(result)) { hasChanges = true; } } // The latest state in the main thread may be changed when the callback is // triggered. if (callback != null) { callback.run(hasChanges); } }); }); } /** * Update the cached list of embedded subscription based on the passed in * GetEuiccProfileInfoListResult {@code result}. * * @return true if changes may have been made. This is not a guarantee that changes were made, * but notifications about subscription changes may be skipped if this returns false as an * optimization to avoid spurious notifications. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean updateEmbeddedSubscriptions(int cardId) { if (DBG) logd("updateEmbeddedSubscriptions"); private boolean updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result) { if (DBG) logd("updateEmbeddedSubscriptionsCache"); // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they // are filtered out of list calls as long as EuiccManager.isEnabled returns false). if (!mEuiccManager.isEnabled()) { return false; } GetEuiccProfileInfoListResult result = EuiccController.get().blockingGetEuiccProfileInfoList(cardId); if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId); if (result == null) { // IPC to the eUICC controller failed. return false; Loading src/java/com/android/internal/telephony/dataconnection/TransportManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -423,6 +423,21 @@ public class TransportManager extends Handler { ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); } /** * Check if there is any APN type of network preferred on IWLAN. * * @return {@code true} if there is any APN preferred on IWLAN, otherwise {@code false}. */ public boolean isAnyApnPreferredOnIwlan() { for (int i = 0; i < mCurrentAvailableNetworks.size(); i++) { int[] networkList = mCurrentAvailableNetworks.valueAt(i); if (networkList.length > 0 && networkList[0] == AccessNetworkType.IWLAN) { return true; } } return false; } /** * Register for data handover needed event * Loading Loading
src/java/com/android/internal/telephony/PhoneSwitcher.java +4 −0 Original line number Diff line number Diff line Loading @@ -758,11 +758,15 @@ public class PhoneSwitcher extends Handler { int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId) ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID; // Currently we assume multi-SIM devices will only support one Internet PDN connection. So // if Internet PDN is established on the non-preferred phone, it will interrupt // Internet connection on the preferred phone. So we only accept Internet request with // preferred data subscription or no specified subscription. // One exception is, if it's restricted request (doesn't have NET_CAPABILITY_NOT_RESTRICTED) // it will be accepted, which is used temporary data usage from system. if (netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) && subId != preferredDataSubId && subId != mValidator.getSubIdInValidation()) { // Returning INVALID_PHONE_INDEX will result in netRequest not being handled. return INVALID_PHONE_INDEX; Loading
src/java/com/android/internal/telephony/ServiceStateTracker.java +18 −4 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ import android.telephony.PhysicalChannelConfig; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; Loading Loading @@ -1995,11 +1996,16 @@ public class ServiceStateTracker extends Handler { NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); NetworkRegistrationInfo wwanPsRegState = serviceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); // Check if any APN is preferred on IWLAN. boolean isIwlanPreferred = mTransportManager.isAnyApnPreferredOnIwlan(); serviceState.setIwlanPreferred(isIwlanPreferred); if (wlanPsRegState != null && wlanPsRegState.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN && wlanPsRegState.getRegistrationState() == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) { == NetworkRegistrationInfo.REGISTRATION_STATE_HOME && isIwlanPreferred) { serviceState.setDataRegState(ServiceState.STATE_IN_SERVICE); } else if (wwanPsRegState != null) { // If the device is not camped on IWLAN, then we use cellular PS registration state Loading Loading @@ -4007,17 +4013,25 @@ public class ServiceStateTracker extends Handler { loge("cannot setNotification on invalid subid mSubId=" + mSubId); return; } Context context = mPhone.getContext(); SubscriptionInfo info = mSubscriptionController .getActiveSubscriptionInfo(mPhone.getSubId(), context.getOpPackageName()); //if subscription is part of a group and non-primary, suppress all notifications if (info == null || (info.isOpportunistic() && info.getGroupUuid() != null)) { log("cannot setNotification on invisible subid mSubId=" + mSubId); return; } // Needed because sprout RIL sends these when they shouldn't? boolean isSetNotification = mPhone.getContext().getResources().getBoolean( boolean isSetNotification = context.getResources().getBoolean( com.android.internal.R.bool.config_user_notification_of_restrictied_mobile_access); if (!isSetNotification) { if (DBG) log("Ignore all the notifications"); return; } Context context = mPhone.getContext(); boolean autoCancelCsRejectNotification = false; PersistableBundle bundle = getCarrierConfig(); Loading
src/java/com/android/internal/telephony/SubscriptionController.java +16 −4 Original line number Diff line number Diff line Loading @@ -1560,10 +1560,14 @@ public class SubscriptionController extends ISub.Stub { final long identity = Binder.clearCallingIdentity(); try { validateSubId(subId); for (SubscriptionInfo subInfo : mCacheActiveSubInfoList) { List<SubscriptionInfo> allSubInfo = getSubInfo(null, null); // if there is no sub in the db, return 0 since subId does not exist in db if (allSubInfo == null || allSubInfo.isEmpty()) return 0; for (SubscriptionInfo subInfo : allSubInfo) { if (subInfo.getSubscriptionId() == subId && getNameSourcePriority(subInfo.getNameSource()) > getNameSourcePriority(nameSource)) { && (getNameSourcePriority(subInfo.getNameSource()) > getNameSourcePriority(nameSource) || (displayName != null && displayName.equals(subInfo.getDisplayName())))) { return 0; } } Loading Loading @@ -2930,8 +2934,10 @@ public class SubscriptionController extends ISub.Stub { Binder.restoreCallingIdentity(identity); } // If the group does not exist, then by default the UUID is up for grabs so no need to // restrict management of a group (that someone may be attempting to create). if (ArrayUtils.isEmpty(infoList)) { throw new IllegalArgumentException("No subscription in group " + groupUuid); return true; } // If the calling package is the group owner, skip carrier permission check and return Loading Loading @@ -2973,6 +2979,12 @@ public class SubscriptionController extends ISub.Stub { throw new IllegalArgumentException("Invalid groupUuid"); } // TODO: Revisit whether we need this restriction in R. There's no technical need for it, // but we don't want to change the API behavior at this time. if (getSubscriptionsInGroup(groupUuid, callingPackage).isEmpty()) { throw new IllegalArgumentException("Cannot add subscriptions to a non-existent group!"); } // Makes sure calling package matches caller UID. mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); // If it doesn't have modify phone state permission, or carrier privilege permission, Loading
src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java +104 −37 Original line number Diff line number Diff line Loading @@ -66,7 +66,6 @@ import com.android.internal.telephony.uicc.UiccSlot; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** Loading Loading @@ -113,12 +112,26 @@ public class SubscriptionInfoUpdater extends Handler { private EuiccManager mEuiccManager; @UnsupportedAppUsage private IPackageManager mPackageManager; private Handler mBackgroundHandler; // The current foreground user ID. @UnsupportedAppUsage private int mCurrentlyActiveUserId; private CarrierServiceBindHelper mCarrierServiceBindHelper; /** * Runnable with a boolean parameter. This is used in * updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback). */ private interface UpdateEmbeddedSubsCallback { /** * Callback of the Runnable. * @param hasChanges Whether there is any subscription info change. If yes, we need to * notify the listeners. */ void run(boolean hasChanges); } // TODO: The SubscriptionController instance should be passed in here from PhoneFactory // rather than invoking the static getter all over the place. public SubscriptionInfoUpdater( Loading @@ -130,8 +143,8 @@ public class SubscriptionInfoUpdater extends Handler { @VisibleForTesting public SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci, IPackageManager packageMgr) { super(looper); logd("Constructor invoked"); mBackgroundHandler = new Handler(looper); mContext = context; mPhone = phone; Loading Loading @@ -228,6 +241,7 @@ public class SubscriptionInfoUpdater extends Handler { @Override public void handleMessage(Message msg) { List<Integer> cardIds = new ArrayList<>(); switch (msg.what) { case EVENT_GET_NETWORK_SELECTION_MODE_DONE: { AsyncResult ar = (AsyncResult)msg.obj; Loading Loading @@ -279,6 +293,12 @@ public class SubscriptionInfoUpdater extends Handler { break; case EVENT_SIM_READY: cardIds.add(getCardIdFromPhoneId(msg.arg1)); updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } }); broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null); broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT); broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); Loading @@ -289,22 +309,27 @@ public class SubscriptionInfoUpdater extends Handler { break; case EVENT_SIM_NOT_READY: handleSimNotReady(msg.arg1); int cardId = getCardIdFromPhoneId(msg.arg1); // an eUICC with no active subscriptions never becomes ready, so we need to trigger // the embedded subscriptions update here if (updateEmbeddedSubscriptions(cardId)) { cardIds.add(getCardIdFromPhoneId(msg.arg1)); updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } }); handleSimNotReady(msg.arg1); break; case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS: if (updateEmbeddedSubscriptions(msg.arg1)) { cardIds.add(msg.arg1); updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } if (msg.obj != null) { ((Runnable) msg.obj).run(); } }); break; default: Loading Loading @@ -353,7 +378,7 @@ public class SubscriptionInfoUpdater extends Handler { logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId); } updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason); broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT); Loading Loading @@ -387,7 +412,7 @@ public class SubscriptionInfoUpdater extends Handler { // phase, the subscription list is accessible. Treating NOT_READY // as equivalent to ABSENT, once the rest of the system can handle it. mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, false /* updateEmbeddedSubs */); } broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY, Loading Loading @@ -419,7 +444,7 @@ public class SubscriptionInfoUpdater extends Handler { } mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId()); updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); List<SubscriptionInfo> subscriptionInfos = SubscriptionController.getInstance() .getSubInfoUsingSlotIndexPrivileged(slotId); if (subscriptionInfos == null || subscriptionInfos.isEmpty()) { Loading Loading @@ -541,7 +566,7 @@ public class SubscriptionInfoUpdater extends Handler { logd("SIM" + (slotId + 1) + " hot plug out, absentAndInactive=" + absentAndInactive); } mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); // Do not broadcast if the SIM is absent and inactive, because the logical slotId here is // no longer correct if (absentAndInactive == 0) { Loading @@ -558,7 +583,7 @@ public class SubscriptionInfoUpdater extends Handler { logd("SIM" + (slotId + 1) + " Error "); } mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; updateSubscriptionInfoByIccId(slotId); updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR); Loading @@ -567,7 +592,8 @@ public class SubscriptionInfoUpdater extends Handler { updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); } synchronized private void updateSubscriptionInfoByIccId(int slotIndex) { private synchronized void updateSubscriptionInfoByIccId(int slotIndex, boolean updateEmbeddedSubs) { logd("updateSubscriptionInfoByIccId:+ Start"); if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { loge("[updateSubscriptionInfoByIccId]- invalid slotIndex=" + slotIndex); Loading Loading @@ -621,20 +647,30 @@ public class SubscriptionInfoUpdater extends Handler { } else { logd("bypass reset default data sub if inactive"); } setSubInfoInitialized(); } UiccController uiccController = UiccController.getInstance(); UiccSlot[] uiccSlots = uiccController.getUiccSlots(); if (uiccSlots != null) { Arrays.stream(uiccSlots) .filter(uiccSlot -> uiccSlot != null && uiccSlot.getUiccCard() != null) .map(uiccSlot -> uiccController.convertToPublicCardId( uiccSlot.getUiccCard().getCardId())) .forEach(cardId -> updateEmbeddedSubscriptions(cardId)); if (uiccSlots != null && updateEmbeddedSubs) { List<Integer> cardIds = new ArrayList<>(); for (UiccSlot uiccSlot : uiccSlots) { if (uiccSlot != null && uiccSlot.getUiccCard() != null) { int cardId = uiccController.convertToPublicCardId( uiccSlot.getUiccCard().getCardId()); cardIds.add(cardId); } setSubInfoInitialized(); } updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { if (hasChanges) { SubscriptionController.getInstance().notifySubscriptionInfoChanged(); } if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); }); } SubscriptionController.getInstance().notifySubscriptionInfoChanged(); logd("updateSubscriptionInfoByIccId:- SubscriptionInfo update complete"); if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); } private static void setSubInfoInitialized() { Loading @@ -655,25 +691,56 @@ public class SubscriptionInfoUpdater extends Handler { } /** * Update the cached list of embedded subscription for the eUICC with the given card ID * {@code cardId}. * Updates the cached list of embedded subscription for the eUICC with the given list of card * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is * executed in background thread. The callback {@code callback} is executed after the cache is * refreshed. The callback is executed in main thread. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public void updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback callback) { mBackgroundHandler.post(() -> { List<GetEuiccProfileInfoListResult> results = new ArrayList<>(); for (int cardId : cardIds) { GetEuiccProfileInfoListResult result = EuiccController.get().blockingGetEuiccProfileInfoList(cardId); if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId); results.add(result); } // The runnable will be executed in the main thread. this.post(() -> { boolean hasChanges = false; for (GetEuiccProfileInfoListResult result : results) { if (updateEmbeddedSubscriptionsCache(result)) { hasChanges = true; } } // The latest state in the main thread may be changed when the callback is // triggered. if (callback != null) { callback.run(hasChanges); } }); }); } /** * Update the cached list of embedded subscription based on the passed in * GetEuiccProfileInfoListResult {@code result}. * * @return true if changes may have been made. This is not a guarantee that changes were made, * but notifications about subscription changes may be skipped if this returns false as an * optimization to avoid spurious notifications. */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public boolean updateEmbeddedSubscriptions(int cardId) { if (DBG) logd("updateEmbeddedSubscriptions"); private boolean updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result) { if (DBG) logd("updateEmbeddedSubscriptionsCache"); // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they // are filtered out of list calls as long as EuiccManager.isEnabled returns false). if (!mEuiccManager.isEnabled()) { return false; } GetEuiccProfileInfoListResult result = EuiccController.get().blockingGetEuiccProfileInfoList(cardId); if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId); if (result == null) { // IPC to the eUICC controller failed. return false; Loading
src/java/com/android/internal/telephony/dataconnection/TransportManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -423,6 +423,21 @@ public class TransportManager extends Handler { ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); } /** * Check if there is any APN type of network preferred on IWLAN. * * @return {@code true} if there is any APN preferred on IWLAN, otherwise {@code false}. */ public boolean isAnyApnPreferredOnIwlan() { for (int i = 0; i < mCurrentAvailableNetworks.size(); i++) { int[] networkList = mCurrentAvailableNetworks.valueAt(i); if (networkList.length > 0 && networkList[0] == AccessNetworkType.IWLAN) { return true; } } return false; } /** * Register for data handover needed event * Loading