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