1 /*
2  * Copyright (C) 2022 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 com.android.settings.deviceinfo.simstatus;
18 
19 import android.content.Context;
20 import android.telephony.SubscriptionInfo;
21 import android.telephony.TelephonyManager;
22 import android.telephony.UiccCardInfo;
23 import android.telephony.euicc.EuiccManager;
24 import android.text.TextUtils;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.Objects;
28 import java.util.concurrent.Executor;
29 import java.util.concurrent.Phaser;
30 import java.util.concurrent.atomic.AtomicReference;
31 import java.util.stream.IntStream;
32 
33 /**
34  * A class for query EID.
35  */
36 public class EidStatus {
37 
38     private static final String TAG = "EidStatus";
39     private final SlotSimStatus mSlotSimStatus;
40     private final Phaser mBlocker = new Phaser(1);
41     private final AtomicReference<String> mEid = new AtomicReference<String>();
42 
43     /**
44      * Construct of class.
45      * @param slotSimStatus SlotSimStatus
46      * @param context Context
47      */
EidStatus(SlotSimStatus slotSimStatus, Context context)48     public EidStatus(SlotSimStatus slotSimStatus, Context context) {
49         this(slotSimStatus, context, null);
50     }
51 
52     /**
53      * Construct of class.
54      * @param slotSimStatus SlotSimStatus
55      * @param context Context
56      * @param executor executor for offload to thread
57      */
EidStatus(SlotSimStatus slotSimStatus, Context context, Executor executor)58     public EidStatus(SlotSimStatus slotSimStatus, Context context, Executor executor) {
59         mSlotSimStatus = slotSimStatus;
60 
61         if (executor == null) {
62             getEidOperation(context);
63         } else {
64             executor.execute(() -> getEidOperation(context));
65         }
66     }
67 
68     /**
69      * Get the EID
70      * @return EID string
71      */
getEid()72     public String getEid() {
73         mBlocker.awaitAdvance(0);
74         return mEid.get();
75     }
76 
getTelephonyManager(Context context)77     protected TelephonyManager getTelephonyManager(Context context) {
78         return context.getSystemService(TelephonyManager.class);
79     }
80 
getEuiccManager(Context context)81     protected EuiccManager getEuiccManager(Context context) {
82         return context.getSystemService(EuiccManager.class);
83     }
84 
getDefaultEid(EuiccManager euiccMgr)85     protected String getDefaultEid(EuiccManager euiccMgr) {
86         if ((euiccMgr == null) || (!euiccMgr.isEnabled())) {
87             return null;
88         }
89         return euiccMgr.getEid();
90     }
91 
getEidOperation(Context context)92     protected void getEidOperation(Context context) {
93         EuiccManager euiccMgr = getEuiccManager(context);
94         String eid = getEidPerSlot(context, euiccMgr);
95         if (eid == null) {
96             eid = getDefaultEid(euiccMgr);
97         }
98         mEid.set(eid);
99         mBlocker.arrive();
100     }
101 
getEidPerSlot(Context context, EuiccManager euiccMgr)102     protected String getEidPerSlot(Context context, EuiccManager euiccMgr) {
103         if (mSlotSimStatus.size() <= SimStatusDialogController.MAX_PHONE_COUNT_SINGLE_SIM) {
104             return null;
105         }
106 
107         TelephonyManager telMgr = getTelephonyManager(context);
108         if (telMgr == null) {
109             return null;
110         }
111 
112         List<UiccCardInfo> uiccCardInfoList = telMgr.getUiccCardsInfo();
113         if (uiccCardInfoList == null) {
114             return null;
115         }
116 
117         // Collects all card ID from all eSIM(s) reported from SubscsriptionManager
118         final int [] cardIdList = IntStream.range(0, mSlotSimStatus.size())
119                 .mapToObj(slotIdx -> mSlotSimStatus.getSubscriptionInfo(slotIdx))
120                 .filter(Objects::nonNull)
121                 .filter(SubscriptionInfo::isEmbedded)
122                 .mapToInt(SubscriptionInfo::getCardId)
123                 .sorted()
124                 .distinct()
125                 .toArray();
126         if (cardIdList.length == 0) {
127             return null;
128         }
129 
130         /**
131          * Find EID from first slot which contains an eSIM and with card ID listed within
132          * the eSIM card ID provided by SubscsriptionManager.
133          */
134         return uiccCardInfoList.stream()
135                 .filter(UiccCardInfo::isEuicc)
136                 .filter(cardInfo -> {
137                     int cardId = cardInfo.getCardId();
138                     return Arrays.binarySearch(cardIdList, cardId) >= 0;
139                 })
140                 .map(cardInfo -> {
141                     String eid = cardInfo.getEid();
142                     if (TextUtils.isEmpty(eid)) {
143                         eid = euiccMgr.createForCardId(cardInfo.getCardId()).getEid();
144                     }
145                     return eid;
146                 })
147                 .filter(Objects::nonNull)
148                 .findFirst()
149                 .orElse(null);
150     }
151 
152 }
153