From 6f4e063edbaacfeb56b882644b7ca1a427f61c09 Mon Sep 17 00:00:00 2001 From: Tony Mak Date: Thu, 23 Apr 2020 22:27:37 +0100 Subject: [PATCH] Use TextClassicationSession to call smart selection APIs. We used to use TextClassicationSession to send us logging only (i.e. onSelectionEvent()). Now we use TCSession to call smart selection APIs (i.e. suggestSelection and classifyText). This allows the TCS to obtain the session ID in onSuggestSelection and onClassifyText. BUG: 149077320 Test: atest TextViewActivityTest Test: Try a few smart selections and log the sessionID of each TC APIs. Change-Id: I320249735aa08fb7e8612060955b2aa5496da94b --- .../widget/SelectionActionModeHelper.java | 4 +- core/java/android/widget/TextView.java | 3 +- .../android/widget/TextViewActivityTest.java | 59 ++++++++++++++++++- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 45943f512c22f..e57b789173080 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -90,7 +90,7 @@ public final class SelectionActionModeHelper { mTextView = mEditor.getTextView(); mTextClassificationHelper = new TextClassificationHelper( mTextView.getContext(), - mTextView::getTextClassifier, + mTextView::getTextClassificationSession, getText(mTextView), 0, 1, mTextView.getTextLocales()); mSelectionTracker = new SelectionTracker(mTextView); @@ -465,7 +465,7 @@ public final class SelectionActionModeHelper { selectionEnd = mTextView.getSelectionEnd(); } mTextClassificationHelper.init( - mTextView::getTextClassifier, + mTextView::getTextClassificationSession, getText(mTextView), selectionStart, selectionEnd, mTextView.getTextLocales()); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 4be9e1a2051b6..f08696916a576 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -12624,7 +12624,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return getTextClassifier() == TextClassifier.NO_OP; } - /** * Starts an ActionMode for the specified TextLinkSpan. * @@ -12668,7 +12667,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setDefaultLocales(getTextLocales()) .build(); final Supplier supplier = () -> - getTextClassifier().classifyText(request); + getTextClassificationSession().classifyText(request); final Consumer consumer = classification -> { if (classification != null) { if (!classification.getActions().isEmpty()) { diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index 45d4b38d82aa5..7cde19c30dd4b 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -120,8 +120,10 @@ public class TextViewActivityTest { public void setUp() { mActivity = mActivityRule.getActivity(); mInstrumentation = InstrumentationRegistry.getInstrumentation(); - mActivity.getSystemService(TextClassificationManager.class) - .setTextClassifier(TextClassifier.NO_OP); + TextClassificationManager tcm = mActivity.getSystemService( + TextClassificationManager.class); + tcm.setTextClassifier(TextClassifier.NO_OP); + tcm.setTextClassificationSessionFactory(null); } @Test @@ -1173,6 +1175,53 @@ public class TextViewActivityTest { assertEquals(TextClassifier.TYPE_PHONE, lastEvent.getEntityType()); } + @Test + public void testTextClassifierSession() throws Throwable { + useSystemDefaultTextClassifier(); + TextClassificationManager tcm = + mActivity.getSystemService(TextClassificationManager.class); + List testableTextClassifiers = new ArrayList<>(); + tcm.setTextClassificationSessionFactory(classificationContext -> { + TestableTextClassifier textClassifier = new TestableTextClassifier(); + testableTextClassifiers.add(textClassifier); + return new TextClassifier() { + private boolean mIsDestroyed = false; + + @Override + public TextSelection suggestSelection(TextSelection.Request request) { + return textClassifier.suggestSelection(request); + } + + @Override + public void destroy() { + mIsDestroyed = true; + } + + @Override + public boolean isDestroyed() { + return mIsDestroyed; + } + }; + }); + + // Long press to trigger selection + onView(withId(R.id.textview)).perform(replaceText("android.com")); + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(0)); + sleepForFloatingToolbarPopup(); + // Click "Copy" to dismiss the selection. + clickFloatingToolbarItem(mActivity.getString(com.android.internal.R.string.copy)); + + // Long press to trigger another selection + onView(withId(R.id.textview)).perform(replaceText("android@android.com")); + onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(0)); + sleepForFloatingToolbarPopup(); + + // suggestSelection should be called in two different TextClassifier sessions. + assertEquals(2, testableTextClassifiers.size()); + assertEquals(1, testableTextClassifiers.get(0).getTextSelectionRequests().size()); + assertEquals(1, testableTextClassifiers.get(1).getTextSelectionRequests().size()); + } + @Test public void testPastePlainText_menuAction() { initializeClipboardWithText(TextStyle.STYLED); @@ -1227,6 +1276,7 @@ public class TextViewActivityTest { private final class TestableTextClassifier implements TextClassifier { final List mSelectionEvents = new ArrayList<>(); + final List mTextSelectionRequests = new ArrayList<>(); @Override public void onSelectionEvent(SelectionEvent event) { @@ -1235,6 +1285,7 @@ public class TextViewActivityTest { @Override public TextSelection suggestSelection(TextSelection.Request request) { + mTextSelectionRequests.add(request); return new TextSelection.Builder(request.getStartIndex(), request.getEndIndex()) .setEntityType(TextClassifier.TYPE_PHONE, 1) .build(); @@ -1243,5 +1294,9 @@ public class TextViewActivityTest { List getSelectionEvents() { return mSelectionEvents; } + + List getTextSelectionRequests() { + return mTextSelectionRequests; + } } }