Merge "Add log when clipboard smart actions shown" into tm-qpr-dev

This commit is contained in:
Miranda Kephart
2022-12-15 16:02:47 +00:00
committed by Android (Google) Code Review
6 changed files with 196 additions and 31 deletions

View File

@@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_EDIT_BUTTON;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_SHOWN;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISSED_OTHER; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISSED_OTHER;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED;
@@ -41,7 +42,6 @@ import android.app.RemoteAction;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipDescription; import android.content.ClipDescription;
import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@@ -51,7 +51,6 @@ import android.graphics.Bitmap;
import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask;
import android.os.Looper; import android.os.Looper;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.text.TextUtils; import android.text.TextUtils;
@@ -62,10 +61,6 @@ import android.view.InputEvent;
import android.view.InputEventReceiver; import android.view.InputEventReceiver;
import android.view.InputMonitor; import android.view.InputMonitor;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -74,12 +69,13 @@ import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext; import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.screenshot.TimeoutHandler; import com.android.systemui.screenshot.TimeoutHandler;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject; import javax.inject.Inject;
@@ -102,9 +98,9 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
private final DisplayManager mDisplayManager; private final DisplayManager mDisplayManager;
private final ClipboardOverlayWindow mWindow; private final ClipboardOverlayWindow mWindow;
private final TimeoutHandler mTimeoutHandler; private final TimeoutHandler mTimeoutHandler;
private final TextClassifier mTextClassifier;
private final ClipboardOverlayUtils mClipboardUtils; private final ClipboardOverlayUtils mClipboardUtils;
private final FeatureFlags mFeatureFlags; private final FeatureFlags mFeatureFlags;
private final Executor mBgExecutor;
private final ClipboardOverlayView mView; private final ClipboardOverlayView mView;
@@ -189,6 +185,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
TimeoutHandler timeoutHandler, TimeoutHandler timeoutHandler,
FeatureFlags featureFlags, FeatureFlags featureFlags,
ClipboardOverlayUtils clipboardUtils, ClipboardOverlayUtils clipboardUtils,
@Background Executor bgExecutor,
UiEventLogger uiEventLogger) { UiEventLogger uiEventLogger) {
mBroadcastDispatcher = broadcastDispatcher; mBroadcastDispatcher = broadcastDispatcher;
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class)); mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
@@ -204,14 +201,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
hideImmediate(); hideImmediate();
}); });
mTextClassifier = requireNonNull(context.getSystemService(TextClassificationManager.class))
.getTextClassifier();
mTimeoutHandler = timeoutHandler; mTimeoutHandler = timeoutHandler;
mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS); mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
mFeatureFlags = featureFlags; mFeatureFlags = featureFlags;
mClipboardUtils = clipboardUtils; mClipboardUtils = clipboardUtils;
mBgExecutor = bgExecutor;
mView.setCallbacks(mClipboardCallbacks); mView.setCallbacks(mClipboardCallbacks);
@@ -281,7 +276,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
if (isRemote || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI, if (isRemote || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) { CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
if (item.getTextLinks() != null) { if (item.getTextLinks() != null) {
AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource)); classifyText(clipData.getItemAt(0), clipSource);
} }
} }
if (isSensitive) { if (isSensitive) {
@@ -338,22 +333,18 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
} }
private void classifyText(ClipData.Item item, String source) { private void classifyText(ClipData.Item item, String source) {
ArrayList<RemoteAction> actions = new ArrayList<>(); mBgExecutor.execute(() -> {
for (TextLinks.TextLink link : item.getTextLinks().getLinks()) { Optional<RemoteAction> action = mClipboardUtils.getAction(item, source);
TextClassification classification = mTextClassifier.classifyText(
item.getText(), link.getStart(), link.getEnd(), null);
actions.addAll(classification.getActions());
}
mView.post(() -> { mView.post(() -> {
Optional<RemoteAction> action = actions.stream().filter(remoteAction -> {
ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
return component != null && !TextUtils.equals(source, component.getPackageName());
}).findFirst();
mView.resetActionChips(); mView.resetActionChips();
action.ifPresent(remoteAction -> mView.setActionChip(remoteAction, () -> { action.ifPresent(remoteAction -> {
mView.setActionChip(remoteAction, () -> {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED); mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
animateOut(); animateOut();
})); });
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
});
});
}); });
} }
@@ -539,6 +530,10 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mClipSource = clipSource; mClipSource = clipSource;
} }
void logUnguarded(@NonNull UiEventLogger.UiEventEnum event) {
mUiEventLogger.log(event, 0, mClipSource);
}
void logSessionComplete(@NonNull UiEventLogger.UiEventEnum event) { void logSessionComplete(@NonNull UiEventLogger.UiEventEnum event) {
if (!mGuarded) { if (!mGuarded) {
mGuarded = true; mGuarded = true;

View File

@@ -28,6 +28,8 @@ public enum ClipboardOverlayEvent implements UiEventLogger.UiEventEnum {
CLIPBOARD_OVERLAY_EDIT_TAPPED(951), CLIPBOARD_OVERLAY_EDIT_TAPPED(951),
@UiEvent(doc = "clipboard share tapped") @UiEvent(doc = "clipboard share tapped")
CLIPBOARD_OVERLAY_SHARE_TAPPED(1067), CLIPBOARD_OVERLAY_SHARE_TAPPED(1067),
@UiEvent(doc = "clipboard smart action shown")
CLIPBOARD_OVERLAY_ACTION_SHOWN(1260),
@UiEvent(doc = "clipboard action tapped") @UiEvent(doc = "clipboard action tapped")
CLIPBOARD_OVERLAY_ACTION_TAPPED(952), CLIPBOARD_OVERLAY_ACTION_TAPPED(952),
@UiEvent(doc = "clipboard remote copy tapped") @UiEvent(doc = "clipboard remote copy tapped")

View File

@@ -16,22 +16,34 @@
package com.android.systemui.clipboardoverlay; package com.android.systemui.clipboardoverlay;
import android.app.RemoteAction;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipDescription; import android.content.ClipDescription;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Build;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.systemui.R; import com.android.systemui.R;
import java.util.ArrayList;
import java.util.Optional;
import javax.inject.Inject; import javax.inject.Inject;
class ClipboardOverlayUtils { class ClipboardOverlayUtils {
private final TextClassifier mTextClassifier;
@Inject @Inject
ClipboardOverlayUtils() { ClipboardOverlayUtils(TextClassificationManager textClassificationManager) {
mTextClassifier = textClassificationManager.getTextClassifier();
} }
boolean isRemoteCopy(Context context, ClipData clipData, String clipSource) { boolean isRemoteCopy(Context context, ClipData clipData, String clipSource) {
@@ -52,4 +64,21 @@ class ClipboardOverlayUtils {
} }
return false; return false;
} }
public Optional<RemoteAction> getAction(ClipData.Item item, String source) {
return getActions(item).stream().filter(remoteAction -> {
ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
return component != null && !TextUtils.equals(source, component.getPackageName());
}).findFirst();
}
private ArrayList<RemoteAction> getActions(ClipData.Item item) {
ArrayList<RemoteAction> actions = new ArrayList<>();
for (TextLinks.TextLink link : item.getTextLinks().getLinks()) {
TextClassification classification = mTextClassifier.classifyText(
item.getText(), link.getStart(), link.getEnd(), null);
actions.addAll(classification.getActions());
}
return actions;
}
} }

View File

@@ -92,6 +92,7 @@ import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.view.textclassifier.TextClassificationManager;
import androidx.core.app.NotificationManagerCompat; import androidx.core.app.NotificationManagerCompat;
@@ -631,4 +632,10 @@ public class FrameworkServicesModule {
static BluetoothAdapter provideBluetoothAdapter(BluetoothManager bluetoothManager) { static BluetoothAdapter provideBluetoothAdapter(BluetoothManager bluetoothManager) {
return bluetoothManager.getAdapter(); return bluetoothManager.getAdapter();
} }
@Provides
@Singleton
static TextClassificationManager provideTextClassificationManager(Context context) {
return context.getSystemService(TextClassificationManager.class);
}
} }

View File

@@ -16,12 +16,14 @@
package com.android.systemui.clipboardoverlay; package com.android.systemui.clipboardoverlay;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_SHOWN;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHARE_TAPPED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHARE_TAPPED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR; import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@@ -29,10 +31,13 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.animation.Animator; import android.animation.Animator;
import android.app.RemoteAction;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipDescription; import android.content.ClipDescription;
import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.view.textclassifier.TextLinks;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -42,6 +47,8 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastSender; import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.flags.FakeFeatureFlags; import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.screenshot.TimeoutHandler; import com.android.systemui.screenshot.TimeoutHandler;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@@ -50,7 +57,12 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Optional;
@SmallTest @SmallTest
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@@ -80,6 +92,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor; private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor;
private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks; private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Before @Before
public void setup() { public void setup() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
@@ -101,6 +115,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
mTimeoutHandler, mTimeoutHandler,
mFeatureFlags, mFeatureFlags,
mClipboardUtils, mClipboardUtils,
mExecutor,
mUiEventLogger); mUiEventLogger);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture()); verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue(); mCallbacks = mOverlayCallbacksCaptor.getValue();
@@ -237,4 +252,29 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "second.package"); verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "second.package");
verifyNoMoreInteractions(mUiEventLogger); verifyNoMoreInteractions(mUiEventLogger);
} }
@Test
public void test_logOnClipboardActionsShown() {
ClipData.Item item = mSampleClipData.getItemAt(0);
item.setTextLinks(Mockito.mock(TextLinks.class));
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
.thenReturn(true);
when(mClipboardUtils.getAction(any(ClipData.Item.class), anyString()))
.thenReturn(Optional.of(Mockito.mock(RemoteAction.class)));
when(mClipboardOverlayView.post(any(Runnable.class))).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((Runnable) invocation.getArgument(0)).run();
return null;
}
});
mOverlayController.setClipData(
new ClipData(mSampleClipData.getDescription(), item), "actionShownSource");
mExecutor.runAllReady();
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_ACTION_SHOWN, 0, "actionShownSource");
verifyNoMoreInteractions(mUiEventLogger);
}
} }

