Home | History | Annotate | Download | only in telecom
      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.app.role.RoleManager;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.pm.ActivityInfo;
     22 import android.content.pm.PackageManager;
     23 import android.content.pm.ResolveInfo;
     24 import android.net.Uri;
     25 import android.os.AsyncTask;
     26 import android.os.Binder;
     27 import android.os.Process;
     28 import android.os.UserHandle;
     29 import android.text.TextUtils;
     30 import android.util.Slog;
     31 
     32 import com.android.internal.util.CollectionUtils;
     33 
     34 import java.util.ArrayList;
     35 import java.util.List;
     36 import java.util.concurrent.CompletableFuture;
     37 import java.util.concurrent.ExecutionException;
     38 import java.util.concurrent.TimeUnit;
     39 import java.util.concurrent.TimeoutException;
     40 import java.util.function.Consumer;
     41 
     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  */
     48 public class DefaultDialerManager {
     49     private static final String TAG = "DefaultDialerManager";
     50 
     51     /**
     52      * 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.
     55      *
     56      * @return {@code true} if the default dialer application was successfully changed,
     57      *         {@code false} otherwise.
     58      *
     59      * @hide
     60      * */
     61     public static boolean setDefaultDialerApplication(Context context, String packageName) {
     62         return setDefaultDialerApplication(context, packageName, ActivityManager.getCurrentUser());
     63     }
     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      *
     70      * @return {@code true} if the default dialer application was successfully changed,
     71      *         {@code false} otherwise.
     72      *
     73      * @hide
     74      * */
     75     public static boolean setDefaultDialerApplication(Context context, String packageName,
     76             int user) {
     77         long identity = Binder.clearCallingIdentity();
     78         try {
     79             CompletableFuture<Void> future = new CompletableFuture<>();
     80             Consumer<Boolean> callback = successful -> {
     81                 if (successful) {
     82                     future.complete(null);
     83                 } else {
     84                     future.completeExceptionally(new RuntimeException());
     85                 }
     86             };
     87             context.getSystemService(RoleManager.class).addRoleHolderAsUser(
     88                     RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(user),
     89                     AsyncTask.THREAD_POOL_EXECUTOR, callback);
     90             future.get(5, TimeUnit.SECONDS);
     91             return true;
     92         } catch (InterruptedException | ExecutionException | TimeoutException e) {
     93             Slog.e(TAG, "Failed to set default dialer to " + packageName + " for user " + user, e);
     94             return false;
     95         } finally {
     96             Binder.restoreCallingIdentity(identity);
     97         }
     98     }
     99 
    100     /**
    101      * Returns the installed dialer application for the current user that will be used to receive
    102      * incoming calls, and is allowed to make emergency calls.
    103      *
    104      * The application will be returned in order of preference:
    105      * 1) User selected phone application (if still installed)
    106      * 2) Pre-installed system dialer (if not disabled)
    107      * 3) Null
    108      *
    109      * The caller of this method needs to have permission to manage users on the device.
    110      *
    111      * @hide
    112      * */
    113     public static String getDefaultDialerApplication(Context context) {
    114         return getDefaultDialerApplication(context, context.getUserId());
    115     }
    116 
    117     /**
    118      * Returns the installed dialer application for the specified user that will be used to receive
    119      * incoming calls, and is allowed to make emergency calls.
    120      *
    121      * The application will be returned in order of preference:
    122      * 1) User selected phone application (if still installed)
    123      * 2) Pre-installed system dialer (if not disabled)
    124      * 3) Null
    125      *
    126      * The caller of this method needs to have permission to manage users on the device.
    127      *
    128      * @hide
    129      * */
    130     public static String getDefaultDialerApplication(Context context, int user) {
    131         long identity = Binder.clearCallingIdentity();
    132         try {
    133             return CollectionUtils.firstOrNull(context.getSystemService(RoleManager.class)
    134                     .getRoleHoldersAsUser(RoleManager.ROLE_DIALER, UserHandle.of(user)));
    135         } finally {
    136             Binder.restoreCallingIdentity(identity);
    137         }
    138     }
    139 
    140     /**
    141      * Returns a list of installed and available dialer applications.
    142      *
    143      * In order to appear in the list, a dialer application must implement an intent-filter with
    144      * the DIAL intent for the following schemes:
    145      *
    146      * 1) Empty scheme
    147      * 2) tel Uri scheme
    148      *
    149      * @hide
    150      **/
    151     public static List<String> getInstalledDialerApplications(Context context, int userId) {
    152         PackageManager packageManager = context.getPackageManager();
    153 
    154         // Get the list of apps registered for the DIAL intent with empty scheme
    155         Intent intent = new Intent(Intent.ACTION_DIAL);
    156         List<ResolveInfo> resolveInfoList =
    157                 packageManager.queryIntentActivitiesAsUser(intent, 0, userId);
    158 
    159         List<String> packageNames = new ArrayList<>();
    160 
    161         for (ResolveInfo resolveInfo : resolveInfoList) {
    162             final ActivityInfo activityInfo = resolveInfo.activityInfo;
    163             if (activityInfo != null
    164                     && !packageNames.contains(activityInfo.packageName)
    165                     // ignore cross profile intent handler
    166                     && resolveInfo.targetUserId == UserHandle.USER_CURRENT) {
    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, userId);
    174     }
    175 
    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      */
    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      * @param userId The UserId
    208      * @return The filtered list.
    209      */
    210     private static List<String> filterByIntent(Context context, List<String> packageNames,
    211             Intent intent, int userId) {
    212         if (packageNames == null || packageNames.isEmpty()) {
    213             return new ArrayList<>();
    214         }
    215 
    216         final List<String> result = new ArrayList<>();
    217         final List<ResolveInfo> resolveInfoList = context.getPackageManager()
    218                 .queryIntentActivitiesAsUser(intent, 0, userId);
    219         final int length = resolveInfoList.size();
    220         for (int i = 0; i < length; i++) {
    221             final ActivityInfo info = resolveInfoList.get(i).activityInfo;
    222             if (info != null && packageNames.contains(info.packageName)
    223                     && !result.contains(info.packageName)) {
    224                 result.add(info.packageName);
    225             }
    226         }
    227 
    228         return result;
    229     }
    230 
    231 
    232     private static TelecomManager getTelecomManager(Context context) {
    233         return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
    234     }
    235 }
    236