Merge "Add log when clipboard smart actions shown" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
04f38f22d0
@@ -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;
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user