summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Abodunrinwa Toki <toki@google.com> 2019-02-06 01:17:10 +0000
committer Abodunrinwa Toki <toki@google.com> 2019-02-08 12:58:57 +0000
commitc33fc77de4abfcc51a2a1be3c5c5e3be510f26a3 (patch)
tree5c21029f3a0b3b9e114a52bc51f56eb2b7a8579c
parent6f82297cb1c3fbb740ae91d2d5e59603f67b1e84 (diff)
TextClassifier: normalize uri for browser intent.
Also updates TemplateIntentFactory to validate RemoteActionTemplates. Bug: 123640937 Test: atest core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java Test: atest core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java Change-Id: I2dc5d988234f1aaace4b30e9fbe272937c99ca47
-rw-r--r--core/java/android/view/textclassifier/ExtrasUtils.java15
-rw-r--r--core/java/android/view/textclassifier/LegacyIntentFactory.java3
-rw-r--r--core/java/android/view/textclassifier/TemplateIntentFactory.java71
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java48
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java120
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java20
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java4
7 files changed, 205 insertions, 76 deletions
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 602455c65beb..b0e7ad5d7264 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -85,15 +85,16 @@ public final class ExtrasUtils {
}
/**
- * Returns the first "translate" action found in the {@code classification} object.
+ * Returns the first action found in the {@code classification} object with an intent
+ * action string, {@code intentAction}.
*/
@Nullable
- public static RemoteAction findTranslateAction(TextClassification classification) {
+ public static RemoteAction findAction(TextClassification classification, String intentAction) {
final ArrayList<Intent> actionIntents = getActionsIntents(classification);
if (actionIntents != null) {
final int size = actionIntents.size();
for (int i = 0; i < size; i++) {
- if (Intent.ACTION_TRANSLATE.equals(actionIntents.get(i).getAction())) {
+ if (intentAction.equals(actionIntents.get(i).getAction())) {
return classification.getActions().get(i);
}
}
@@ -102,6 +103,14 @@ public final class ExtrasUtils {
}
/**
+ * Returns the first "translate" action found in the {@code classification} object.
+ */
+ @Nullable
+ public static RemoteAction findTranslateAction(TextClassification classification) {
+ return findAction(classification, Intent.ACTION_TRANSLATE);
+ }
+
+ /**
* Returns the entity type contained in the {@code extra}.
*/
@Nullable
diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/LegacyIntentFactory.java
index b6e5b3e26b16..2d0d032cfef3 100644
--- a/core/java/android/view/textclassifier/LegacyIntentFactory.java
+++ b/core/java/android/view/textclassifier/LegacyIntentFactory.java
@@ -182,7 +182,8 @@ public final class LegacyIntentFactory implements IntentFactory {
actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.browse),
context.getString(com.android.internal.R.string.browse_desc),
- new Intent(Intent.ACTION_VIEW, Uri.parse(text))
+ new Intent(Intent.ACTION_VIEW)
+ .setDataAndNormalize(Uri.parse(text))
.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()),
LabeledIntent.DEFAULT_REQUEST_CODE));
return actions;
diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/TemplateIntentFactory.java
index 52788436b3ea..95f88c7de146 100644
--- a/core/java/android/view/textclassifier/TemplateIntentFactory.java
+++ b/core/java/android/view/textclassifier/TemplateIntentFactory.java
@@ -49,20 +49,18 @@ public final class TemplateIntentFactory {
}
final List<TextClassifierImpl.LabeledIntent> labeledIntents = new ArrayList<>();
for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
- Intent intent = createIntent(remoteActionTemplate);
- if (intent == null) {
+ if (!isValidTemplate(remoteActionTemplate)) {
+ Log.w(TAG, "Invalid RemoteActionTemplate skipped.");
continue;
}
- TextClassifierImpl.LabeledIntent
- labeledIntent = new TextClassifierImpl.LabeledIntent(
- remoteActionTemplate.title,
- remoteActionTemplate.description,
- intent,
- remoteActionTemplate.requestCode == null
- ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE
- : remoteActionTemplate.requestCode
- );
- labeledIntents.add(labeledIntent);
+ labeledIntents.add(
+ new TextClassifierImpl.LabeledIntent(
+ remoteActionTemplate.title,
+ remoteActionTemplate.description,
+ createIntent(remoteActionTemplate),
+ remoteActionTemplate.requestCode == null
+ ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE
+ : remoteActionTemplate.requestCode));
}
labeledIntents.forEach(
action -> action.getIntent()
@@ -70,29 +68,43 @@ public final class TemplateIntentFactory {
return labeledIntents;
}
- @Nullable
- private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) {
- Intent intent = new Intent();
- if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) {
- Log.w(TAG, "A RemoteActionTemplate is skipped as package name is set.");
- return null;
+ private static boolean isValidTemplate(@Nullable RemoteActionTemplate remoteActionTemplate) {
+ if (remoteActionTemplate == null) {
+ Log.w(TAG, "Invalid RemoteActionTemplate: is null");
+ return false;
}
- if (!TextUtils.isEmpty(remoteActionTemplate.action)) {
- intent.setAction(remoteActionTemplate.action);
+ if (TextUtils.isEmpty(remoteActionTemplate.title)) {
+ Log.w(TAG, "Invalid RemoteActionTemplate: title is null");
+ return false;
}
- Uri data = null;
- if (!TextUtils.isEmpty(remoteActionTemplate.data)) {
- data = Uri.parse(remoteActionTemplate.data);
+ if (TextUtils.isEmpty(remoteActionTemplate.description)) {
+ Log.w(TAG, "Invalid RemoteActionTemplate: description is null");
+ return false;
}
- if (data != null || !TextUtils.isEmpty(remoteActionTemplate.type)) {
- intent.setDataAndType(data, remoteActionTemplate.type);
+ if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) {
+ Log.w(TAG, "Invalid RemoteActionTemplate: package name is set");
+ return false;
}
- if (remoteActionTemplate.flags != null) {
- intent.setFlags(remoteActionTemplate.flags);
+ if (TextUtils.isEmpty(remoteActionTemplate.action)) {
+ Log.w(TAG, "Invalid RemoteActionTemplate: intent action not set");
+ return false;
}
+ return true;
+ }
+
+ private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) {
+ final Intent intent = new Intent(remoteActionTemplate.action);
+ final Uri uri = TextUtils.isEmpty(remoteActionTemplate.data)
+ ? null : Uri.parse(remoteActionTemplate.data).normalizeScheme();
+ final String type = TextUtils.isEmpty(remoteActionTemplate.type)
+ ? null : Intent.normalizeMimeType(remoteActionTemplate.type);
+ intent.setDataAndType(uri, type);
+ intent.setFlags(remoteActionTemplate.flags == null ? 0 : remoteActionTemplate.flags);
if (remoteActionTemplate.category != null) {
for (String category : remoteActionTemplate.category) {
- intent.addCategory(category);
+ if (category != null) {
+ intent.addCategory(category);
+ }
}
}
intent.putExtras(createExtras(remoteActionTemplate.extras));
@@ -105,6 +117,9 @@ public final class TemplateIntentFactory {
}
Bundle bundle = new Bundle();
for (NamedVariant namedVariant : namedVariants) {
+ if (namedVariant == null) {
+ continue;
+ }
switch (namedVariant.getType()) {
case NamedVariant.TYPE_INT:
bundle.putInt(namedVariant.getName(), namedVariant.getInt());
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
index 08ad62ab843d..d9dac314fc7c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
@@ -41,6 +41,7 @@ public class TemplateClassificationIntentFactoryTest {
private static final String TEXT = "text";
private static final String TITLE = "Map";
+ private static final String DESCRIPTION = "Opens in Maps";
private static final String ACTION = Intent.ACTION_VIEW;
@Mock
@@ -57,19 +58,6 @@ public class TemplateClassificationIntentFactoryTest {
@Test
public void create_foreignText() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
- null,
- ACTION,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
-
AnnotatorModel.ClassificationResult classificationResult =
new AnnotatorModel.ClassificationResult(
TextClassifier.TYPE_ADDRESS,
@@ -81,7 +69,7 @@ public class TemplateClassificationIntentFactoryTest {
null,
null,
null,
- new RemoteActionTemplate[]{remoteActionTemplate});
+ createRemoteActionTemplates());
List<TextClassifierImpl.LabeledIntent> intents =
mTemplateClassificationIntentFactory.create(
@@ -106,19 +94,6 @@ public class TemplateClassificationIntentFactoryTest {
@Test
public void create_notForeignText() {
- RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- TITLE,
- null,
- ACTION,
- null,
- null,
- null,
- null,
- null,
- null,
- null
- );
-
AnnotatorModel.ClassificationResult classificationResult =
new AnnotatorModel.ClassificationResult(
TextClassifier.TYPE_ADDRESS,
@@ -130,7 +105,7 @@ public class TemplateClassificationIntentFactoryTest {
null,
null,
null,
- new RemoteActionTemplate[]{remoteActionTemplate});
+ createRemoteActionTemplates());
List<TextClassifierImpl.LabeledIntent> intents =
mTemplateClassificationIntentFactory.create(
@@ -147,4 +122,21 @@ public class TemplateClassificationIntentFactoryTest {
assertThat(intent.getAction()).isEqualTo(ACTION);
assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
+
+ private static RemoteActionTemplate[] createRemoteActionTemplates() {
+ return new RemoteActionTemplate[]{
+ new RemoteActionTemplate(
+ TITLE,
+ DESCRIPTION,
+ ACTION,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ )
+ };
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
index 0d364a329de4..a1158a7cbb6c 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
@@ -81,7 +81,6 @@ public class TemplateIntentFactoryTest {
REQUEST_CODE
);
-
List<TextClassifierImpl.LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
@@ -97,23 +96,22 @@ public class TemplateIntentFactoryTest {
assertThat(intent.getFlags()).isEqualTo(FLAG);
assertThat(intent.getCategories()).containsExactly((Object[]) CATEGORY);
assertThat(intent.getPackage()).isNull();
- assertThat(
- intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
+ assertThat(intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
assertThat(intent.getIntExtra(KEY_TWO, 0)).isEqualTo(VALUE_TWO);
assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@Test
- public void create_packageIsNotNull() {
+ public void normalizesScheme() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
TITLE,
DESCRIPTION,
ACTION,
- DATA,
+ "HTTp://www.android.com",
TYPE,
FLAG,
CATEGORY,
- PACKAGE_NAME,
+ /* packageName */ null,
NAMED_VARIANTS,
REQUEST_CODE
);
@@ -121,15 +119,16 @@ public class TemplateIntentFactoryTest {
List<TextClassifierImpl.LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
- assertThat(intents).hasSize(0);
+ String data = intents.get(0).getIntent().getData().toString();
+ assertThat(data).isEqualTo("http://www.android.com");
}
@Test
public void create_minimal() {
RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
- null,
- null,
- null,
+ TITLE,
+ DESCRIPTION,
+ ACTION,
null,
null,
null,
@@ -142,15 +141,14 @@ public class TemplateIntentFactoryTest {
List<TextClassifierImpl.LabeledIntent> intents =
mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
-
assertThat(intents).hasSize(1);
TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
- assertThat(labeledIntent.getTitle()).isNull();
- assertThat(labeledIntent.getDescription()).isNull();
+ assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
+ assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION);
assertThat(labeledIntent.getRequestCode()).isEqualTo(
TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE);
Intent intent = labeledIntent.getIntent();
- assertThat(intent.getAction()).isNull();
+ assertThat(intent.getAction()).isEqualTo(ACTION);
assertThat(intent.getData()).isNull();
assertThat(intent.getType()).isNull();
assertThat(intent.getFlags()).isEqualTo(0);
@@ -158,4 +156,98 @@ public class TemplateIntentFactoryTest {
assertThat(intent.getPackage()).isNull();
assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
+
+ @Test
+ public void invalidTemplate_nullTemplate() {
+ RemoteActionTemplate remoteActionTemplate = null;
+
+ List<TextClassifierImpl.LabeledIntent> intents =
+ mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+ assertThat(intents).isEmpty();
+ }
+
+ @Test
+ public void invalidTemplate_nonEmptyPackageName() {
+ RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+ TITLE,
+ DESCRIPTION,
+ ACTION,
+ DATA,
+ TYPE,
+ FLAG,
+ CATEGORY,
+ PACKAGE_NAME,
+ NAMED_VARIANTS,
+ REQUEST_CODE
+ );
+
+ List<TextClassifierImpl.LabeledIntent> intents =
+ mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+ assertThat(intents).isEmpty();
+ }
+
+ @Test
+ public void invalidTemplate_emptyTitle() {
+ RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+ null,
+ DESCRIPTION,
+ ACTION,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+
+ List<TextClassifierImpl.LabeledIntent> intents =
+ mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+ assertThat(intents).isEmpty();
+ }
+
+ @Test
+ public void invalidTemplate_emptyDescription() {
+ RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+ TITLE,
+ null,
+ ACTION,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+
+ List<TextClassifierImpl.LabeledIntent> intents =
+ mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+ assertThat(intents).isEmpty();
+ }
+
+ @Test
+ public void invalidTemplate_emptyIntentAction() {
+ RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+ TITLE,
+ DESCRIPTION,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+
+ List<TextClassifierImpl.LabeledIntent> intents =
+ mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+ assertThat(intents).isEmpty();
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 582be9d51731..bdd03707c1f1 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -176,6 +176,7 @@ public class TextClassifierTest {
TextClassification classification = mClassifier.classifyText(request);
assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+ assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
}
@Test
@@ -207,6 +208,7 @@ public class TextClassifierTest {
TextClassification classification = mClassifier.classifyText(request);
assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+ assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
}
@Test
@@ -517,6 +519,24 @@ public class TextClassifierTest {
};
}
+ private static Matcher<TextClassification> containsIntentWithAction(final String action) {
+ return new BaseMatcher<TextClassification>() {
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof TextClassification) {
+ TextClassification result = (TextClassification) o;
+ return ExtrasUtils.findAction(result, action) != null;
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("intent action=").appendValue(action);
+ }
+ };
+ }
+
private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
return new BaseMatcher<TextLanguage>() {
@Override
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
index 73af56743b5f..1980a604fdd2 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -91,8 +91,8 @@ public class TextClassifierEventTronLoggerTest {
.isEqualTo(ConversationAction.TYPE_CALL_PHONE);
assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE))
.isWithin(0.00001f).of(0.5f);
- assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME))
- .isEqualTo(EVENT_TIME);
+ // Never write event time.
+ assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME)).isNull();
assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE))
.isEqualTo(WIDGET_TYPE);