1 /* 2 * Copyright (C) 2021 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 android.provider.cts.simphonebook; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.telephony.SubscriptionInfo; 23 import android.telephony.SubscriptionManager; 24 import android.telephony.TelephonyManager; 25 import android.telephony.UiccCardInfo; 26 import android.util.Log; 27 28 import com.android.compatibility.common.util.PollingCheck; 29 import com.android.compatibility.common.util.RequiredFeatureRule; 30 import com.android.compatibility.common.util.SystemUtil; 31 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.Objects; 37 import java.util.stream.Collectors; 38 39 /** Provides the SubscriptionInfo and slot count for removable SIM cards. */ 40 class RemovableSims { 41 private final Context mContext; 42 private final TelephonyManager mTelephonyManager; 43 44 private List<SubscriptionInfo> mRemovableSubscriptionInfos; 45 private int mRemovableSimSlotCount; 46 RemovableSims(Context context)47 public RemovableSims(Context context) { 48 mContext = context; 49 mTelephonyManager = Objects.requireNonNull( 50 context.getSystemService(TelephonyManager.class)); 51 } 52 initialize()53 private synchronized void initialize() { 54 SubscriptionManager subscriptionManager = Objects.requireNonNull( 55 mContext.getSystemService(SubscriptionManager.class)); 56 mRemovableSubscriptionInfos = new ArrayList<>(); 57 mRemovableSimSlotCount = 0; 58 // If the device has only active PSIMs then it is not required to wait for EUICC 59 // initialization and we can skip it. 60 if (RequiredFeatureRule.hasFeature(PackageManager.FEATURE_TELEPHONY_EUICC) && 61 !hasActivePsimsOnly(subscriptionManager)) { 62 // Wait for the eSIM state to be loaded before continuing. Otherwise, the card info 63 // we load later may indicate that they are not eSIM when they actually are. 64 PollingCheck.waitFor(30_000, () -> 65 mTelephonyManager.getCardIdForDefaultEuicc() != 66 TelephonyManager.UNINITIALIZED_CARD_ID 67 ); 68 } 69 70 List<UiccCardInfo> uiccCards = SystemUtil.runWithShellPermissionIdentity( 71 mTelephonyManager::getUiccCardsInfo, 72 Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 73 74 List<SubscriptionInfo> allSubscriptions = SystemUtil.runWithShellPermissionIdentity(() -> 75 subscriptionManager.getActiveSubscriptionInfoList(), 76 Manifest.permission.READ_PHONE_STATE); 77 if (allSubscriptions == null) { 78 allSubscriptions = Collections.emptyList(); 79 } 80 Map<Integer, List<SubscriptionInfo>> subscriptionsByCardId = allSubscriptions.stream() 81 .collect(Collectors.groupingBy(SubscriptionInfo::getCardId)); 82 for (UiccCardInfo cardInfo : uiccCards) { 83 // On GSI builds the eUICC won't be loaded but its card info will still be returned 84 // and so it will have UNINITIALIZED_CARD_ID permanently. 85 if (!cardInfo.isRemovable() || cardInfo.isEuicc() || 86 cardInfo.getCardId() == TelephonyManager.UNINITIALIZED_CARD_ID) { 87 continue; 88 } 89 mRemovableSimSlotCount++; 90 91 List<SubscriptionInfo> listWithSubscription = subscriptionsByCardId 92 .getOrDefault(cardInfo.getCardId(), Collections.emptyList()); 93 // There should only be 1 in the list but using addAll simplifies things because we 94 // don't have to check for the empty case. 95 mRemovableSubscriptionInfos.addAll(listWithSubscription); 96 } 97 } 98 getSubscriptionInfoForRemovableSims()99 public List<SubscriptionInfo> getSubscriptionInfoForRemovableSims() { 100 if (mRemovableSubscriptionInfos == null || 101 mRemovableSubscriptionInfos.size() < mRemovableSimSlotCount) { 102 initialize(); 103 } 104 return mRemovableSubscriptionInfos; 105 } 106 getRemovableSimSlotCount()107 public int getRemovableSimSlotCount() { 108 if (mRemovableSubscriptionInfos == null) { 109 initialize(); 110 } 111 return mRemovableSimSlotCount; 112 } 113 getDefaultSubscriptionId()114 public int getDefaultSubscriptionId() { 115 List<SubscriptionInfo> removableSubscriptionInfos = getSubscriptionInfoForRemovableSims(); 116 int subscriptionId = SubscriptionManager.getDefaultSubscriptionId(); 117 if (removableSubscriptionInfos.stream().anyMatch( 118 info -> info.getSubscriptionId() == subscriptionId)) { 119 return subscriptionId; 120 } else if (!removableSubscriptionInfos.isEmpty()) { 121 return removableSubscriptionInfos.get(0).getSubscriptionId(); 122 } 123 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 124 } 125 hasActivePsimsOnly(SubscriptionManager subscriptionManager)126 private boolean hasActivePsimsOnly(SubscriptionManager subscriptionManager) { 127 List<SubscriptionInfo> activeList = SystemUtil.runWithShellPermissionIdentity(() -> 128 subscriptionManager.getActiveSubscriptionInfoList(), 129 Manifest.permission.READ_PHONE_STATE); 130 int counter = 0; 131 if (activeList != null) { 132 for (SubscriptionInfo subInfo : activeList) { 133 if (!subInfo.isEmbedded()) { 134 counter++; 135 } 136 } 137 } 138 Log.i("RemovableSims", 139 "hasActivePsimsOnly: counter = " + counter + " active modemCount = " 140 + mTelephonyManager.getActiveModemCount()); 141 return (counter > 0 && counter == mTelephonyManager.getActiveModemCount()); 142 } 143 } 144