Merge "Persist copy UI from remote devices" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
02bc3d23ff
@@ -31,6 +31,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO
|
||||
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
|
||||
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
|
||||
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
|
||||
import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
@@ -73,6 +74,7 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.broadcast.BroadcastSender;
|
||||
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.screenshot.TimeoutHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -101,6 +103,8 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
private final ClipboardOverlayWindow mWindow;
|
||||
private final TimeoutHandler mTimeoutHandler;
|
||||
private final TextClassifier mTextClassifier;
|
||||
private final ClipboardOverlayUtils mClipboardUtils;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
|
||||
private final ClipboardOverlayView mView;
|
||||
|
||||
@@ -119,11 +123,15 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
private Animator mExitAnimator;
|
||||
private Animator mEnterAnimator;
|
||||
|
||||
private Runnable mOnUiUpdate;
|
||||
|
||||
private final ClipboardOverlayView.ClipboardOverlayCallbacks mClipboardCallbacks =
|
||||
new ClipboardOverlayView.ClipboardOverlayCallbacks() {
|
||||
@Override
|
||||
public void onInteraction() {
|
||||
mTimeoutHandler.resetTimeout();
|
||||
if (mOnUiUpdate != null) {
|
||||
mOnUiUpdate.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,7 +186,10 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
ClipboardOverlayWindow clipboardOverlayWindow,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
BroadcastSender broadcastSender,
|
||||
TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) {
|
||||
TimeoutHandler timeoutHandler,
|
||||
FeatureFlags featureFlags,
|
||||
ClipboardOverlayUtils clipboardUtils,
|
||||
UiEventLogger uiEventLogger) {
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
|
||||
final Context displayContext = context.createDisplayContext(getDefaultDisplay());
|
||||
@@ -199,6 +210,9 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
mTimeoutHandler = timeoutHandler;
|
||||
mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
|
||||
|
||||
mFeatureFlags = featureFlags;
|
||||
mClipboardUtils = clipboardUtils;
|
||||
|
||||
mView.setCallbacks(mClipboardCallbacks);
|
||||
|
||||
|
||||
@@ -257,11 +271,13 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
|
||||
&& clipData.getDescription().getExtras()
|
||||
.getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
|
||||
boolean isRemote = mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR)
|
||||
&& mClipboardUtils.isRemoteCopy(mContext, clipData, clipSource);
|
||||
if (clipData == null || clipData.getItemCount() == 0) {
|
||||
mView.showDefaultTextPreview();
|
||||
} else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
|
||||
ClipData.Item item = clipData.getItemAt(0);
|
||||
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||
if (isRemote || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
|
||||
CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
|
||||
if (item.getTextLinks() != null) {
|
||||
AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
|
||||
@@ -287,7 +303,13 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
maybeShowRemoteCopy(clipData);
|
||||
animateIn();
|
||||
mView.announceForAccessibility(accessibilityAnnouncement);
|
||||
mTimeoutHandler.resetTimeout();
|
||||
if (isRemote) {
|
||||
mTimeoutHandler.cancelTimeout();
|
||||
mOnUiUpdate = null;
|
||||
} else {
|
||||
mOnUiUpdate = mTimeoutHandler::resetTimeout;
|
||||
mOnUiUpdate.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeShowRemoteCopy(ClipData clipData) {
|
||||
@@ -427,7 +449,9 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
mTimeoutHandler.resetTimeout();
|
||||
if (mOnUiUpdate != null) {
|
||||
mOnUiUpdate.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
mEnterAnimator.start();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.clipboardoverlay;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
class ClipboardOverlayUtils {
|
||||
|
||||
@Inject
|
||||
ClipboardOverlayUtils() {
|
||||
}
|
||||
|
||||
boolean isRemoteCopy(Context context, ClipData clipData, String clipSource) {
|
||||
if (clipData != null && clipData.getDescription().getExtras() != null
|
||||
&& clipData.getDescription().getExtras().getBoolean(
|
||||
ClipDescription.EXTRA_IS_REMOTE_DEVICE)) {
|
||||
ComponentName remoteComponent = ComponentName.unflattenFromString(
|
||||
context.getResources().getString(R.string.config_remoteCopyPackage));
|
||||
if (remoteComponent != null) {
|
||||
return remoteComponent.getPackageName().equals(clipSource);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -316,6 +316,7 @@ object Flags {
|
||||
|
||||
// 1700 - clipboard
|
||||
@JvmField val CLIPBOARD_OVERLAY_REFACTOR = UnreleasedFlag(1700)
|
||||
@JvmField val CLIPBOARD_REMOTE_BEHAVIOR = UnreleasedFlag(1701)
|
||||
|
||||
// 1800 - shade container
|
||||
@JvmField val LEAVE_SHADE_OPEN_FOR_BUGREPORT = UnreleasedFlag(1800, teamfood = true)
|
||||
|
||||
@@ -19,7 +19,9 @@ package com.android.systemui.clipboardoverlay;
|
||||
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_SWIPE_DISMISSED;
|
||||
import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -37,6 +39,7 @@ import androidx.test.runner.AndroidJUnit4;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.broadcast.BroadcastSender;
|
||||
import com.android.systemui.flags.FakeFeatureFlags;
|
||||
import com.android.systemui.screenshot.TimeoutHandler;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -62,7 +65,10 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private TimeoutHandler mTimeoutHandler;
|
||||
@Mock
|
||||
private ClipboardOverlayUtils mClipboardUtils;
|
||||
@Mock
|
||||
private UiEventLogger mUiEventLogger;
|
||||
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
|
||||
|
||||
@Mock
|
||||
private Animator mAnimator;
|
||||
@@ -73,7 +79,6 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
|
||||
private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor;
|
||||
private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -84,6 +89,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
|
||||
mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
|
||||
new ClipData.Item("Test Item"));
|
||||
|
||||
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, false);
|
||||
|
||||
mOverlayController = new ClipboardOverlayController(
|
||||
mContext,
|
||||
mClipboardOverlayView,
|
||||
@@ -91,6 +98,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
|
||||
getFakeBroadcastDispatcher(),
|
||||
mBroadcastSender,
|
||||
mTimeoutHandler,
|
||||
mFeatureFlags,
|
||||
mClipboardUtils,
|
||||
mUiEventLogger);
|
||||
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
|
||||
mCallbacks = mOverlayCallbacksCaptor.getValue();
|
||||
@@ -186,4 +195,33 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
|
||||
verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
|
||||
verify(mUiEventLogger, never()).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_remoteCopy_withFlagOn() {
|
||||
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
|
||||
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
|
||||
|
||||
mOverlayController.setClipData(mSampleClipData, "");
|
||||
|
||||
verify(mTimeoutHandler, never()).resetTimeout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_remoteCopy_withFlagOff() {
|
||||
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
|
||||
|
||||
mOverlayController.setClipData(mSampleClipData, "");
|
||||
|
||||
verify(mTimeoutHandler).resetTimeout();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_nonRemoteCopy() {
|
||||
mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
|
||||
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(false);
|
||||
|
||||
mOverlayController.setClipData(mSampleClipData, "");
|
||||
|
||||
verify(mTimeoutHandler).resetTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.clipboardoverlay;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipDescription;
|
||||
import android.os.PersistableBundle;
|
||||
import android.testing.TestableResources;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ClipboardOverlayUtilsTest extends SysuiTestCase {
|
||||
|
||||
private ClipboardOverlayUtils mClipboardUtils;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mClipboardUtils = new ClipboardOverlayUtils();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_extra_withPackage_returnsTrue() {
|
||||
PersistableBundle b = new PersistableBundle();
|
||||
b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
|
||||
ClipData data = constructClipData(
|
||||
new String[]{"text/plain"}, new ClipData.Item("6175550000"), b);
|
||||
TestableResources res = mContext.getOrCreateTestableResources();
|
||||
res.addOverride(
|
||||
R.string.config_remoteCopyPackage, "com.android.remote/.RemoteActivity");
|
||||
|
||||
assertTrue(mClipboardUtils.isRemoteCopy(mContext, data, "com.android.remote"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_noExtra_returnsFalse() {
|
||||
ClipData data = constructClipData(
|
||||
new String[]{"text/plain"}, new ClipData.Item("6175550000"), null);
|
||||
TestableResources res = mContext.getOrCreateTestableResources();
|
||||
res.addOverride(
|
||||
R.string.config_remoteCopyPackage, "com.android.remote/.RemoteActivity");
|
||||
|
||||
assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, "com.android.remote"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_falseExtra_returnsFalse() {
|
||||
PersistableBundle b = new PersistableBundle();
|
||||
b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, false);
|
||||
ClipData data = constructClipData(
|
||||
new String[]{"text/plain"}, new ClipData.Item("6175550000"), b);
|
||||
TestableResources res = mContext.getOrCreateTestableResources();
|
||||
res.addOverride(
|
||||
R.string.config_remoteCopyPackage, "com.android.remote/.RemoteActivity");
|
||||
|
||||
assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, "com.android.remote"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_wrongPackage_returnsFalse() {
|
||||
PersistableBundle b = new PersistableBundle();
|
||||
b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
|
||||
ClipData data = constructClipData(
|
||||
new String[]{"text/plain"}, new ClipData.Item("6175550000"), b);
|
||||
|
||||
assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, ""));
|
||||
}
|
||||
|
||||
static ClipData constructClipData(String[] mimeTypes, ClipData.Item item,
|
||||
PersistableBundle extras) {
|
||||
ClipDescription description = new ClipDescription("Test", mimeTypes);
|
||||
if (extras != null) {
|
||||
description.setExtras(extras);
|
||||
}
|
||||
return new ClipData(description, item);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user