Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 176249fc authored by Miranda Kephart's avatar Miranda Kephart Committed by Automerger Merge Worker
Browse files

Merge "Consider entity length when deciding whether to show actions" into...

Merge "Consider entity length when deciding whether to show actions" into tm-qpr-dev am: 5ecceeef am: 68d152b3 am: 103a6fbb am: 78c02c9f

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21647313



Change-Id: If7bc1ca79582935a7272761d4dac716305e05a52
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents bca427dd 78c02c9f
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -363,15 +363,15 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv

    private void classifyText(ClipboardModel model) {
        mBgExecutor.execute(() -> {
            Optional<RemoteAction> remoteAction = mClipboardUtils.getAction(
                            model.getText(), model.getTextLinks(), model.getSource());
            Optional<RemoteAction> remoteAction =
                    mClipboardUtils.getAction(model.getTextLinks(), model.getSource());
            if (model.equals(mClipboardModel)) {
                remoteAction.ifPresent(action -> {
                    mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
                    mView.setActionChip(action, () -> {
                    mView.post(() -> mView.setActionChip(action, () -> {
                        mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
                        animateOut();
                    });
                    }));
                });
            }
        });
+20 −9
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ import javax.inject.Inject;

class ClipboardOverlayUtils {

    // minimum proportion of entire text an entity must take up, to be considered for smart actions
    private static final float MINIMUM_ENTITY_PROPORTION = .8f;

    private final TextClassifier mTextClassifier;

    @Inject
@@ -65,20 +68,24 @@ class ClipboardOverlayUtils {
        return false;
    }

    public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) {
        return getActions(text, textLinks).stream().filter(remoteAction -> {
    public Optional<RemoteAction> getAction(TextLinks textLinks, String source) {
        return getActions(textLinks).stream().filter(remoteAction -> {
            ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
            return component != null && !TextUtils.equals(source, component.getPackageName());
        }).findFirst();
    }

    private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) {
    private ArrayList<RemoteAction> getActions(TextLinks textLinks) {
        ArrayList<RemoteAction> actions = new ArrayList<>();
        for (TextLinks.TextLink link : textLinks.getLinks()) {
            // skip classification for incidental entities
            if (link.getEnd() - link.getStart()
                    >= textLinks.getText().length() * MINIMUM_ENTITY_PROPORTION) {
                TextClassification classification = mTextClassifier.classifyText(
                    text, link.getStart(), link.getEnd(), null);
                        textLinks.getText(), link.getStart(), link.getEnd(), null);
                actions.addAll(classification.getActions());
            }
        }
        return actions;
    }

@@ -92,10 +99,14 @@ class ClipboardOverlayUtils {
    private ArrayList<RemoteAction> getActions(ClipData.Item item) {
        ArrayList<RemoteAction> actions = new ArrayList<>();
        for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
            // skip classification for incidental entities
            if (link.getEnd() - link.getStart()
                    >= item.getText().length() * MINIMUM_ENTITY_PROPORTION) {
                TextClassification classification = mTextClassifier.classifyText(
                        item.getText(), link.getStart(), link.getEnd(), null);
                actions.addAll(classification.getActions());
            }
        }
        return actions;
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -446,7 +446,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
        mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
        when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
                .thenReturn(true);
        when(mClipboardUtils.getAction(any(CharSequence.class), any(TextLinks.class), anyString()))
        when(mClipboardUtils.getAction(any(TextLinks.class), anyString()))
                .thenReturn(Optional.of(Mockito.mock(RemoteAction.class)));
        when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
            @Override
+106 −10
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;

@@ -77,6 +78,74 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {

    @Test
    public void test_getAction_noLinks_returnsEmptyOptional() {
        Optional<RemoteAction> action =
                mClipboardUtils.getAction(Mockito.mock(TextLinks.class), "abc");

        assertTrue(action.isEmpty());
    }

    @Test
    public void test_getAction_returnsFirstLink() {
        TextLinks links = getFakeTextLinksBuilder().build();
        RemoteAction actionA = constructRemoteAction("abc");
        RemoteAction actionB = constructRemoteAction("def");
        TextClassification classificationA = Mockito.mock(TextClassification.class);
        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
        TextClassification classificationB = Mockito.mock(TextClassification.class);
        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
        when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
                classificationA, classificationB);

        RemoteAction result = mClipboardUtils.getAction(links, "test").orElse(null);

        assertEquals(actionA, result);
    }

    @Test
    public void test_getAction_skipsMatchingComponent() {
        TextLinks links = getFakeTextLinksBuilder().build();
        RemoteAction actionA = constructRemoteAction("abc");
        RemoteAction actionB = constructRemoteAction("def");
        TextClassification classificationA = Mockito.mock(TextClassification.class);
        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
        TextClassification classificationB = Mockito.mock(TextClassification.class);
        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
        when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
                classificationA, classificationB);

        RemoteAction result = mClipboardUtils.getAction(links, "abc").orElse(null);

        assertEquals(actionB, result);
    }

    @Test
    public void test_getAction_skipsShortEntity() {
        TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
        final Map<String, Float> scores = new ArrayMap<>();
        scores.put(TextClassifier.TYPE_EMAIL, 1f);
        textLinks.addLink(20, 22, scores);
        textLinks.addLink(0, 22, scores);

        RemoteAction actionA = constructRemoteAction("abc");
        RemoteAction actionB = constructRemoteAction("def");
        TextClassification classificationA = Mockito.mock(TextClassification.class);
        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
        TextClassification classificationB = Mockito.mock(TextClassification.class);
        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
        when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
                classificationA);
        when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
                classificationB);

        RemoteAction result = mClipboardUtils.getAction(textLinks.build(), "test").orElse(null);

        assertEquals(actionB, result);
    }

    // TODO(b/267162944): Next four tests (marked "legacy") are obsolete once
    //  CLIPBOARD_MINIMIZED_LAYOUT flag is released and removed
    @Test
    public void test_getAction_noLinks_returnsEmptyOptional_legacy() {
        ClipData.Item item = new ClipData.Item("no text links");
        item.setTextLinks(Mockito.mock(TextLinks.class));

@@ -86,8 +155,8 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
    }

    @Test
    public void test_getAction_returnsFirstLink() {
        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
    public void test_getAction_returnsFirstLink_legacy() {
        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
        when(mClipDataItem.getText()).thenReturn("");
        RemoteAction actionA = constructRemoteAction("abc");
        RemoteAction actionB = constructRemoteAction("def");
@@ -98,14 +167,14 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
        when(mTextClassifier.classifyText(anyString(), anyInt(), anyInt(), isNull())).thenReturn(
                classificationA, classificationB);

        RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "def").orElse(null);
        RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);

        assertEquals(actionA, result);
    }

    @Test
    public void test_getAction_skipsMatchingComponent() {
        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
    public void test_getAction_skipsMatchingComponent_legacy() {
        when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinksBuilder().build());
        when(mClipDataItem.getText()).thenReturn("");
        RemoteAction actionA = constructRemoteAction("abc");
        RemoteAction actionB = constructRemoteAction("def");
@@ -121,6 +190,33 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
        assertEquals(actionB, result);
    }

    @Test
    public void test_getAction_skipsShortEntity_legacy() {
        TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
        final Map<String, Float> scores = new ArrayMap<>();
        scores.put(TextClassifier.TYPE_EMAIL, 1f);
        textLinks.addLink(20, 22, scores);
        textLinks.addLink(0, 22, scores);

        when(mClipDataItem.getTextLinks()).thenReturn(textLinks.build());
        when(mClipDataItem.getText()).thenReturn(textLinks.build().getText());

        RemoteAction actionA = constructRemoteAction("abc");
        RemoteAction actionB = constructRemoteAction("def");
        TextClassification classificationA = Mockito.mock(TextClassification.class);
        when(classificationA.getActions()).thenReturn(Lists.newArrayList(actionA));
        TextClassification classificationB = Mockito.mock(TextClassification.class);
        when(classificationB.getActions()).thenReturn(Lists.newArrayList(actionB));
        when(mTextClassifier.classifyText(anyString(), eq(20), eq(22), isNull())).thenReturn(
                classificationA);
        when(mTextClassifier.classifyText(anyString(), eq(0), eq(22), isNull())).thenReturn(
                classificationB);

        RemoteAction result = mClipboardUtils.getAction(mClipDataItem, "test").orElse(null);

        assertEquals(actionB, result);
    }

    @Test
    public void test_extra_withPackage_returnsTrue() {
        PersistableBundle b = new PersistableBundle();
@@ -184,12 +280,12 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
        return action;
    }

    private static TextLinks getFakeTextLinks() {
        TextLinks.Builder textLinks = new TextLinks.Builder("test");
    private static TextLinks.Builder getFakeTextLinksBuilder() {
        TextLinks.Builder textLinks = new TextLinks.Builder("test text of length 22");
        final Map<String, Float> scores = new ArrayMap<>();
        scores.put(TextClassifier.TYPE_EMAIL, 1f);
        textLinks.addLink(0, 0, scores);
        textLinks.addLink(0, 0, scores);
        return textLinks.build();
        textLinks.addLink(0, 22, scores);
        textLinks.addLink(0, 22, scores);
        return textLinks;
    }
}