From 0d78363a39de01232097a90933cfeb9f8bbe823d Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 8 May 2017 09:47:55 -0700 Subject: [PATCH] Remove forward matches before checking for default A forward match is a intent-target (aka. match) that switches between the personal and work profile's intent resolver. This can be unnecessary if there are no work profile matches. We need to remove these unnecessary matches early as the default activity resolution code considers a system app as default _only_ if it is the only match. Before there could still the an unnecessary forward match under consideration. Test: Connected USB accessory that only matches a system app on the personal profile. Before we showed a confirm-dialog, now we consider the system app as default and automatically launch it. Fixes: 37530439 Change-Id: I7bc9b969fc0b9abae4d15dd3f268783d05b91f9a --- .../usb/UsbProfileGroupSettingsManager.java | 123 +++++++++++------- 1 file changed, 78 insertions(+), 45 deletions(-) diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java index 5399bb9e5d80c..840ae221df30c 100644 --- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java @@ -841,7 +841,7 @@ class UsbProfileGroupSettingsManager { // Only one of device and accessory should be non-null. private boolean packageMatchesLocked(ResolveInfo info, String metaDataName, UsbDevice device, UsbAccessory accessory) { - if (info.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { + if (isForwardMatch(info)) { return true; } @@ -901,6 +901,17 @@ class UsbProfileGroupSettingsManager { return resolveInfos; } + /** + * If this match used to forward the intent to another profile? + * + * @param match The match + * + * @return {@code true} iff this is such a forward match + */ + private boolean isForwardMatch(@NonNull ResolveInfo match) { + return match.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE); + } + /** * Only return those matches with the highest priority. * @@ -909,16 +920,23 @@ class UsbProfileGroupSettingsManager { * @return The matches with the highest priority */ @NonNull - private ArrayList preferHighPriority( - @NonNull ArrayList matches) { + private ArrayList preferHighPriority(@NonNull ArrayList matches) { SparseArray> highestPriorityMatchesByUserId = new SparseArray<>(); SparseIntArray highestPriorityByUserId = new SparseIntArray(); + ArrayList forwardMatches = new ArrayList<>(); // Create list of highest priority matches per user in highestPriorityMatchesByUserId int numMatches = matches.size(); for (int matchNum = 0; matchNum < numMatches; matchNum++) { ResolveInfo match = matches.get(matchNum); + // Unnecessary forward matches are filtered out later, hence collect them all to add + // them below + if (isForwardMatch(match)) { + forwardMatches.add(match); + continue; + } + // If this a previously unknown user? if (highestPriorityByUserId.indexOfKey(match.targetUserId) < 0) { highestPriorityByUserId.put(match.targetUserId, Integer.MIN_VALUE); @@ -940,9 +958,10 @@ class UsbProfileGroupSettingsManager { } } - // Combine all users back together. This means that all matches have the same priority for a - // user. Matches for different users might have different priority. - ArrayList combinedMatches = new ArrayList<>(); + // Combine all users (+ forward matches) back together. This means that all non-forward + // matches have the same priority for a user. Matches for different users might have + // different priority. + ArrayList combinedMatches = new ArrayList<>(forwardMatches); int numMatchArrays = highestPriorityMatchesByUserId.size(); for (int matchArrayNum = 0; matchArrayNum < numMatchArrays; matchArrayNum++) { combinedMatches.addAll(highestPriorityMatchesByUserId.valueAt(matchArrayNum)); @@ -951,6 +970,51 @@ class UsbProfileGroupSettingsManager { return combinedMatches; } + /** + * If there are no matches for a profile, remove the forward intent to this profile. + * + * @param rawMatches The matches that contain all forward intents + * + * @return The matches with the unnecessary forward intents removed + */ + @NonNull private ArrayList removeForwardIntentIfNotNeeded( + @NonNull ArrayList rawMatches) { + final int numRawMatches = rawMatches.size(); + + // The raw matches contain the activities that can be started but also the intents to + // forward the intent to the other profile + int numParentActivityMatches = 0; + int numNonParentActivityMatches = 0; + for (int i = 0; i < numRawMatches; i++) { + final ResolveInfo rawMatch = rawMatches.get(i); + if (!isForwardMatch(rawMatch)) { + if (UserHandle.getUserHandleForUid( + rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) { + numParentActivityMatches++; + } else { + numNonParentActivityMatches++; + } + } + } + + // If only one profile has activity matches, we need to remove all switch intents + if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) { + ArrayList matches = new ArrayList<>( + numParentActivityMatches + numNonParentActivityMatches); + + for (int i = 0; i < numRawMatches; i++) { + ResolveInfo rawMatch = rawMatches.get(i); + if (!isForwardMatch(rawMatch)) { + matches.add(rawMatch); + } + } + return matches; + + } else { + return rawMatches; + } + } + private final ArrayList getDeviceMatchesLocked(UsbDevice device, Intent intent) { ArrayList matches = new ArrayList(); List resolveInfos = queryIntentActivitiesForAllProfiles(intent); @@ -961,7 +1025,8 @@ class UsbProfileGroupSettingsManager { matches.add(resolveInfo); } } - return preferHighPriority(matches); + + return removeForwardIntentIfNotNeeded(preferHighPriority(matches)); } private final ArrayList getAccessoryMatchesLocked( @@ -975,7 +1040,8 @@ class UsbProfileGroupSettingsManager { matches.add(resolveInfo); } } - return preferHighPriority(matches); + + return removeForwardIntentIfNotNeeded(preferHighPriority(matches)); } public void deviceAttached(UsbDevice device) { @@ -1067,34 +1133,16 @@ class UsbProfileGroupSettingsManager { * Start the appropriate package when an device/accessory got attached. * * @param intent The intent to start the package - * @param rawMatches The available resolutions of the intent + * @param matches The available resolutions of the intent * @param defaultActivity The default activity for the device (if set) * @param device The device if a device was attached * @param accessory The accessory if a device was attached */ - private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList rawMatches, + private void resolveActivity(@NonNull Intent intent, @NonNull ArrayList matches, @Nullable ActivityInfo defaultActivity, @Nullable UsbDevice device, @Nullable UsbAccessory accessory) { - final int numRawMatches = rawMatches.size(); - - // The raw matches contain the activities that can be started but also the intents to switch - // between the profiles - int numParentActivityMatches = 0; - int numNonParentActivityMatches = 0; - for (int i = 0; i < numRawMatches; i++) { - final ResolveInfo rawMatch = rawMatches.get(i); - if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { - if (UserHandle.getUserHandleForUid( - rawMatch.activityInfo.applicationInfo.uid).equals(mParentUser)) { - numParentActivityMatches++; - } else { - numNonParentActivityMatches++; - } - } - } - // don't show the resolver activity if there are no choices available - if (numParentActivityMatches + numNonParentActivityMatches == 0) { + if (matches.size() == 0) { if (accessory != null) { String uri = accessory.getUri(); if (uri != null && uri.length() > 0) { @@ -1117,21 +1165,6 @@ class UsbProfileGroupSettingsManager { return; } - // If only one profile has activity matches, we need to remove all switch intents - ArrayList matches; - if (numParentActivityMatches == 0 || numNonParentActivityMatches == 0) { - matches = new ArrayList<>(numParentActivityMatches + numNonParentActivityMatches); - - for (int i = 0; i < numRawMatches; i++) { - ResolveInfo rawMatch = rawMatches.get(i); - if (!rawMatch.getComponentInfo().name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) { - matches.add(rawMatch); - } - } - } else { - matches = rawMatches; - } - if (defaultActivity != null) { UsbUserSettingsManager defaultRIUserSettings = mSettingsManager.getSettingsForUser( UserHandle.getUserId(defaultActivity.applicationInfo.uid)); @@ -1216,10 +1249,10 @@ class UsbProfileGroupSettingsManager { if (matches.size() == 1) { final ActivityInfo activityInfo = matches.get(0).activityInfo; if (activityInfo != null) { - // bypass dialog and launch the only matching activity if (mDisablePermissionDialogs) { return activityInfo; } + // System apps are considered default unless there are other matches if (activityInfo.applicationInfo != null && (activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {