1 /* 2 * Copyright (C) 2019 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.systemui; 18 19 import android.app.PendingIntent; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.pm.ActivityInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.ResolveInfo; 25 26 import com.android.systemui.dagger.SysUISingleton; 27 28 import java.util.List; 29 30 import javax.inject.Inject; 31 32 /** 33 * Contains useful methods for querying properties of an Activity Intent. 34 */ 35 @SysUISingleton 36 public class ActivityIntentHelper { 37 38 private final PackageManager mPm; 39 40 @Inject ActivityIntentHelper(Context context)41 public ActivityIntentHelper(Context context) { 42 // TODO: inject a package manager, not a context. 43 mPm = context.getPackageManager(); 44 } 45 46 /** 47 * Determines if sending the given intent would result in starting an Intent resolver activity, 48 * instead of resolving to a specific component. 49 * 50 * @param intent the intent 51 * @param currentUserId the id for the user to resolve as 52 * @return true if the intent would launch a resolver activity 53 */ wouldLaunchResolverActivity(Intent intent, int currentUserId)54 public boolean wouldLaunchResolverActivity(Intent intent, int currentUserId) { 55 ActivityInfo targetActivityInfo = getTargetActivityInfo(intent, currentUserId, 56 false /* onlyDirectBootAware */); 57 return targetActivityInfo == null; 58 } 59 60 /** 61 * @see #wouldLaunchResolverActivity(Intent, int) 62 */ wouldPendingLaunchResolverActivity(PendingIntent intent, int currentUserId)63 public boolean wouldPendingLaunchResolverActivity(PendingIntent intent, int currentUserId) { 64 ActivityInfo targetActivityInfo = getPendingTargetActivityInfo(intent, currentUserId, 65 false /* onlyDirectBootAware */); 66 return targetActivityInfo == null; 67 } 68 69 /** 70 * Returns info about the target Activity of a given intent, or null if the intent does not 71 * resolve to a specific component meeting the requirements. 72 * 73 * @param onlyDirectBootAware a boolean indicating whether the matched activity packages must 74 * be direct boot aware when in direct boot mode if false, all packages are considered 75 * a match even if they are not aware. 76 * @return the target activity info of the intent it resolves to a specific package or 77 * {@code null} if it resolved to the resolver activity 78 */ getTargetActivityInfo(Intent intent, int currentUserId, boolean onlyDirectBootAware)79 public ActivityInfo getTargetActivityInfo(Intent intent, int currentUserId, 80 boolean onlyDirectBootAware) { 81 int flags = PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA; 82 if (!onlyDirectBootAware) { 83 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE 84 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 85 } 86 final List<ResolveInfo> appList = mPm.queryIntentActivitiesAsUser( 87 intent, flags, currentUserId); 88 if (appList.size() == 0) { 89 return null; 90 } 91 if (appList.size() == 1) { 92 return appList.get(0).activityInfo; 93 } 94 ResolveInfo resolved = mPm.resolveActivityAsUser(intent, flags, currentUserId); 95 if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) { 96 return null; 97 } else { 98 return resolved.activityInfo; 99 } 100 } 101 102 /** 103 * @see #getTargetActivityInfo(Intent, int, boolean) 104 */ getPendingTargetActivityInfo(PendingIntent intent, int currentUserId, boolean onlyDirectBootAware)105 public ActivityInfo getPendingTargetActivityInfo(PendingIntent intent, int currentUserId, 106 boolean onlyDirectBootAware) { 107 int flags = PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA; 108 if (!onlyDirectBootAware) { 109 flags |= PackageManager.MATCH_DIRECT_BOOT_AWARE 110 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; 111 } 112 final List<ResolveInfo> appList = intent.queryIntentComponents(flags); 113 if (appList.size() == 0) { 114 return null; 115 } 116 if (appList.size() == 1) { 117 return appList.get(0).activityInfo; 118 } 119 ResolveInfo resolved = mPm.resolveActivityAsUser(intent.getIntent(), flags, currentUserId); 120 if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) { 121 return null; 122 } else { 123 return resolved.activityInfo; 124 } 125 } 126 127 /** 128 * Determines if the given intent resolves to an Activity which is allowed to appear above 129 * the lock screen. 130 * 131 * @param intent the intent to resolve 132 * @return true if the launched Activity would appear above the lock screen 133 */ wouldShowOverLockscreen(Intent intent, int currentUserId)134 public boolean wouldShowOverLockscreen(Intent intent, int currentUserId) { 135 ActivityInfo targetActivityInfo = getTargetActivityInfo(intent, 136 currentUserId, false /* onlyDirectBootAware */); 137 return targetActivityInfo != null 138 && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED 139 | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0; 140 } 141 142 /** 143 * @see #wouldShowOverLockscreen(Intent, int) 144 */ wouldPendingShowOverLockscreen(PendingIntent intent, int currentUserId)145 public boolean wouldPendingShowOverLockscreen(PendingIntent intent, int currentUserId) { 146 ActivityInfo targetActivityInfo = getPendingTargetActivityInfo(intent, 147 currentUserId, false /* onlyDirectBootAware */); 148 return targetActivityInfo != null 149 && (targetActivityInfo.flags & (ActivityInfo.FLAG_SHOW_WHEN_LOCKED 150 | ActivityInfo.FLAG_SHOW_FOR_ALL_USERS)) > 0; 151 } 152 153 /** 154 * Determines if sending the given intent would result in starting an Intent resolver activity, 155 * instead of resolving to a specific component. 156 * 157 * @param resolved the resolveInfo for the intent as returned by resolveActivityAsUser 158 * @param appList a list of resolveInfo as returned by queryIntentActivitiesAsUser 159 * @return true if the intent would launch a resolver activity 160 */ wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList)161 public boolean wouldLaunchResolverActivity(ResolveInfo resolved, List<ResolveInfo> appList) { 162 // If the list contains the above resolved activity, then it can't be 163 // ResolverActivity itself. 164 for (int i = 0; i < appList.size(); i++) { 165 ResolveInfo tmp = appList.get(i); 166 if (tmp.activityInfo.name.equals(resolved.activityInfo.name) 167 && tmp.activityInfo.packageName.equals(resolved.activityInfo.packageName)) { 168 return false; 169 } 170 } 171 return true; 172 } 173 } 174