Deduplicate actions by their look
1. Deduplicate actions by their look. Ideally, we should compare
their labels and icons, but comparing icon is expensive and thus
we are comparing title + component name instead.
2. Put intent to extras in ConversationAction object
3. Updated LabeledIntent.resolve, so we only support activity intent
handler.
4. Fixed a minor issue in the browser title chooser.
If it is resolves to sharesheet / chooser, we will still show the URL.
BUG: 121200744
Test: atest frameworks/base/core/tests/coretests/src/android/view/textclassifier/
Change-Id: Ic7ea31eb0ac5e9386e8e4b428686a0b66726c96b
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index efdc968..ddbff7b 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -18,9 +18,11 @@
import android.annotation.Nullable;
import android.app.Person;
+import android.app.RemoteAction;
import android.content.Context;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
@@ -118,12 +120,60 @@
@Nullable
public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
if (ConversationAction.TYPE_OPEN_URL.equals(actionType)) {
- return (labeledIntent, resolveInfo) -> resolveInfo.handleAllWebDataURI
- ? labeledIntent.titleWithEntity : labeledIntent.titleWithoutEntity;
+ return (labeledIntent, resolveInfo) -> {
+ if (resolveInfo.handleAllWebDataURI) {
+ return labeledIntent.titleWithEntity;
+ }
+ if ("android".equals(resolveInfo.activityInfo.packageName)) {
+ return labeledIntent.titleWithEntity;
+ }
+ return labeledIntent.titleWithoutEntity;
+ };
}
return null;
}
+ /**
+ * Returns a list of {@link ConversationAction}s that have 0 duplicates. Two actions are
+ * duplicates if they may look the same to users. This function assumes every
+ * ConversationActions with a non-null RemoteAction also have a non-null intent in the extras.
+ */
+ public static List<ConversationAction> removeActionsWithDuplicates(
+ List<ConversationAction> conversationActions) {
+ // Ideally, we should compare title and icon here, but comparing icon is expensive and thus
+ // we use the component name of the target handler as the heuristic.
+ Map<Pair<String, String>, Integer> counter = new ArrayMap<>();
+ for (ConversationAction conversationAction : conversationActions) {
+ Pair<String, String> representation = getRepresentation(conversationAction);
+ if (representation == null) {
+ continue;
+ }
+ Integer existingCount = counter.getOrDefault(representation, 0);
+ counter.put(representation, existingCount + 1);
+ }
+ List<ConversationAction> result = new ArrayList<>();
+ for (ConversationAction conversationAction : conversationActions) {
+ Pair<String, String> representation = getRepresentation(conversationAction);
+ if (representation == null || counter.getOrDefault(representation, 0) == 1) {
+ result.add(conversationAction);
+ }
+ }
+ return result;
+ }
+
+ @Nullable
+ private static Pair<String, String> getRepresentation(
+ ConversationAction conversationAction) {
+ RemoteAction remoteAction = conversationAction.getAction();
+ if (remoteAction == null) {
+ return null;
+ }
+ return new Pair<>(
+ conversationAction.getAction().getTitle().toString(),
+ ExtrasUtils.getActionIntent(
+ conversationAction.getExtras()).getComponent().getPackageName());
+ }
+
private static final class PersonEncoder {
private final Map<Person, Integer> mMapping = new ArrayMap<>();
private int mNextUserId = FIRST_NON_LOCAL_USER;