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">
- * &lt;application&gt;
- *    &lt;meta-data android:name="androidx.textclassifier"
- *          android:resource="@xml/text_classifiers"&gt;
- * </pre>
- *
- * And the text_classifiers.xml is like this:
- * <pre class="prettyprint">
- * &lt;text-classifiers xmlns:app="http://schemas.android.com/apk/res-auto"/&gt;
- *    &lt;-- Text classifier implementation provided by OEM --/&gt;
- *    &lt;text-classifier app:packageName="oem"/&gt;
- *    &lt;-- Package that provides TextClassifierService, certificate should be the base64
- *    encoded sha256 hash of the apps's signing certificate --/&gt;
- *    &lt;text-classifier app:packageName="packageName" app:certificate="certificate"/&gt;
- *    &lt;-- Text classifier implementation provided by AOSP --/&gt;
- *    &lt;text-classifier app:packageName="aosp"/&gt;
- * &lt;/text-classifiers&gt;
- * </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;