From 86100d18ad0bd5ae3267a0e0944d15f4fe94078a Mon Sep 17 00:00:00 2001 From: Adam Powell Date: Thu, 12 May 2016 16:13:17 -0700 Subject: [PATCH] Show package icon/label for resolved package-targeted implicit intents If we're going to show metadata about a resolved implicit intent that is targeted to a single package with multiple potential targets, populate the ResolveInfo with the label and icon of the target package's ApplicationInfo and set resolvePackageName. This helps use cases such as EXTRA_INITIAL_INTENTS in ChooserActivity, where sometimes apps set target packages but not components. Bug 28739056 Change-Id: I8070d341fccc139463c5ac8d66db45fce02252e5 --- .../android/internal/app/ChooserActivity.java | 24 ++++++++++-- .../server/pm/PackageManagerService.java | 37 +++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index ed6ab5674d719..a5b2a9194fd51 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -825,13 +825,31 @@ public class ChooserActivity extends ResolverActivity { if (ii == null) { continue; } - final ActivityInfo ai = ii.resolveActivityInfo(pm, 0); + + // We reimplement Intent#resolveActivityInfo here because if we have an + // implicit intent, we want the ResolveInfo returned by PackageManager + // instead of one we reconstruct ourselves. The ResolveInfo returned might + // have extra metadata and resolvePackageName set and we want to respect that. + ResolveInfo ri = null; + ActivityInfo ai = null; + final ComponentName cn = ii.getComponent(); + if (cn != null) { + try { + ai = pm.getActivityInfo(ii.getComponent(), 0); + ri = new ResolveInfo(); + ri.activityInfo = ai; + } catch (PackageManager.NameNotFoundException ignored) { + // ai will == null below + } + } + if (ai == null) { + ri = pm.resolveActivity(ii, PackageManager.MATCH_DEFAULT_ONLY); + ai = ri != null ? ri.activityInfo : null; + } if (ai == null) { Log.w(TAG, "No activity found for " + ii); continue; } - ResolveInfo ri = new ResolveInfo(); - ri.activityInfo = ai; UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); if (ii instanceof LabeledIntent) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index da8799d5c1bf2..a5104a6cd04b5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5009,6 +5009,25 @@ public class PackageManagerService extends IPackageManager.Stub { ri = new ResolveInfo(mResolveInfo); ri.activityInfo = new ActivityInfo(ri.activityInfo); ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction()); + // If all of the options come from the same package, show the application's + // label and icon instead of the generic resolver's. + // Some calls like Intent.resolveActivityInfo query the ResolveInfo from here + // and then throw away the ResolveInfo itself, meaning that the caller loses + // the resolvePackageName. Therefore the activityInfo.labelRes above provides + // a fallback for this case; we only set the target package's resources on + // the ResolveInfo, not the ActivityInfo. + final String intentPackage = intent.getPackage(); + if (!TextUtils.isEmpty(intentPackage) && allHavePackage(query, intentPackage)) { + final ApplicationInfo appi = query.get(0).activityInfo.applicationInfo; + ri.resolvePackageName = intentPackage; + if (userNeedsBadging(userId)) { + ri.noResourceId = true; + } else { + ri.icon = appi.icon; + } + ri.iconResourceId = appi.icon; + ri.labelRes = appi.labelRes; + } ri.activityInfo.applicationInfo = new ApplicationInfo( ri.activityInfo.applicationInfo); if (userId != 0) { @@ -5024,6 +5043,24 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } + /** + * Return true if the given list is not empty and all of its contents have + * an activityInfo with the given package name. + */ + private boolean allHavePackage(List list, String packageName) { + if (ArrayUtils.isEmpty(list)) { + return false; + } + for (int i = 0, N = list.size(); i < N; i++) { + final ResolveInfo ri = list.get(i); + final ActivityInfo ai = ri != null ? ri.activityInfo : null; + if (ai == null || !packageName.equals(ai.packageName)) { + return false; + } + } + return true; + } + private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags, List query, boolean debug, int userId) { final int N = query.size();