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 com.android.imsserviceentitlement.utils;
18 
19 import android.content.Context;
20 import android.net.ConnectivityManager;
21 import android.net.NetworkInfo;
22 import android.os.Build;
23 import android.os.PersistableBundle;
24 import android.telephony.CarrierConfigManager;
25 import android.telephony.SubscriptionInfo;
26 import android.telephony.SubscriptionManager;
27 import android.telephony.TelephonyManager;
28 import android.util.Log;
29 
30 import com.google.common.collect.ImmutableSet;
31 
32 import java.util.List;
33 
34 /** This class implements Telephony helper methods. */
35 public class TelephonyUtils {
36     public static final String TAG = "IMSSE-TelephonyUtils";
37 
38     private final ConnectivityManager mConnectivityManager;
39     private final TelephonyManager mTelephonyManager;
40 
TelephonyUtils(Context context)41     public TelephonyUtils(Context context) {
42         this(context, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
43     }
44 
TelephonyUtils(Context context, int subId)45     public TelephonyUtils(Context context, int subId) {
46         if (SubscriptionManager.isValidSubscriptionId(subId)) {
47             mTelephonyManager =
48                     context.getSystemService(TelephonyManager.class).createForSubscriptionId(subId);
49         } else {
50             mTelephonyManager = context.getSystemService(TelephonyManager.class);
51         }
52         mConnectivityManager = context.getSystemService(ConnectivityManager.class);
53     }
54 
55     /** Returns device timestamp in milliseconds. */
getTimeStamp()56     public long getTimeStamp() {
57         return System.currentTimeMillis();
58     }
59 
60     /** Returns device uptime in milliseconds. */
getUptimeMillis()61     public long getUptimeMillis() {
62         return android.os.SystemClock.uptimeMillis();
63     }
64 
65     /** Returns device model name. */
getDeviceName()66     public String getDeviceName() {
67         return Build.MODEL;
68     }
69 
70     /** Returns device OS version. */
getDeviceOsVersion()71     public String getDeviceOsVersion() {
72         return Build.VERSION.RELEASE;
73     }
74 
75     /** Returns {@code true} if network is connected (cellular or WiFi). */
isNetworkConnected()76     public boolean isNetworkConnected() {
77         NetworkInfo activeNetwork = mConnectivityManager.getActiveNetworkInfo();
78         return activeNetwork != null && activeNetwork.isConnected();
79     }
80 
81     /**
82      * Returns the response of EAP-AKA authetication {@code data} or {@code null} on failure.
83      *
84      * <p>Requires permission: READ_PRIVILEGED_PHONE_STATE
85      */
getEapAkaAuthentication(String data)86     public String getEapAkaAuthentication(String data) {
87         return mTelephonyManager.getIccAuthentication(
88                 TelephonyManager.APPTYPE_USIM, TelephonyManager.AUTHTYPE_EAP_AKA, data);
89     }
90 
91     /** Returns carrier ID. */
getCarrierId()92     public int getCarrierId() {
93         return mTelephonyManager.getSimCarrierId();
94     }
95 
96     /** Returns fine-grained carrier ID. */
getSpecificCarrierId()97     public int getSpecificCarrierId() {
98         return mTelephonyManager.getSimSpecificCarrierId();
99     }
100 
101     /** Returns SIM card application state. */
getSimApplicationState()102     public int getSimApplicationState() {
103         return mTelephonyManager.getSimApplicationState();
104     }
105 
106     /**
107      * Returns {@code true} if the {@code subId} still point to a actived SIM; {@code false}
108      * otherwise.
109      */
isActivedSubId(Context context, int subId)110     public static boolean isActivedSubId(Context context, int subId) {
111         SubscriptionManager subscriptionManager =
112                 (SubscriptionManager) context.getSystemService(
113                         Context.TELEPHONY_SUBSCRIPTION_SERVICE);
114         SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(subId);
115         return subInfo != null;
116     }
117 
118     /**
119      * Returns the slot index for the actived {@code subId}; {@link
120      * SubscriptionManager#INVALID_SIM_SLOT_INDEX} otherwise.
121      */
getSlotId(Context context, int subId)122     public static int getSlotId(Context context, int subId) {
123         SubscriptionManager subscriptionManager =
124                 (SubscriptionManager) context.getSystemService(
125                         Context.TELEPHONY_SUBSCRIPTION_SERVICE);
126         SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(subId);
127         if (subInfo != null) {
128             return subInfo.getSimSlotIndex();
129         }
130         Log.d(TAG, "Can't find actived subscription for " + subId);
131         return SubscriptionManager.INVALID_SIM_SLOT_INDEX;
132     }
133 
134     /** Returns carrier config for the {@code subId}. */
getConfigForSubId(Context context, int subId)135     private static PersistableBundle getConfigForSubId(Context context, int subId) {
136         CarrierConfigManager carrierConfigManager =
137                 context.getSystemService(CarrierConfigManager.class);
138         PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
139         if (carrierConfig == null) {
140             Log.d(TAG, "getDefaultConfig");
141             carrierConfig = CarrierConfigManager.getDefaultConfig();
142         }
143         return carrierConfig;
144     }
145 
146     /**
147      * Returns FCM sender id for the {@code subId} or a default empty string if it is not available.
148      */
getFcmSenderId(Context context, int subId)149     public static String getFcmSenderId(Context context, int subId) {
150         return getConfigForSubId(context, subId).getString(
151                 CarrierConfigManager.ImsServiceEntitlement.KEY_FCM_SENDER_ID_STRING,
152                 ""
153         );
154     }
155 
156     /**
157      * Returns entitlement server url for the {@code subId} or
158      * a default empty string if it is not available.
159      */
getEntitlementServerUrl(Context context, int subId)160     public static String getEntitlementServerUrl(Context context, int subId) {
161         return getConfigForSubId(context, subId).getString(
162                 CarrierConfigManager.ImsServiceEntitlement.KEY_ENTITLEMENT_SERVER_URL_STRING,
163                 ""
164         );
165     }
166 
167     /**
168      * Returns true if app needs to do IMS (VoLTE/VoWiFi/SMSoIP) provisioning in the background
169      * or false if it doesn't need to do.
170      */
isImsProvisioningRequired(Context context, int subId)171     public static boolean isImsProvisioningRequired(Context context, int subId) {
172         return getConfigForSubId(context, subId).getBoolean(
173                 CarrierConfigManager.ImsServiceEntitlement.KEY_IMS_PROVISIONING_BOOL,
174                 false
175         );
176     }
177 
178     /** Returns SubIds which support FCM. */
getSubIdsWithFcmSupported(Context context)179     public static ImmutableSet<Integer> getSubIdsWithFcmSupported(Context context) {
180         SubscriptionManager subscriptionManager =
181                 context.getSystemService(SubscriptionManager.class);
182         List<SubscriptionInfo> infos = subscriptionManager.getActiveSubscriptionInfoList();
183         if (infos == null) {
184             return ImmutableSet.of();
185         }
186 
187         ImmutableSet.Builder<Integer> builder = ImmutableSet.builder();
188         for (SubscriptionInfo info : infos) {
189             int subId = info.getSubscriptionId();
190             if (isFcmPushNotificationSupported(context, subId)) {
191                 builder.add(subId);
192             }
193         }
194         return builder.build();
195     }
196 
isFcmPushNotificationSupported(Context context, int subId)197     private static boolean isFcmPushNotificationSupported(Context context, int subId) {
198         return !TelephonyUtils.getFcmSenderId(context, subId).isEmpty();
199     }
200 }
201