Add filter ordering

Filter ordering allows automatic disambiguation between multiple filters
that matching a pattern. Ordering currently only works for EphemeralResolveInfo
objects.

Bug: 30837021
Change-Id: Ia217218c7c7d159dbd75d7733c45556e690d06d2
This commit is contained in:
Todd Kennedy
2016-09-08 15:34:03 -07:00
parent 7d59cb81f8
commit c2e96d45d2
3 changed files with 79 additions and 1 deletions

View File

@@ -265,6 +265,7 @@ public class IntentFilter implements Parcelable {
public static final String SCHEME_HTTPS = "https";
private int mPriority;
private int mOrder;
private final ArrayList<String> mActions;
private ArrayList<String> mCategories = null;
private ArrayList<String> mDataSchemes = null;
@@ -425,6 +426,7 @@ public class IntentFilter implements Parcelable {
*/
public IntentFilter(IntentFilter o) {
mPriority = o.mPriority;
mOrder = o.mOrder;
mActions = new ArrayList<String>(o.mActions);
if (o.mCategories != null) {
mCategories = new ArrayList<String>(o.mCategories);
@@ -477,6 +479,16 @@ public class IntentFilter implements Parcelable {
return mPriority;
}
/** @hide */
public final void setOrder(int order) {
mOrder = order;
}
/** @hide */
public final int getOrder() {
return mOrder;
}
/**
* Set whether this filter will needs to be automatically verified against its data URIs or not.
* The default is false.

View File

@@ -364,6 +364,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, listCut.get(i), resultList, userId);
}
filterResults(resultList);
sortResults(resultList);
return resultList;
}
@@ -457,6 +458,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
buildResolveList(intent, categories, debug, defaultOnly,
resolvedType, scheme, schemeCut, finalList, userId);
}
filterResults(finalList);
sortResults(finalList);
if (debug) {
@@ -521,6 +523,12 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
Collections.sort(results, mResolvePrioritySorter);
}
/**
* Apply filtering to the results. This happens before the results are sorted.
*/
protected void filterResults(List<R> results) {
}
protected void dumpFilter(PrintWriter out, String prefix, F filter) {
out.print(prefix); out.println(filter);
}

View File

@@ -212,6 +212,7 @@ import android.util.ExceptionUtils;
import android.util.Log;
import android.util.LogPrinter;
import android.util.MathUtils;
import android.util.Pair;
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -11229,6 +11230,19 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final class EphemeralIntentResolver
extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
/**
* The result that has the highest defined order. Ordering applies on a
* per-package basis. Mapping is from package name to Pair of order and
* EphemeralResolveInfo.
* <p>
* NOTE: This is implemented as a field variable for convenience and efficiency.
* By having a field variable, we're able to track filter ordering as soon as
* a non-zero order is defined. Otherwise, multiple loops across the result set
* would be needed to apply ordering. If the intent resolver becomes re-entrant,
* this needs to be contained entirely within {@link #filterResults()}.
*/
final ArrayMap<String, Pair<Integer, EphemeralResolveInfo>> mOrderResult = new ArrayMap<>();
@Override
protected EphemeralResolveIntentInfo[] newArray(int size) {
return new EphemeralResolveIntentInfo[size];
@@ -11245,7 +11259,51 @@ public class PackageManagerService extends IPackageManager.Stub {
if (!sUserManager.exists(userId)) {
return null;
}
return info.getEphemeralResolveInfo();
final String packageName = info.getEphemeralResolveInfo().getPackageName();
final Integer order = info.getOrder();
final Pair<Integer, EphemeralResolveInfo> lastOrderResult =
mOrderResult.get(packageName);
// ordering is enabled and this item's order isn't high enough
if (lastOrderResult != null && lastOrderResult.first >= order) {
return null;
}
final EphemeralResolveInfo res = info.getEphemeralResolveInfo();
if (order > 0) {
// non-zero order, enable ordering
mOrderResult.put(packageName, new Pair<>(order, res));
}
return res;
}
@Override
protected void filterResults(List<EphemeralResolveInfo> results) {
// only do work if ordering is enabled [most of the time it won't be]
if (mOrderResult.size() == 0) {
return;
}
int resultSize = results.size();
for (int i = 0; i < resultSize; i++) {
final EphemeralResolveInfo info = results.get(i);
final String packageName = info.getPackageName();
final Pair<Integer, EphemeralResolveInfo> savedInfo = mOrderResult.get(packageName);
if (savedInfo == null) {
// package doesn't having ordering
continue;
}
if (savedInfo.second == info) {
// circled back to the highest ordered item; remove from order list
mOrderResult.remove(savedInfo);
if (mOrderResult.size() == 0) {
// no more ordered items
break;
}
continue;
}
// item has a worse order, remove it from the result list
results.remove(i);
resultSize--;
i--;
}
}
}