• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 package com.android.nfc.cardemulation.util;
17 
18 import android.content.Context;
19 import android.telephony.SubscriptionInfo;
20 import android.telephony.SubscriptionManager;
21 import android.telephony.TelephonyManager;
22 import android.util.Log;
23 
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Optional;
27 import java.util.concurrent.Executors;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.Predicate;
30 
31 public class TelephonyUtils extends SubscriptionManager.OnSubscriptionsChangedListener{
32     private final String TAG = "TelephonyUtils";
33     public static final int SUBSCRIPTION_STATE_UNKNOWN = -1;
34     public static final int SUBSCRIPTION_STATE_ACTIVATE = 1;
35     public static final int SUBSCRIPTION_STATE_INACTIVATE = 2;
36 
37     public static final int SUBSCRIPTION_ID_UNKNOWN = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
38     public static final int SUBSCRIPTION_ID_UICC = 0x100000;
39     public static final int PORT_IS_NOT_SET = 0xFF;
40 
41     public static final int SIM_TYPE_UNKNOWN = 0;
42     public static final int SIM_TYPE_UICC = 1;
43     public static final int SIM_TYPE_EUICC_1 = 2;
44     public static final int SIM_TYPE_EUICC_2 = 3;
45 
46     public static final int MEP_MODE_NONE = 0;
47     public static final int MEP_MODE_A1 = 1;
48     public static final int MEP_MODE_A2 = 2;
49     public static final int MEP_MODE_B = 3;
50 
51     private TelephonyManager mTelephonyManager;
52     private SubscriptionManager mSubscriptionManager;
53 
54     private boolean mIsSubscriptionsChangedListenerRegistered = false;
55 
56     public static Predicate<SubscriptionInfo> SUBSCRIPTION_ACTIVE_CONDITION_FOR_UICC =
57             subscriptionInfo -> !subscriptionInfo.isEmbedded()
58                     && subscriptionInfo.areUiccApplicationsEnabled();
59     public static Predicate<SubscriptionInfo> SUBSCRIPTION_ACTIVE_CONDITION_FOR_EUICC =
60             subscriptionInfo -> subscriptionInfo.isEmbedded();
61 
62     int mMepMode ;   // TODO - How to set MEP mode. Port value is depending on MEP Mode
63     public interface Callback {
onActiveSubscriptionsUpdated(List<SubscriptionInfo> activeSubscriptionList)64         void onActiveSubscriptionsUpdated(List<SubscriptionInfo> activeSubscriptionList);
65     }
66     Callback mCallback;
67     private static class Singleton {
68         private static TelephonyUtils sInstance = null;
69     }
70 
getInstance(Context context)71     public static TelephonyUtils getInstance(Context context) {
72         if (TelephonyUtils.Singleton.sInstance == null) {
73             TelephonyUtils.Singleton.sInstance = new TelephonyUtils(context);
74         }
75         return TelephonyUtils.Singleton.sInstance;
76     }
77 
TelephonyUtils(Context context)78     public TelephonyUtils(Context context) {
79         mTelephonyManager = context.getSystemService(TelephonyManager.class);
80         mSubscriptionManager = SubscriptionManager.from(context);
81         mMepMode = MEP_MODE_B;  //TODO - How to check MEP mode from eSIM
82     }
83 
registerSubscriptionChangedCallback(Callback callback)84     public void registerSubscriptionChangedCallback(Callback callback) {
85         mCallback = callback;
86         mSubscriptionManager.addOnSubscriptionsChangedListener(
87                 Executors.newSingleThreadExecutor(), this);
88     }
89 
getActiveSubscriptionInfoById(int subscriptionId)90     public Optional<SubscriptionInfo> getActiveSubscriptionInfoById(int subscriptionId) {
91         Log.d(TAG, "getActiveSubscriptionInfoById: " + subscriptionId);
92         if (isUiccSubscription(subscriptionId)) {
93             Log.d(TAG, "getActiveSubscriptionInfoById: Uicc Subscription");
94             return findFirstActiveSubscriptionInfo(subscriptionInfo ->
95                     !subscriptionInfo.isEmbedded()
96                             && subscriptionInfo.areUiccApplicationsEnabled());
97         }
98         else {
99             Log.d(TAG, "getActiveSubscriptionInfoById: Embedded Uicc Subscription");
100             return Optional.ofNullable(
101                     mSubscriptionManager.getActiveSubscriptionInfo(subscriptionId));
102         }
103     }
isUiccSubscription(int subscriptionId)104     public boolean isUiccSubscription(int subscriptionId) {
105         return subscriptionId == SUBSCRIPTION_ID_UICC;
106     }
107 
isEuiccSubscription(int subscriptionId)108     public boolean isEuiccSubscription(int subscriptionId) {
109         return (subscriptionId != SUBSCRIPTION_ID_UICC) &&
110                 (subscriptionId != SUBSCRIPTION_ID_UNKNOWN);
111     }
112 
getActiveSubscriptions()113     public List<SubscriptionInfo> getActiveSubscriptions() {
114         List<SubscriptionInfo> list = mSubscriptionManager.getActiveSubscriptionInfoList();
115         return (list != null) ? list : Collections.emptyList();
116     }
117 
118     @Override
onSubscriptionsChanged()119     public void onSubscriptionsChanged() {
120         Log.d(TAG, "onSubscriptionsChanged");
121         if (!mIsSubscriptionsChangedListenerRegistered) {
122             Log.d(TAG, "onSubscriptionsChanged: Skip when receive the event with registering");
123             mIsSubscriptionsChangedListenerRegistered = true;
124             return;
125         }
126 
127         mCallback.onActiveSubscriptionsUpdated(
128                 mSubscriptionManager.getActiveSubscriptionInfoList());
129     }
130 
updateSwpStatusForEuicc(int simType)131     public String updateSwpStatusForEuicc(int simType) {
132         return transmitApduToActiveSubscription(0x80, 0x7C, 0x02,
133                 getPort(simType), 0x00, "");
134     }
135 
transmitApduToActiveSubscription( int cla, int ins, int p1, int p2, int p3, String data)136     private String transmitApduToActiveSubscription(
137             int cla, int ins, int p1, int p2, int p3, String data) {
138         AtomicReference<String > response = new AtomicReference<>();
139         findFirstActiveSubscriptionInfo(SUBSCRIPTION_ACTIVE_CONDITION_FOR_EUICC)
140                 .ifPresentOrElse(
141                         subscriptionInfo -> {
142                             String result = mTelephonyManager
143                                     .createForSubscriptionId(subscriptionInfo.getSubscriptionId())
144                                     .iccTransmitApduBasicChannel(cla, ins, p1, p2, p3, data);
145                             response.set(result);
146                         } ,
147                         ()-> {
148                             Log.d(TAG, "transmitApduToActiveSubscription: Send APDU fail because "
149                                     + "active subscription is not exist");
150                             response.set("FFFF");
151                         }
152                 );
153         return response.get();
154     }
155 
findFirstActiveSubscriptionInfo( Predicate<SubscriptionInfo> condition)156     private Optional<SubscriptionInfo> findFirstActiveSubscriptionInfo(
157             Predicate<SubscriptionInfo> condition) {
158         return getActiveSubscriptions().stream().filter(condition)
159                 .findFirst();
160     }
161 
162     // TODO - port value updated according to MEP Mode
163     // Currently, Nfc could not know MEP mode.
getPort(int simType)164     private int getPort(int simType) {
165         int port = PORT_IS_NOT_SET;
166         if (mMepMode != MEP_MODE_NONE) {
167             if (simType == SIM_TYPE_EUICC_1) {
168                 port = (mMepMode == MEP_MODE_B) ? 0x00 : 0x01;
169             } else if (simType == SIM_TYPE_EUICC_2) {
170                 port = (mMepMode == MEP_MODE_B) ? 0x01 : 0x02;
171             }
172         }
173         return port;
174     }
175 
setMepMode(int mepMode)176     public void setMepMode(int mepMode) {
177         mMepMode = mepMode;
178     }
179 
180 
181 }
182