From 56f0ff3c48c88b969d9bf5e62eb1ee590e03e461 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 13 Aug 2015 16:29:33 -0700 Subject: Make "Ask every time" actually work that way ..in link-opening behavior. If a candidate is marked as "ask every time," then the user is guaranteed to get a disambiguation prompt including that candidate even when some other candidate app is in the "always prefer this over a browser" state. Bug 23147746 Change-Id: I904d8697a992b3f16f32b1c1b49c2bf9424c7137 --- cmds/pm/src/com/android/commands/pm/Pm.java | 7 ++++- .../content/pm/IntentFilterVerificationInfo.java | 5 ++++ core/java/android/content/pm/PackageManager.java | 12 ++++++++ .../android/server/pm/PackageManagerService.java | 33 ++++++++++++++++++++-- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index b39376c22be7..9f385fef0a89 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -19,6 +19,7 @@ package com.android.commands.pm; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import android.app.ActivityManager; @@ -840,7 +841,7 @@ public final class Pm { return Integer.toString(result); } - // pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined} + // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined} private int runSetAppLink() { int userId = UserHandle.USER_OWNER; @@ -889,6 +890,10 @@ public final class Pm { newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; break; + case "always-ask": + newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; + break; + case "never": newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; break; diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java index 4dbac05f4580..953b051ae6da 100644 --- a/core/java/android/content/pm/IntentFilterVerificationInfo.java +++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java @@ -19,6 +19,7 @@ package android.content.pm; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import android.os.Parcel; @@ -199,6 +200,10 @@ public final class IntentFilterVerificationInfo implements Parcelable { sb.append("never"); break; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK: + sb.append("always-ask"); + break; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: default: sb.append("undefined"); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 0f936fd693ed..c8e9402e6442 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1072,6 +1072,18 @@ public abstract class PackageManager { */ public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER = 3; + /** + * Used as the {@code status} argument for {@link PackageManager#updateIntentVerificationStatus} + * to indicate that this app should always be considered as an ambiguous candidate for + * handling the matching Intent even if there are other candidate apps in the "always" + * state. Put another way: if there are any 'always ask' apps in a set of more than + * one candidate app, then a disambiguation is *always* presented even if there is + * another candidate app with the 'always' state. + * + * @hide + */ + public static final int INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK = 4; + /** * Can be used as the {@code millisecondsToDelay} argument for * {@link PackageManager#extendVerificationTimeout}. This is the diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 21e256e8970f..b9ed88b6b0a0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -56,6 +56,7 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST; import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR; @@ -4701,6 +4702,7 @@ public class PackageManagerService extends IPackageManager.Stub { ArrayList result = new ArrayList(); ArrayList alwaysList = new ArrayList(); ArrayList undefinedList = new ArrayList(); + ArrayList alwaysAskList = new ArrayList(); ArrayList neverList = new ArrayList(); ArrayList matchAllList = new ArrayList(); @@ -4737,6 +4739,11 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.i(TAG, " + never: " + info.activityInfo.packageName); } neverList.add(info); + } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) { + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.i(TAG, " + always-ask: " + info.activityInfo.packageName); + } + alwaysAskList.add(info); } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED || status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK) { if (DEBUG_DOMAIN_VERIFICATION) { @@ -4746,6 +4753,10 @@ public class PackageManagerService extends IPackageManager.Stub { } } } + + // We'll want to include browser possibilities in a few cases + boolean includeBrowser = false; + // First try to add the "always" resolution(s) for the current user, if any if (alwaysList.size() > 0) { result.addAll(alwaysList); @@ -4754,7 +4765,7 @@ public class PackageManagerService extends IPackageManager.Stub { == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) { result.add(xpDomainInfo.resolveInfo); } else { - // Add all undefined Apps as we want them to appear in the Disambiguation dialog. + // Add all undefined apps as we want them to appear in the disambiguation dialog. result.addAll(undefinedList); if (xpDomainInfo != null && ( xpDomainInfo.bestDomainVerificationStatus @@ -4763,7 +4774,25 @@ public class PackageManagerService extends IPackageManager.Stub { == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK)) { result.add(xpDomainInfo.resolveInfo); } - // Also add Browsers (all of them or only the default one) + includeBrowser = true; + } + + // The presence of any 'always ask' alternatives means we'll also offer browsers. + // If there were 'always' entries their preferred order has been set, so we also + // back that off to make the alternatives equivalent + if (alwaysAskList.size() > 0) { + for (ResolveInfo i : result) { + i.preferredOrder = 0; + } + result.addAll(alwaysAskList); + includeBrowser = true; + } + + if (includeBrowser) { + // Also add browsers (all of them or only the default one) + if (DEBUG_DOMAIN_VERIFICATION) { + Slog.v(TAG, " ...including browsers in candidate set"); + } if ((matchFlags & MATCH_ALL) != 0) { result.addAll(matchAllList); } else { -- cgit v1.2.3-59-g8ed1b