1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package android.telecom;
16 
17 import android.app.ActivityManager;
18 import android.content.Context;
19 import android.content.Intent;
20 import android.content.pm.ActivityInfo;
21 import android.content.pm.PackageManager;
22 import android.content.pm.ResolveInfo;
23 import android.net.Uri;
24 import android.os.Process;
25 import android.provider.Settings;
26 import android.text.TextUtils;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 /**
32  * Class for managing the default dialer application that will receive incoming calls, and be
33  * allowed to make emergency outgoing calls.
34  *
35  * @hide
36  */
37 public class DefaultDialerManager {
38     private static final String TAG = "DefaultDialerManager";
39 
40     /**
41      * Sets the specified package name as the default dialer application for the current user.
42      * The caller of this method needs to have permission to write to secure settings and
43      * manage users on the device.
44      *
45      * @return {@code true} if the default dialer application was successfully changed,
46      *         {@code false} otherwise.
47      *
48      * @hide
49      * */
setDefaultDialerApplication(Context context, String packageName)50     public static boolean setDefaultDialerApplication(Context context, String packageName) {
51         return setDefaultDialerApplication(context, packageName, ActivityManager.getCurrentUser());
52     }
53 
54     /**
55      * Sets the specified package name as the default dialer application for the specified user.
56      * The caller of this method needs to have permission to write to secure settings and
57      * manage users on the device.
58      *
59      * @return {@code true} if the default dialer application was successfully changed,
60      *         {@code false} otherwise.
61      *
62      * @hide
63      * */
setDefaultDialerApplication(Context context, String packageName, int user)64     public static boolean setDefaultDialerApplication(Context context, String packageName,
65             int user) {
66         // Get old package name
67         String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
68                 Settings.Secure.DIALER_DEFAULT_APPLICATION, user);
69 
70         if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
71             // No change
72             return false;
73         }
74 
75         // Only make the change if the new package belongs to a valid phone application
76         List<String> packageNames = getInstalledDialerApplications(context);
77 
78         if (packageNames.contains(packageName)) {
79             // Update the secure setting.
80             Settings.Secure.putStringForUser(context.getContentResolver(),
81                     Settings.Secure.DIALER_DEFAULT_APPLICATION, packageName, user);
82             return true;
83         }
84         return false;
85     }
86 
87     /**
88      * Returns the installed dialer application for the current user that will be used to receive
89      * incoming calls, and is allowed to make emergency calls.
90      *
91      * The application will be returned in order of preference:
92      * 1) User selected phone application (if still installed)
93      * 2) Pre-installed system dialer (if not disabled)
94      * 3) Null
95      *
96      * The caller of this method needs to have permission to manage users on the device.
97      *
98      * @hide
99      * */
getDefaultDialerApplication(Context context)100     public static String getDefaultDialerApplication(Context context) {
101         return getDefaultDialerApplication(context, context.getUserId());
102     }
103 
104     /**
105      * Returns the installed dialer application for the specified user that will be used to receive
106      * incoming calls, and is allowed to make emergency calls.
107      *
108      * The application will be returned in order of preference:
109      * 1) User selected phone application (if still installed)
110      * 2) Pre-installed system dialer (if not disabled)
111      * 3) Null
112      *
113      * The caller of this method needs to have permission to manage users on the device.
114      *
115      * @hide
116      * */
getDefaultDialerApplication(Context context, int user)117     public static String getDefaultDialerApplication(Context context, int user) {
118         String defaultPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
119                 Settings.Secure.DIALER_DEFAULT_APPLICATION, user);
120 
121         final List<String> packageNames = getInstalledDialerApplications(context);
122 
123         // Verify that the default dialer has not been disabled or uninstalled.
124         if (packageNames.contains(defaultPackageName)) {
125             return defaultPackageName;
126         }
127 
128         // No user-set dialer found, fallback to system dialer
129         String systemDialerPackageName = getTelecomManager(context).getSystemDialerPackage();
130 
131         if (TextUtils.isEmpty(systemDialerPackageName)) {
132             // No system dialer configured at build time
133             return null;
134         }
135 
136         if (packageNames.contains(systemDialerPackageName)) {
137             return systemDialerPackageName;
138         } else {
139             return null;
140         }
141     }
142 
143     /**
144      * Returns a list of installed and available dialer applications.
145      *
146      * In order to appear in the list, a dialer application must implement an intent-filter with
147      * the DIAL intent for the following schemes:
148      *
149      * 1) Empty scheme
150      * 2) tel Uri scheme
151      *
152      * @hide
153      **/
getInstalledDialerApplications(Context context, int userId)154     public static List<String> getInstalledDialerApplications(Context context, int userId) {
155         PackageManager packageManager = context.getPackageManager();
156 
157         // Get the list of apps registered for the DIAL intent with empty scheme
158         Intent intent = new Intent(Intent.ACTION_DIAL);
159         List<ResolveInfo> resolveInfoList =
160                 packageManager.queryIntentActivitiesAsUser(intent, 0, userId);
161 
162         List<String> packageNames = new ArrayList<>();
163 
164         for (ResolveInfo resolveInfo : resolveInfoList) {
165             final ActivityInfo activityInfo = resolveInfo.activityInfo;
166             if (activityInfo != null && !packageNames.contains(activityInfo.packageName)) {
167                 packageNames.add(activityInfo.packageName);
168             }
169         }
170 
171         final Intent dialIntentWithTelScheme = new Intent(Intent.ACTION_DIAL);
172         dialIntentWithTelScheme.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, "", null));
173         return filterByIntent(context, packageNames, dialIntentWithTelScheme);
174     }
175 
getInstalledDialerApplications(Context context)176     public static List<String> getInstalledDialerApplications(Context context) {
177         return getInstalledDialerApplications(context, Process.myUserHandle().getIdentifier());
178     }
179 
180     /**
181      * Determines if the package name belongs to the user-selected default dialer or the preloaded
182      * system dialer, and thus should be allowed to perform certain privileged operations.
183      *
184      * @param context A valid context.
185      * @param packageName of the package to check for.
186      *
187      * @return {@code true} if the provided package name corresponds to the user-selected default
188      *         dialer or the preloaded system dialer, {@code false} otherwise.
189      *
190      * @hide
191      */
isDefaultOrSystemDialer(Context context, String packageName)192     public static boolean isDefaultOrSystemDialer(Context context, String packageName) {
193         if (TextUtils.isEmpty(packageName)) {
194             return false;
195         }
196         final TelecomManager tm = getTelecomManager(context);
197         return packageName.equals(tm.getDefaultDialerPackage())
198                 || packageName.equals(tm.getSystemDialerPackage());
199     }
200 
201     /**
202      * Filter a given list of package names for those packages that contain an activity that has
203      * an intent filter for a given intent.
204      *
205      * @param context A valid context
206      * @param packageNames List of package names to filter.
207      * @return The filtered list.
208      */
filterByIntent(Context context, List<String> packageNames, Intent intent)209     private static List<String> filterByIntent(Context context, List<String> packageNames,
210             Intent intent) {
211         if (packageNames == null || packageNames.isEmpty()) {
212             return new ArrayList<>();
213         }
214 
215         final List<String> result = new ArrayList<>();
216         final List<ResolveInfo> resolveInfoList = context.getPackageManager()
217                 .queryIntentActivities(intent, 0);
218         final int length = resolveInfoList.size();
219         for (int i = 0; i < length; i++) {
220             final ActivityInfo info = resolveInfoList.get(i).activityInfo;
221             if (info != null && packageNames.contains(info.packageName)
222                     && !result.contains(info.packageName)) {
223                 result.add(info.packageName);
224             }
225         }
226 
227         return result;
228     }
229 
230 
getTelecomManager(Context context)231     private static TelecomManager getTelecomManager(Context context) {
232         return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
233     }
234 }
235