1 /*
2  * Copyright (C) 2020 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.ims.rcs.uce.presence.publish;
18 
19 import android.content.Context;
20 import android.net.Uri;
21 import android.telephony.PhoneNumberUtils;
22 import android.telephony.TelephonyManager;
23 import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
24 import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import com.android.ims.rcs.uce.util.UceUtils;
29 
30 import java.util.Arrays;
31 
32 /**
33  * The util class of publishing device's capabilities.
34  */
35 public class PublishUtils {
36     private static final String LOG_TAG = UceUtils.getLogPrefix() + "PublishUtils";
37 
38     private static final String SCHEME_SIP = "sip";
39     private static final String SCHEME_TEL = "tel";
40     private static final String DOMAIN_SEPARATOR = "@";
41 
getDeviceContactUri(Context context, int subId, DeviceCapabilityInfo deviceCap)42     public static Uri getDeviceContactUri(Context context, int subId,
43             DeviceCapabilityInfo deviceCap) {
44         // Get the uri from the IMS associated URI which is provided by the IMS service.
45         Uri contactUri = deviceCap.getImsAssociatedUri();
46         if (contactUri != null) {
47             Log.d(LOG_TAG, "getDeviceContactUri: ims associated uri");
48             return contactUri;
49         }
50 
51         TelephonyManager telephonyManager = getTelephonyManager(context, subId);
52         if (telephonyManager == null) {
53             Log.w(LOG_TAG, "getDeviceContactUri: TelephonyManager is null");
54             return null;
55         }
56 
57         // Get the contact uri from ISIM.
58         contactUri = getContactUriFromIsim(telephonyManager);
59         if (contactUri != null) {
60             Log.d(LOG_TAG, "getDeviceContactUri: impu");
61             return contactUri;
62         } else {
63             Log.d(LOG_TAG, "getDeviceContactUri: line number");
64             return getContactUriFromLine1Number(telephonyManager);
65         }
66     }
67 
68     /**
69      * Find all instances of sip/sips/tel URIs containing PII and replace them.
70      * <p>
71      * This is used for removing PII in logging.
72      * @param source The source string to remove the phone numbers from.
73      * @return A version of the given string with SIP URIs removed.
74      */
removeNumbersFromUris(String source)75     public static String removeNumbersFromUris(String source) {
76         // Replace only the number portion in the sip/sips/tel URI
77         return source.replaceAll("(?:sips?|tel):(\\+?[\\d\\-]+)", "[removed]");
78     }
79 
getContactUriFromIsim(TelephonyManager telephonyManager)80     private static Uri getContactUriFromIsim(TelephonyManager telephonyManager) {
81         // Get the home network domain and the array of the public user identities
82         String domain = telephonyManager.getIsimDomain();
83         String[] impus = telephonyManager.getIsimImpu();
84 
85         if (TextUtils.isEmpty(domain) || impus == null) {
86             Log.d(LOG_TAG, "getContactUriFromIsim: domain is null=" + TextUtils.isEmpty(domain));
87             Log.d(LOG_TAG, "getContactUriFromIsim: impu is null=" +
88                     ((impus == null || impus.length == 0) ? "true" : "false"));
89             return null;
90         }
91 
92         for (String impu : impus) {
93             if (TextUtils.isEmpty(impu)) continue;
94             Uri impuUri = Uri.parse(impu);
95             String scheme = impuUri.getScheme();
96             String schemeSpecificPart = impuUri.getSchemeSpecificPart();
97             if (SCHEME_SIP.equals(scheme) && !TextUtils.isEmpty(schemeSpecificPart) &&
98                     schemeSpecificPart.endsWith(domain)) {
99                 return impuUri;
100             }
101         }
102         Log.d(LOG_TAG, "getContactUriFromIsim: there is no impu matching the domain");
103         return null;
104     }
105 
getContactUriFromLine1Number(TelephonyManager telephonyManager)106     private static Uri getContactUriFromLine1Number(TelephonyManager telephonyManager) {
107         String phoneNumber = formatPhoneNumber(telephonyManager.getLine1Number());
108         if (TextUtils.isEmpty(phoneNumber)) {
109             Log.w(LOG_TAG, "Cannot get the phone number");
110             return null;
111         }
112 
113         String domain = telephonyManager.getIsimDomain();
114         if (!TextUtils.isEmpty(domain)) {
115             return Uri.fromParts(SCHEME_SIP, phoneNumber + DOMAIN_SEPARATOR + domain, null);
116         } else {
117             return Uri.fromParts(SCHEME_TEL, phoneNumber, null);
118         }
119     }
120 
formatPhoneNumber(final String phoneNumber)121     private static String formatPhoneNumber(final String phoneNumber) {
122         if (TextUtils.isEmpty(phoneNumber)) {
123             Log.w(LOG_TAG, "formatPhoneNumber: phone number is empty");
124             return null;
125         }
126         String number = PhoneNumberUtils.stripSeparators(phoneNumber);
127         return PhoneNumberUtils.normalizeNumber(number);
128     }
129 
getTelephonyManager(Context context, int subId)130     private static TelephonyManager getTelephonyManager(Context context, int subId) {
131         TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
132         if (telephonyManager == null) {
133             return null;
134         } else {
135             return telephonyManager.createForSubscriptionId(subId);
136         }
137     }
138 
getCapabilityType(Context context, int subId)139     static @RcsImsCapabilityFlag int getCapabilityType(Context context, int subId) {
140         boolean isPresenceSupported = UceUtils.isPresenceSupported(context, subId);
141         boolean isSipOptionsSupported = UceUtils.isSipOptionsSupported(context, subId);
142         if (isPresenceSupported) {
143             return RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
144         } else if (isSipOptionsSupported) {
145             return RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE;
146         } else {
147             // Return NONE when neither OPTIONS nor PRESENCE is supported.
148             return RcsImsCapabilities.CAPABILITY_TYPE_NONE;
149         }
150     }
151 }
152