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