• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.phone;
18 
19 import android.app.role.RoleManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ApplicationInfo;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.os.AsyncTask;
28 import android.os.Binder;
29 import android.os.Process;
30 import android.telephony.TelephonyManager;
31 import android.text.TextUtils;
32 import android.util.Log;
33 
34 import com.android.internal.util.CollectionUtils;
35 
36 import java.util.List;
37 
38 /**
39  * A helper to query activities of emergency assistance.
40  */
41 public class EmergencyAssistanceHelper {
42     private static final String TAG = EmergencyAssistanceHelper.class.getSimpleName();
43     /**
44      * Get intent action of target emergency app.
45      *
46      * @return A string of intent action to launch target emergency app.
47      */
getIntentAction()48     public static String getIntentAction() {
49         return TelephonyManager.ACTION_EMERGENCY_ASSISTANCE;
50     }
51 
52     /**
53      * Query activities of emergency assistance.
54      *
55      * @param context The context of the application.
56      * @return A list of {@link ResolveInfo} which is queried from default assistance package,
57      * or null if there is no installed system application of emergency assistance.
58      */
resolveAssistPackageAndQueryActivities(Context context)59     public static List<ResolveInfo> resolveAssistPackageAndQueryActivities(Context context) {
60         final String assistPackage = getDefaultEmergencyPackage(context);
61         List<ResolveInfo> infos = queryAssistActivities(context, assistPackage);
62         if (infos == null || infos.isEmpty()) {
63             PackageManager packageManager = context.getPackageManager();
64             Intent queryIntent = new Intent(getIntentAction());
65             infos = packageManager.queryIntentActivities(queryIntent, 0);
66 
67             PackageInfo bestMatch = null;
68             for (int i = 0; i < infos.size(); i++) {
69                 if (infos.get(i).activityInfo == null) continue;
70                 String packageName = infos.get(i).activityInfo.packageName;
71                 PackageInfo packageInfo;
72                 try {
73                     packageInfo = packageManager.getPackageInfo(packageName, 0);
74                 } catch (PackageManager.NameNotFoundException e) {
75                     continue;
76                 }
77                 // Get earliest installed system app.
78                 if (isSystemApp(packageInfo) && (bestMatch == null
79                         || bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
80                     bestMatch = packageInfo;
81                 }
82             }
83 
84             if (bestMatch != null) {
85                 setDefaultEmergencyPackageAsync(context, bestMatch.packageName);
86                 return queryAssistActivities(context, bestMatch.packageName);
87             } else {
88                 return null;
89             }
90         } else {
91             return infos;
92         }
93     }
94 
95     /**
96      * Compose {@link ComponentName} from {@link ResolveInfo}.
97      */
getComponentName(ResolveInfo resolveInfo)98     public static ComponentName getComponentName(ResolveInfo resolveInfo) {
99         if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
100         return new ComponentName(resolveInfo.activityInfo.packageName,
101                 resolveInfo.activityInfo.name);
102     }
103 
queryAssistActivities(Context context, String assistPackage)104     private static List<ResolveInfo> queryAssistActivities(Context context, String assistPackage) {
105         List<ResolveInfo> infos = null;
106 
107         if (!TextUtils.isEmpty(assistPackage)) {
108             Intent queryIntent = new Intent(getIntentAction())
109                     .setPackage(assistPackage);
110             infos = context.getPackageManager().queryIntentActivities(queryIntent, 0);
111         }
112         return infos;
113     }
114 
isSystemApp(PackageInfo info)115     private static boolean isSystemApp(PackageInfo info) {
116         return info.applicationInfo != null
117                 && (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
118     }
119 
getDefaultEmergencyPackage(Context context)120     private static String getDefaultEmergencyPackage(Context context) {
121         long identity = Binder.clearCallingIdentity();
122         try {
123             return CollectionUtils.firstOrNull(context.getSystemService(RoleManager.class)
124                     .getRoleHolders(RoleManager.ROLE_EMERGENCY));
125         } finally {
126             Binder.restoreCallingIdentity(identity);
127         }
128     }
129 
setDefaultEmergencyPackageAsync(Context context, String pkgName)130     private static boolean setDefaultEmergencyPackageAsync(Context context, String pkgName) {
131         long identity = Binder.clearCallingIdentity();
132         try {
133             context.getSystemService(RoleManager.class).addRoleHolderAsUser(
134                     RoleManager.ROLE_EMERGENCY, pkgName, 0, Process.myUserHandle(),
135                     AsyncTask.THREAD_POOL_EXECUTOR, successful -> {
136                         if (!successful) {
137                             Log.e(TAG, "Failed to set emergency default app.");
138                         }
139                     });
140         } finally {
141             Binder.restoreCallingIdentity(identity);
142         }
143         return true;
144     }
145 }
146