Merge "Revise TCM createTextClassifier" into androidx-master-dev
diff --git a/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java b/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java
index 35c8050..ac4761c 100644
--- a/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java
+++ b/textclassifier/src/androidTest/java/androidx/textclassifier/TextClassificationManagerTest.java
@@ -16,34 +16,23 @@
package androidx.textclassifier;
-import static androidx.textclassifier.TextClassificationManager.METADATA_XML_KEY;
-
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.os.Bundle;
+import android.os.Build;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
-import androidx.textclassifier.resolver.TextClassifierEntry;
-import androidx.textclassifier.resolver.TextClassifierEntryParser;
-import androidx.textclassifier.resolver.TextClassifierResolver;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.Collections;
-import java.util.List;
-
@SmallTest
public class TextClassificationManagerTest {
private static final String PACKAGE_NAME = "my.package";
@@ -51,10 +40,6 @@
private TextClassificationManager mTextClassificationManager;
private TextClassificationContext mTextClassificationContext;
@Mock
- private TextClassifierResolver mTextClassifierResolver;
- @Mock
- private TextClassifierEntryParser mTextClassifierEntryParser;
- @Mock
private Context mContext;
@Mock
private PackageManager mPackageManager;
@@ -62,8 +47,7 @@
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mTextClassificationManager = new TextClassificationManager(
- mContext, mTextClassifierEntryParser, mTextClassifierResolver);
+ mTextClassificationManager = new TextClassificationManager(mContext);
mTextClassificationContext = new TextClassificationContext.Builder(
PACKAGE_NAME, TextClassifier.WIDGET_TYPE_TEXTVIEW).build();
when(mContext.getPackageManager()).thenReturn(mPackageManager);
@@ -74,73 +58,26 @@
);
}
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
- public void testCreateTextClassifier_noMetaData() throws Exception {
- // Construct application info without metadata.
- ApplicationInfo applicationInfo = new ApplicationInfo();
- when(mPackageManager.getApplicationInfo(
- eq(PACKAGE_NAME), anyInt())).thenReturn(applicationInfo);
-
- TextClassifier textClassifier =
- mTextClassificationManager.createTextClassifier(mTextClassificationContext);
-
- // fallback should be used.
- assertThat(textClassifier).isNotNull();
- }
-
- @SdkSuppress(minSdkVersion = 28)
- @Test
- public void testCreateTextClassifier_platformTextClassifier() throws Exception {
- List<TextClassifierEntry> candidates =
- Collections.singletonList(TextClassifierEntry.createAospEntry());
- TextClassifierEntry bestMatch = candidates.get(0);
- setupEnvironment(candidates, bestMatch);
-
+ public void testCreateTextClassifier_default_postO() throws Exception {
TextClassifier textClassifier =
mTextClassificationManager.createTextClassifier(mTextClassificationContext);
assertThat(textClassifier).isInstanceOf(PlatformTextClassifierWrapper.class);
}
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.N_MR1)
@Test
- public void testCreateTextClassifier_remoteServiceTextClassifier() throws Exception {
- List<TextClassifierEntry> candidates =
- Collections.singletonList(TextClassifierEntry.createPackageEntry("pkg", "cert"));
- TextClassifierEntry bestMatch = candidates.get(0);
- setupEnvironment(candidates, bestMatch);
-
-
+ public void testCreateTextClassifier_default_preO() throws Exception {
TextClassifier textClassifier =
mTextClassificationManager.createTextClassifier(mTextClassificationContext);
- assertThat(textClassifier).isInstanceOf(RemoteServiceTextClassifier.class);
+ assertThat(textClassifier).isSameAs(LegacyTextClassifier.INSTANCE);
}
@Test
- public void testCreateTextClassifier_parserReturnNull() throws Exception {
- setupEnvironment(null, null);
-
- TextClassifier textClassifier =
- mTextClassificationManager.createTextClassifier(mTextClassificationContext);
-
- // fallback should be used.
- assertThat(textClassifier).isNotNull();
- }
-
- @Test
- public void testCreateTextClassifier_resolverReturnNull() throws Exception {
- setupEnvironment(
- Collections.singletonList(TextClassifierEntry.createAospEntry()), null);
-
- TextClassifier textClassifier =
- mTextClassificationManager.createTextClassifier(mTextClassificationContext);
-
- // fallback should be used.
- assertThat(textClassifier).isNotNull();
- }
-
- @Test
- public void testCreateTextClassifier() {
+ public void testCreateTextClassifier_factory() {
mTextClassificationManager.setTextClassifierFactory(
new TextClassifierFactory() {
@Override
@@ -154,38 +91,6 @@
assertThat(textClassifier).isInstanceOf(DummyTextClassifier.class);
}
- @Test
- @SdkSuppress(minSdkVersion = 28)
- public void testFallback_P() throws Exception {
- setupEnvironment(Collections.<TextClassifierEntry>emptyList(), null);
- TextClassifier textClassifier =
- mTextClassificationManager.createTextClassifier(mTextClassificationContext);
- assertThat(textClassifier).isInstanceOf(PlatformTextClassifierWrapper.class);
- }
-
- @Test
- @SdkSuppress(maxSdkVersion = 27)
- public void testFallback_beforeP() throws Exception {
- setupEnvironment(Collections.<TextClassifierEntry>emptyList(), null);
- TextClassifier textClassifier =
- mTextClassificationManager.createTextClassifier(mTextClassificationContext);
- assertThat(textClassifier).isInstanceOf(LegacyTextClassifier.class);
- }
-
- private void setupEnvironment(
- List<TextClassifierEntry> candidates, TextClassifierEntry bestMatch)
- throws Exception {
- final int xmlRes = 10;
- Bundle metadata = new Bundle();
- metadata.putInt(METADATA_XML_KEY, xmlRes);
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.metaData = metadata;
- when(mPackageManager.getApplicationInfo(
- eq(PACKAGE_NAME), anyInt())).thenReturn(applicationInfo);
- when(mTextClassifierEntryParser.parse(xmlRes)).thenReturn(candidates);
- when(mTextClassifierResolver.findBestMatch(candidates)).thenReturn(bestMatch);
- }
-
private static class DummyTextClassifier extends TextClassifier {
DummyTextClassifier(TextClassificationContext textClassificationContext) {
super(textClassificationContext);
diff --git a/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java b/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java
index 83aa57d..31da17d 100644
--- a/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java
+++ b/textclassifier/src/main/java/androidx/textclassifier/TextClassificationManager.java
@@ -16,63 +16,20 @@
package androidx.textclassifier;
-import android.annotation.SuppressLint;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
-import androidx.annotation.XmlRes;
import androidx.core.util.Preconditions;
-import androidx.textclassifier.resolver.TextClassifierEntry;
-import androidx.textclassifier.resolver.TextClassifierEntryParser;
-import androidx.textclassifier.resolver.TextClassifierResolver;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
/**
* Class to handle the creation of {@link TextClassifier}.
- * <p>
- * The choice of text classifier can be specified in the AndroidManifest.xml like this:
- * <pre class="prettyprint">
- * <application>
- * <meta-data android:name="androidx.textclassifier"
- * android:resource="@xml/text_classifiers">
- * </pre>
- *
- * And the text_classifiers.xml is like this:
- * <pre class="prettyprint">
- * <text-classifiers xmlns:app="http://schemas.android.com/apk/res-auto"/>
- * <-- Text classifier implementation provided by OEM --/>
- * <text-classifier app:packageName="oem"/>
- * <-- Package that provides TextClassifierService, certificate should be the base64
- * encoded sha256 hash of the apps's signing certificate --/>
- * <text-classifier app:packageName="packageName" app:certificate="certificate"/>
- * <-- Text classifier implementation provided by AOSP --/>
- * <text-classifier app:packageName="aosp"/>
- * </text-classifiers>
- * </pre>
*/
public final class TextClassificationManager {
- private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
- private static final int NO_RES = -1;
- @VisibleForTesting
- static final String METADATA_XML_KEY = "androidx.textclassifier";
-
private final Context mContext;
- private final TextClassifierEntryParser mTextClassifierEntryParser;
- private final TextClassifierResolver mTextClassifierResolver;
- @Nullable
- private List<TextClassifierEntry> mTextClassifierCandidates;
@Nullable
private static TextClassificationManager sInstance;
private TextClassifierFactory mTextClassifierFactory;
@@ -80,13 +37,8 @@
/** @hide **/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@VisibleForTesting
- TextClassificationManager(
- @NonNull Context context,
- @NonNull TextClassifierEntryParser textClassifierEntryParser,
- @NonNull TextClassifierResolver textClassifierResolver) {
+ TextClassificationManager(@NonNull Context context) {
mContext = Preconditions.checkNotNull(context);
- mTextClassifierEntryParser = Preconditions.checkNotNull(textClassifierEntryParser);
- mTextClassifierResolver = Preconditions.checkNotNull(textClassifierResolver);
}
/**
@@ -95,19 +47,18 @@
public static TextClassificationManager of(@NonNull Context context) {
if (sInstance == null) {
Context appContext = context.getApplicationContext();
- sInstance = new TextClassificationManager(
- appContext,
- new TextClassifierEntryParser(appContext),
- new TextClassifierResolver(appContext));
+ sInstance = new TextClassificationManager(appContext);
}
return sInstance;
}
/**
- * Returns a newly created text classifier, which is session based. That means the text
- * classifier can't be reused once it is destroyed.
+ * Returns a newly created text classifier.
+ * <p>
+ * If a factory is set through {@link #setTextClassifierFactory(TextClassifierFactory)},
+ * an instance created by the factory will be returned. Otherwise, a default text classifier
+ * will be returned.
*/
- @SuppressLint("NewApi") // isAosp and isOem already tell us that we have high enough API level.
@NonNull
public TextClassifier createTextClassifier(
@NonNull TextClassificationContext textClassificationContext) {
@@ -115,24 +66,11 @@
if (mTextClassifierFactory != null) {
return mTextClassifierFactory.create(textClassificationContext);
}
- if (mTextClassifierCandidates == null) {
- mTextClassifierCandidates = parseTextClassifierCandidates();
- }
- TextClassifierEntry bestMatch =
- mTextClassifierResolver.findBestMatch(mTextClassifierCandidates);
- if (bestMatch == null) {
- return defaultTextClassifier(textClassificationContext);
- }
- if (bestMatch.isAosp() || bestMatch.isOem()) {
- return PlatformTextClassifierWrapper.create(mContext, textClassificationContext);
- }
- return new RemoteServiceTextClassifier(
- mContext, textClassificationContext, bestMatch.packageName);
+ return defaultTextClassifier(textClassificationContext);
}
/**
- * Sets a factory that can create a preferred text classifier. This overrides the preferred
- * text classifiers specified in AndroidManifest.
+ * Sets a factory that can create a preferred text classifier.
* <p>
* To turn off the feature completely, you can set a factory that returns
* {@link TextClassifier#NO_OP}.
@@ -141,41 +79,12 @@
mTextClassifierFactory = factory;
}
- @XmlRes
- private int getTextClassifiersXmlRes() {
- Bundle metaData = null;
- try {
- PackageManager packageManager = mContext.getPackageManager();
- metaData = packageManager.getApplicationInfo(
- mContext.getPackageName(), PackageManager.GET_META_DATA).metaData;
- } catch (PackageManager.NameNotFoundException e) {
- // can't happen
- }
- if (metaData == null) {
- return NO_RES;
- }
- return metaData.getInt(METADATA_XML_KEY, NO_RES);
- }
-
- @NonNull
- private List<TextClassifierEntry> parseTextClassifierCandidates() {
- int xmlRes = getTextClassifiersXmlRes();
- try {
- if (xmlRes != NO_RES) {
- return mTextClassifierEntryParser.parse(xmlRes);
- }
- } catch (XmlPullParserException | IOException ex) {
- Log.e(TAG, "parseTextClassifierCandidates: ", ex);
- }
- return Collections.emptyList();
- }
-
/**
- * Returns the default text classifier when we need a fallback.
+ * Returns the default text classifier.
*/
private TextClassifier defaultTextClassifier(
@Nullable TextClassificationContext textClassificationContext) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return PlatformTextClassifierWrapper.create(mContext, textClassificationContext);
}
return LegacyTextClassifier.INSTANCE;