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