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