• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.providers.telephony;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.ComponentName;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.net.Uri;
26 import android.os.Binder;
27 import android.os.Process;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.provider.Telephony;
31 import android.telephony.SubscriptionInfo;
32 import android.telephony.SubscriptionManager;
33 import android.telephony.TelephonyManager;
34 import android.telephony.emergency.EmergencyNumber;
35 import android.text.TextUtils;
36 import android.util.Log;
37 
38 import com.android.internal.telephony.SmsApplication;
39 
40 import java.util.ArrayList;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.stream.Collectors;
44 
45 /**
46  * Helpers
47  */
48 public class ProviderUtil {
49     private final static String TAG = "SmsProvider";
50 
51     /**
52      * Check if a caller of the provider has restricted access,
53      * i.e. being non-system, non-phone, non-default SMS app
54      *
55      * @param context the context to use
56      * @param packageName the caller package name
57      * @param uid the caller uid
58      * @return true if the caller is not system, or phone or default sms app, false otherwise
59      */
isAccessRestricted(Context context, String packageName, int uid)60     public static boolean isAccessRestricted(Context context, String packageName, int uid) {
61         return (uid != Process.SYSTEM_UID
62                 && uid != Process.PHONE_UID
63                 && !SmsApplication.isDefaultSmsApplication(context, packageName));
64     }
65 
66     /**
67      * Whether should set CREATOR for an insertion
68      *
69      * @param values The content of the message
70      * @param uid The caller UID of the insertion
71      * @return true if we should set CREATOR, false otherwise
72      */
shouldSetCreator(ContentValues values, int uid)73     public static boolean shouldSetCreator(ContentValues values, int uid) {
74         return (uid != Process.SYSTEM_UID && uid != Process.PHONE_UID) ||
75                 (!values.containsKey(Telephony.Sms.CREATOR) &&
76                         !values.containsKey(Telephony.Mms.CREATOR));
77     }
78 
79     /**
80      * Whether should remove CREATOR for an update
81      *
82      * @param values The content of the message
83      * @param uid The caller UID of the update
84      * @return true if we should remove CREATOR, false otherwise
85      */
shouldRemoveCreator(ContentValues values, int uid)86     public static boolean shouldRemoveCreator(ContentValues values, int uid) {
87         return (uid != Process.SYSTEM_UID && uid != Process.PHONE_UID) &&
88                 (values.containsKey(Telephony.Sms.CREATOR) ||
89                         values.containsKey(Telephony.Mms.CREATOR));
90     }
91 
92     /**
93      * Notify the default SMS app of an SMS/MMS provider change if the change is being made
94      * by a package other than the default SMS app itself.
95      *
96      * @param uri The uri the provider change applies to
97      * @param callingPackage The package name of the provider caller
98      * @param Context
99      */
notifyIfNotDefaultSmsApp(final Uri uri, final String callingPackage, final Context context)100     public static void notifyIfNotDefaultSmsApp(final Uri uri, final String callingPackage,
101             final Context context) {
102         if (TextUtils.equals(callingPackage, Telephony.Sms.getDefaultSmsPackage(context))) {
103             if (Log.isLoggable(TAG, Log.VERBOSE)) {
104                 Log.d(TAG, "notifyIfNotDefaultSmsApp - called from default sms app");
105             }
106             return;
107         }
108         // Direct the intent to only the default SMS app, and only if the SMS app has a receiver
109         // for the intent.
110         ComponentName componentName =
111                 SmsApplication.getDefaultExternalTelephonyProviderChangedApplication(context, true);
112         if (componentName == null) {
113             return;     // the default sms app doesn't have a receiver for this intent
114         }
115 
116         final Intent intent =
117                 new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
118         intent.setFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
119         intent.setComponent(componentName);
120         if (uri != null) {
121             intent.setData(uri);
122         }
123         if (Log.isLoggable(TAG, Log.VERBOSE)) {
124             Log.d(TAG, "notifyIfNotDefaultSmsApp - called from " + callingPackage + ", notifying");
125         }
126         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
127         context.sendBroadcast(intent);
128     }
129 
getCredentialEncryptedContext(Context context)130     public static Context getCredentialEncryptedContext(Context context) {
131         if (context.isCredentialProtectedStorage()) {
132             return context;
133         }
134         return context.createCredentialProtectedStorageContext();
135     }
136 
getDeviceEncryptedContext(Context context)137     public static Context getDeviceEncryptedContext(Context context) {
138         if (context.isDeviceProtectedStorage()) {
139             return context;
140         }
141         return context.createDeviceProtectedStorageContext();
142     }
143 
144     /**
145      * Get subscriptions associated with the user in the format of a selection string.
146      * @param context context
147      * @param userHandle caller user handle.
148      * @return subscriptions associated with the user in the format of a selection string
149      * or {@code null} if user is not associated with any subscription.
150      */
151     @Nullable
getSelectionBySubIds(Context context, @NonNull UserHandle userHandle)152     public static String getSelectionBySubIds(Context context, @NonNull UserHandle userHandle) {
153         List<SubscriptionInfo> associatedSubscriptionsList = new ArrayList<>();
154         SubscriptionManager subManager = context.getSystemService(SubscriptionManager.class);
155         if (subManager != null) {
156             // Get list of subscriptions associated with this user.
157             associatedSubscriptionsList = subManager
158                     .getSubscriptionInfoListAssociatedWithUser(userHandle);
159         }
160 
161         UserManager userManager = context.getSystemService(UserManager.class);
162         if ((userManager != null) && (!userManager.isManagedProfile(userHandle.getIdentifier()))) {
163             // SMS/MMS restored from another device have sub_id=-1.
164             // To query/update/delete those messages, sub_id=-1 should be in the selection string.
165             SubscriptionInfo invalidSubInfo = new SubscriptionInfo.Builder()
166                     .setId(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
167                     .build();
168             associatedSubscriptionsList.add(invalidSubInfo);
169         }
170 
171         if (associatedSubscriptionsList.isEmpty()) {
172             return null;
173         }
174 
175         // Converts [1,2,3,4,-1] to "'1','2','3','4','-1'" so that it can be appended to
176         // selection string
177         String subIdListStr = associatedSubscriptionsList.stream()
178                 .map(subInfo -> ("'" + subInfo.getSubscriptionId() + "'"))
179                 .collect(Collectors.joining(","));
180         String selectionBySubId = (Telephony.Sms.SUBSCRIPTION_ID + " IN (" + subIdListStr + ")");
181         if (Log.isLoggable(TAG, Log.VERBOSE)) {
182             Log.d(TAG, "getSelectionBySubIds: " + selectionBySubId);
183         }
184         return selectionBySubId;
185     }
186 
187     /**
188      * Get emergency number list in the format of a selection string.
189      * @param context context
190      * @return emergency number list in the format of a selection string
191      * or {@code null} if emergency number list is empty.
192      */
193     @Nullable
getSelectionByEmergencyNumbers(@onNull Context context)194     public static String getSelectionByEmergencyNumbers(@NonNull Context context) {
195         // Get emergency number list to add it to selection string.
196         TelephonyManager tm = context.getSystemService(TelephonyManager.class);
197         Map<Integer, List<EmergencyNumber>> emergencyNumberList = null;
198         try {
199             if (tm != null) {
200                 emergencyNumberList = tm.getEmergencyNumberList();
201             }
202         } catch (Exception e) {
203             Log.e(TAG, "Cannot get emergency number list: " + e);
204         }
205 
206         String selectionByEmergencyNumber = null;
207         if (emergencyNumberList != null && !emergencyNumberList.isEmpty()) {
208             String emergencyNumberListStr = "";
209             for (Map.Entry<Integer, List<EmergencyNumber>> entry : emergencyNumberList.entrySet()) {
210                 if (!emergencyNumberListStr.isEmpty() && !entry.getValue().isEmpty()) {
211                     emergencyNumberListStr += ',';
212                 }
213 
214                 emergencyNumberListStr += entry.getValue().stream()
215                         .map(emergencyNumber -> ("'" + emergencyNumber.getNumber() + "'"))
216                         .collect(Collectors.joining(","));
217             }
218             selectionByEmergencyNumber = Telephony.Sms.ADDRESS +
219                     " IN (" + emergencyNumberListStr + ")";
220         }
221         return selectionByEmergencyNumber;
222     }
223 }
224