blob: aac0956d43395bad33e8207835cb39353448265d [file] [log] [blame]
Yorke Lee014de022015-04-21 17:15:47 -07001/*
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
15package android.telecom;
16
Yorke Lee6526f672015-05-04 17:07:32 -070017import android.app.ActivityManager;
Eugene Susla92b88c72019-01-11 13:31:20 -080018import android.app.role.RoleManager;
19import android.app.role.RoleManagerCallback;
Yorke Lee014de022015-04-21 17:15:47 -070020import android.content.Context;
21import android.content.Intent;
22import android.content.pm.ActivityInfo;
23import android.content.pm.PackageManager;
24import android.content.pm.ResolveInfo;
Hai Zhangb73ec012019-01-30 15:34:45 -080025import android.content.pm.ServiceInfo;
Yorke Lee856a5ac2015-04-28 15:45:42 -070026import android.net.Uri;
Eugene Susla92b88c72019-01-11 13:31:20 -080027import android.os.AsyncTask;
28import android.os.Binder;
Tony Makb401a942016-01-19 19:05:18 +000029import android.os.Process;
Tony Mak39198fa2017-09-15 17:41:43 +010030import android.os.UserHandle;
Yorke Lee014de022015-04-21 17:15:47 -070031import android.text.TextUtils;
Eugene Susla98a872d2019-01-31 18:30:47 -080032import android.util.Slog;
Yorke Lee014de022015-04-21 17:15:47 -070033
Eugene Susla92b88c72019-01-11 13:31:20 -080034import com.android.internal.util.CollectionUtils;
35
Yorke Lee014de022015-04-21 17:15:47 -070036import java.util.ArrayList;
37import java.util.List;
Eugene Susla98a872d2019-01-31 18:30:47 -080038import java.util.concurrent.ExecutionException;
39import java.util.concurrent.TimeUnit;
40import java.util.concurrent.TimeoutException;
Yorke Lee014de022015-04-21 17:15:47 -070041
42/**
43 * Class for managing the default dialer application that will receive incoming calls, and be
44 * allowed to make emergency outgoing calls.
45 *
46 * @hide
47 */
48public class DefaultDialerManager {
49 private static final String TAG = "DefaultDialerManager";
50
51 /**
Yorke Lee6526f672015-05-04 17:07:32 -070052 * Sets the specified package name as the default dialer application for the current user.
53 * The caller of this method needs to have permission to write to secure settings and
54 * manage users on the device.
Yorke Lee014de022015-04-21 17:15:47 -070055 *
Yorke Leedb6da482015-06-02 13:55:25 -070056 * @return {@code true} if the default dialer application was successfully changed,
57 * {@code false} otherwise.
58 *
Yorke Lee014de022015-04-21 17:15:47 -070059 * @hide
60 * */
Yorke Leedb6da482015-06-02 13:55:25 -070061 public static boolean setDefaultDialerApplication(Context context, String packageName) {
62 return setDefaultDialerApplication(context, packageName, ActivityManager.getCurrentUser());
Yorke Lee6526f672015-05-04 17:07:32 -070063 }
64
65 /**
66 * Sets the specified package name as the default dialer application for the specified user.
67 * The caller of this method needs to have permission to write to secure settings and
68 * manage users on the device.
69 *
Yorke Leedb6da482015-06-02 13:55:25 -070070 * @return {@code true} if the default dialer application was successfully changed,
71 * {@code false} otherwise.
72 *
Yorke Lee6526f672015-05-04 17:07:32 -070073 * @hide
74 * */
Yorke Leedb6da482015-06-02 13:55:25 -070075 public static boolean setDefaultDialerApplication(Context context, String packageName,
76 int user) {
Eugene Susla92b88c72019-01-11 13:31:20 -080077 long identity = Binder.clearCallingIdentity();
78 try {
Eugene Susla98a872d2019-01-31 18:30:47 -080079 RoleManagerCallback.Future cb = new RoleManagerCallback.Future();
Eugene Susla92b88c72019-01-11 13:31:20 -080080 context.getSystemService(RoleManager.class).addRoleHolderAsUser(
Hai Zhang71d70362019-02-04 16:17:38 -080081 RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(user),
Eugene Susla98a872d2019-01-31 18:30:47 -080082 AsyncTask.THREAD_POOL_EXECUTOR, cb);
83 cb.get(5, TimeUnit.SECONDS);
Yorke Leedb6da482015-06-02 13:55:25 -070084 return true;
Eugene Susla98a872d2019-01-31 18:30:47 -080085 } catch (InterruptedException | ExecutionException | TimeoutException e) {
86 Slog.e(TAG, "Failed to set default dialer to " + packageName + " for user " + user, e);
87 return false;
Eugene Susla92b88c72019-01-11 13:31:20 -080088 } finally {
89 Binder.restoreCallingIdentity(identity);
Yorke Lee014de022015-04-21 17:15:47 -070090 }
91 }
92
93 /**
Yorke Lee6526f672015-05-04 17:07:32 -070094 * Returns the installed dialer application for the current user that will be used to receive
95 * incoming calls, and is allowed to make emergency calls.
Yorke Lee014de022015-04-21 17:15:47 -070096 *
97 * The application will be returned in order of preference:
98 * 1) User selected phone application (if still installed)
99 * 2) Pre-installed system dialer (if not disabled)
100 * 3) Null
101 *
Yorke Lee6526f672015-05-04 17:07:32 -0700102 * The caller of this method needs to have permission to manage users on the device.
103 *
Yorke Lee014de022015-04-21 17:15:47 -0700104 * @hide
105 * */
Yorke Lee8e0207b2015-04-28 09:39:20 -0700106 public static String getDefaultDialerApplication(Context context) {
Svet Ganov52153f42015-08-11 08:59:12 -0700107 return getDefaultDialerApplication(context, context.getUserId());
Yorke Lee6526f672015-05-04 17:07:32 -0700108 }
Yorke Lee014de022015-04-21 17:15:47 -0700109
Yorke Lee6526f672015-05-04 17:07:32 -0700110 /**
111 * Returns the installed dialer application for the specified user that will be used to receive
112 * incoming calls, and is allowed to make emergency calls.
113 *
114 * The application will be returned in order of preference:
115 * 1) User selected phone application (if still installed)
116 * 2) Pre-installed system dialer (if not disabled)
117 * 3) Null
118 *
119 * The caller of this method needs to have permission to manage users on the device.
120 *
121 * @hide
122 * */
123 public static String getDefaultDialerApplication(Context context, int user) {
Eugene Susla92b88c72019-01-11 13:31:20 -0800124 long identity = Binder.clearCallingIdentity();
125 try {
126 return CollectionUtils.firstOrNull(context.getSystemService(RoleManager.class)
127 .getRoleHoldersAsUser(RoleManager.ROLE_DIALER, UserHandle.of(user)));
128 } finally {
129 Binder.restoreCallingIdentity(identity);
Yorke Lee8e0207b2015-04-28 09:39:20 -0700130 }
Yorke Lee014de022015-04-21 17:15:47 -0700131 }
132
133 /**
134 * Returns a list of installed and available dialer applications.
135 *
136 * In order to appear in the list, a dialer application must implement an intent-filter with
137 * the DIAL intent for the following schemes:
138 *
139 * 1) Empty scheme
140 * 2) tel Uri scheme
141 *
142 * @hide
143 **/
Tony Makb401a942016-01-19 19:05:18 +0000144 public static List<String> getInstalledDialerApplications(Context context, int userId) {
Yorke Lee014de022015-04-21 17:15:47 -0700145 PackageManager packageManager = context.getPackageManager();
146
147 // Get the list of apps registered for the DIAL intent with empty scheme
148 Intent intent = new Intent(Intent.ACTION_DIAL);
Tony Makb401a942016-01-19 19:05:18 +0000149 List<ResolveInfo> resolveInfoList =
150 packageManager.queryIntentActivitiesAsUser(intent, 0, userId);
Yorke Lee014de022015-04-21 17:15:47 -0700151
Yorke Lee8e0207b2015-04-28 09:39:20 -0700152 List<String> packageNames = new ArrayList<>();
Yorke Lee014de022015-04-21 17:15:47 -0700153
154 for (ResolveInfo resolveInfo : resolveInfoList) {
155 final ActivityInfo activityInfo = resolveInfo.activityInfo;
Tony Mak39198fa2017-09-15 17:41:43 +0100156 if (activityInfo != null
157 && !packageNames.contains(activityInfo.packageName)
158 // ignore cross profile intent handler
159 && resolveInfo.targetUserId == UserHandle.USER_CURRENT) {
Yorke Lee856a5ac2015-04-28 15:45:42 -0700160 packageNames.add(activityInfo.packageName);
Yorke Lee014de022015-04-21 17:15:47 -0700161 }
Yorke Lee014de022015-04-21 17:15:47 -0700162 }
163
Yorke Lee856a5ac2015-04-28 15:45:42 -0700164 final Intent dialIntentWithTelScheme = new Intent(Intent.ACTION_DIAL);
165 dialIntentWithTelScheme.setData(Uri.fromParts(PhoneAccount.SCHEME_TEL, "", null));
Hai Zhangb73ec012019-01-30 15:34:45 -0800166 packageNames = filterByIntent(context, packageNames, dialIntentWithTelScheme, userId);
167 packageNames = requireInCallService(packageNames, userId, context);
168 return packageNames;
Yorke Lee014de022015-04-21 17:15:47 -0700169 }
170
Tony Makb401a942016-01-19 19:05:18 +0000171 public static List<String> getInstalledDialerApplications(Context context) {
172 return getInstalledDialerApplications(context, Process.myUserHandle().getIdentifier());
173 }
174
Yorke Lee014de022015-04-21 17:15:47 -0700175 /**
Yorke Lee61043822015-04-27 11:18:38 -0700176 * Determines if the package name belongs to the user-selected default dialer or the preloaded
177 * system dialer, and thus should be allowed to perform certain privileged operations.
178 *
179 * @param context A valid context.
180 * @param packageName of the package to check for.
181 *
182 * @return {@code true} if the provided package name corresponds to the user-selected default
183 * dialer or the preloaded system dialer, {@code false} otherwise.
184 *
185 * @hide
186 */
187 public static boolean isDefaultOrSystemDialer(Context context, String packageName) {
188 if (TextUtils.isEmpty(packageName)) {
189 return false;
190 }
191 final TelecomManager tm = getTelecomManager(context);
192 return packageName.equals(tm.getDefaultDialerPackage())
193 || packageName.equals(tm.getSystemDialerPackage());
194 }
195
Yorke Lee856a5ac2015-04-28 15:45:42 -0700196 /**
197 * Filter a given list of package names for those packages that contain an activity that has
198 * an intent filter for a given intent.
199 *
200 * @param context A valid context
201 * @param packageNames List of package names to filter.
Tyler Gunn0907bd62017-09-01 15:17:05 -0700202 * @param userId The UserId
Yorke Lee856a5ac2015-04-28 15:45:42 -0700203 * @return The filtered list.
204 */
205 private static List<String> filterByIntent(Context context, List<String> packageNames,
Tyler Gunn0907bd62017-09-01 15:17:05 -0700206 Intent intent, int userId) {
Yorke Lee856a5ac2015-04-28 15:45:42 -0700207 if (packageNames == null || packageNames.isEmpty()) {
208 return new ArrayList<>();
209 }
210
211 final List<String> result = new ArrayList<>();
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700212 final List<ResolveInfo> resolveInfoList = context.getPackageManager()
Tyler Gunn0907bd62017-09-01 15:17:05 -0700213 .queryIntentActivitiesAsUser(intent, 0, userId);
Yorke Lee856a5ac2015-04-28 15:45:42 -0700214 final int length = resolveInfoList.size();
215 for (int i = 0; i < length; i++) {
216 final ActivityInfo info = resolveInfoList.get(i).activityInfo;
217 if (info != null && packageNames.contains(info.packageName)
218 && !result.contains(info.packageName)) {
219 result.add(info.packageName);
220 }
221 }
222
223 return result;
224 }
225
Hai Zhangb73ec012019-01-30 15:34:45 -0800226 private static List<String> requireInCallService(List<String> packageNames, int userId,
227 Context context) {
228 if (packageNames == null || packageNames.isEmpty()) {
229 return new ArrayList<>();
230 }
231
232 final Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
233 final List<ResolveInfo> resolveInfoList = context.getPackageManager()
234 .queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, userId);
235 final List<String> result = new ArrayList<>();
236 final int length = resolveInfoList.size();
237 for (int i = 0; i < length; i++) {
238 final ServiceInfo info = resolveInfoList.get(i).serviceInfo;
239 if (info == null || info.metaData == null) {
240 continue;
241 }
242 if (!info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_UI)) {
243 continue;
244 }
245 if (info.metaData.getBoolean(TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI)) {
246 continue;
247 }
248 if (packageNames.contains(info.packageName) && !result.contains(info.packageName)) {
249 result.add(info.packageName);
250 }
251 }
252
253 return result;
254 }
Yorke Lee856a5ac2015-04-28 15:45:42 -0700255
Yorke Lee014de022015-04-21 17:15:47 -0700256 private static TelecomManager getTelecomManager(Context context) {
257 return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
258 }
259}