View File

@@ -16,13 +16,24 @@
package com.android.systemui.clipboardoverlay; package com.android.systemui.clipboardoverlay;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.when;
import android.app.RemoteAction;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipDescription; import android.content.ClipDescription;
import android.os.PersistableBundle; import android.os.PersistableBundle;
import android.testing.TestableResources; import android.testing.TestableResources;
import android.util.ArrayMap;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextLinks;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
@@ -30,19 +41,84 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.google.android.collect.Lists;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Map;
import java.util.Optional;
@SmallTest @SmallTest
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ClipboardOverlayUtilsTest extends SysuiTestCase { public class ClipboardOverlayUtilsTest extends SysuiTestCase {
private ClipboardOverlayUtils mClipboardUtils; private ClipboardOverlayUtils mClipboardUtils;
@Mock
private TextClassificationManager mTextClassificationManager;
@Mock
private TextClassifier mTextClassifier;
@Mock
private ClipData.Item mClipDataItem;
@Before @Before
public void setUp() { public void setUp() {
mClipboardUtils = new ClipboardOverlayUtils(); MockitoAnnotations.initMocks(this);
when(mTextClassificationManager.getTextClassifier()).thenReturn(mTextClassifier);
mClipboardUtils = new ClipboardOverlayUtils(mTextClassificationManager);
}
@Test
public void test_getAction_noLinks_returnsEmptyOptional() {
ClipData.Item item = new ClipData.Item("no text links");
item.setTextLinks(Mockito.mock(TextLinks.class));
Optional<RemoteAction> action = mClipboardUtils.getAction(item, "");
assertTrue(action.isEmpty());
}
@Test
public void test_getAction_returnsFirstLink() {
when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
when(mClipDataItem.getText()).thenReturn("");
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(mClipDataItem, "def").orElse(null);
assertEquals(actionA, result);
}
@Test
public void test_getAction_skipsMatchingComponent() {
when(mClipDataItem.getTextLinks()).thenReturn(getFakeTextLinks());
when(mClipDataItem.getText()).thenReturn("");
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(mClipDataItem, "abc").orElse(null);
assertEquals(actionB, result);
} }
@Test @Test
@@ -92,7 +168,7 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, "")); assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, ""));
} }
static ClipData constructClipData(String[] mimeTypes, ClipData.Item item, private static ClipData constructClipData(String[] mimeTypes, ClipData.Item item,
PersistableBundle extras) { PersistableBundle extras) {
ClipDescription description = new ClipDescription("Test", mimeTypes); ClipDescription description = new ClipDescription("Test", mimeTypes);
if (extras != null) { if (extras != null) {
@@ -100,4 +176,20 @@ public class ClipboardOverlayUtilsTest extends SysuiTestCase {
} }
return new ClipData(description, item); return new ClipData(description, item);
} }
private static RemoteAction constructRemoteAction(String packageName) {
RemoteAction action = Mockito.mock(RemoteAction.class, Answers.RETURNS_DEEP_STUBS);
when(action.getActionIntent().getIntent().getComponent().getPackageName())
.thenReturn(packageName);
return action;
}
private static TextLinks getFakeTextLinks() {
TextLinks.Builder textLinks = new TextLinks.Builder("test");
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();
}
} }