xref: /aosp_15_r20/cts/tests/tests/simphonebookprovider/src/android/provider/cts/simphonebook/RemovableSims.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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