Add shared transitions from clipboard UI

Flag: CLIPBOARD_SHARED_TRANSITIONS

Bug: 277948029
Test: manual
Change-Id: Ic9828ef5577038698772a8c24c08ec5c94ae6eec
This commit is contained in:
Miranda Kephart
2023-04-17 09:01:44 -04:00
parent 8a09737350
commit e98c450cb8
4 changed files with 364 additions and 24 deletions

View File

@@ -18,6 +18,7 @@ package com.android.systemui.clipboardoverlay;
import static android.content.Intent.ACTION_CLOSE_SYSTEM_DIALOGS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_SHOW_ACTIONS;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_SHOWN;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ACTION_TAPPED;
@@ -33,6 +34,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO
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_IMAGE_TIMEOUT;
import static com.android.systemui.flags.Flags.CLIPBOARD_SHARED_TRANSITIONS;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -47,6 +49,7 @@ import android.hardware.input.InputManager;
import android.net.Uri;
import android.os.Looper;
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.InputMonitor;
@@ -54,6 +57,7 @@ import android.view.MotionEvent;
import android.view.WindowInsets;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
@@ -73,7 +77,8 @@ import javax.inject.Inject;
/**
* Controls state and UI for the overlay that appears when something is added to the clipboard
*/
public class ClipboardOverlayController implements ClipboardListener.ClipboardOverlay {
public class ClipboardOverlayController implements ClipboardListener.ClipboardOverlay,
ClipboardOverlayView.ClipboardOverlayCallbacks {
private static final String TAG = "ClipboardOverlayCtrlr";
/** Constants for screenshot/copy deconflicting */
@@ -92,6 +97,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
private final FeatureFlags mFeatureFlags;
private final Executor mBgExecutor;
private final ClipboardImageLoader mClipboardImageLoader;
private final ClipboardTransitionExecutor mTransitionExecutor;
private final ClipboardOverlayView mView;
@@ -179,10 +185,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
ClipboardOverlayUtils clipboardUtils,
@Background Executor bgExecutor,
ClipboardImageLoader clipboardImageLoader,
ClipboardTransitionExecutor transitionExecutor,
UiEventLogger uiEventLogger) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
mClipboardImageLoader = clipboardImageLoader;
mTransitionExecutor = transitionExecutor;
mClipboardLogger = new ClipboardLogger(uiEventLogger);
@@ -200,7 +208,11 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mClipboardUtils = clipboardUtils;
mBgExecutor = bgExecutor;
mView.setCallbacks(mClipboardCallbacks);
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
mView.setCallbacks(this);
} else {
mView.setCallbacks(mClipboardCallbacks);
}
mWindow.withWindowAttached(() -> {
mWindow.setContentView(mView);
@@ -209,16 +221,24 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
});
mTimeoutHandler.setOnTimeoutRunnable(() -> {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
animateOut();
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_TIMED_OUT);
} else {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TIMED_OUT);
animateOut();
}
});
mCloseDialogsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
animateOut();
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
} else {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
animateOut();
}
}
}
};
@@ -229,8 +249,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
@Override
public void onReceive(Context context, Intent intent) {
if (SCREENSHOT_ACTION.equals(intent.getAction())) {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
animateOut();
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
} else {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_DISMISSED_OTHER);
animateOut();
}
}
}
};
@@ -457,8 +481,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
remoteAction.ifPresent(action -> {
mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
mView.post(() -> mView.setActionChip(action, () -> {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
animateOut();
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_ACTION_TAPPED);
} else {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_ACTION_TAPPED);
animateOut();
}
}));
});
}
@@ -500,8 +528,12 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (!mView.isInTouchRegion(
(int) motionEvent.getRawX(), (int) motionEvent.getRawY())) {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
animateOut();
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
} else {
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_TAP_OUTSIDE);
animateOut();
}
}
}
}
@@ -551,12 +583,16 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mEnterAnimator.start();
}
private void finish(ClipboardOverlayEvent event) {
finish(event, null);
}
private void animateOut() {
if (mExitAnimator != null && mExitAnimator.isRunning()) {
return;
}
Animator anim = mView.getExitAnimation();
anim.addListener(new AnimatorListenerAdapter() {
mExitAnimator = mView.getExitAnimation();
mExitAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
@@ -573,8 +609,47 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
}
}
});
mExitAnimator = anim;
anim.start();
mExitAnimator.start();
}
private void finish(ClipboardOverlayEvent event, @Nullable Intent intent) {
if (mExitAnimator != null && mExitAnimator.isRunning()) {
return;
}
mExitAnimator = mView.getExitAnimation();
mExitAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (!mCancelled) {
mClipboardLogger.logSessionComplete(event);
if (intent != null) {
mContext.startActivity(intent);
}
hideImmediate();
}
}
});
mExitAnimator.start();
}
private void finishWithSharedTransition(ClipboardOverlayEvent event, Intent intent) {
if (mExitAnimator != null && mExitAnimator.isRunning()) {
return;
}
mClipboardLogger.logSessionComplete(event);
mExitAnimator = mView.getFadeOutAnimation();
mExitAnimator.start();
mTransitionExecutor.startSharedTransition(
mWindow, mView.getPreview(), intent, this::hideImmediate);
}
void hideImmediate() {
@@ -613,6 +688,76 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
mClipboardLogger.reset();
}
@Override
public void onDismissButtonTapped() {
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
}
}
@Override
public void onRemoteCopyButtonTapped() {
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
finish(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED,
IntentCreator.getRemoteCopyIntent(mClipboardModel.getClipData(), mContext));
}
}
@Override
public void onShareButtonTapped() {
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
if (mClipboardModel.getType() != ClipboardModel.Type.OTHER) {
finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED,
IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext));
}
}
}
@Override
public void onPreviewTapped() {
if (mFeatureFlags.isEnabled(CLIPBOARD_SHARED_TRANSITIONS)) {
switch (mClipboardModel.getType()) {
case TEXT:
finish(CLIPBOARD_OVERLAY_EDIT_TAPPED,
IntentCreator.getTextEditorIntent(mContext));
break;
case IMAGE:
finishWithSharedTransition(CLIPBOARD_OVERLAY_EDIT_TAPPED,
IntentCreator.getImageEditIntent(mClipboardModel.getUri(), mContext));
break;
default:
Log.w(TAG, "Got preview tapped callback for non-editable type "
+ mClipboardModel.getType());
}
}
}
@Override
public void onMinimizedViewTapped() {
animateFromMinimized();
}
@Override
public void onInteraction() {
if (!mClipboardModel.isRemote()) {
mTimeoutHandler.resetTimeout();
}
}
@Override
public void onSwipeDismissInitiated(Animator animator) {
if (mExitAnimator != null && mExitAnimator.isRunning()) {
mExitAnimator.cancel();
}
mExitAnimator = animator;
mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
}
@Override
public void onDismissComplete() {
hideImmediate();
}
static class ClipboardLogger {
private final UiEventLogger mUiEventLogger;
private String mClipSource;

View File

@@ -254,6 +254,10 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
});
}
View getPreview() {
return mClipboardPreview;
}
void showImagePreview(@Nullable Bitmap thumbnail) {
if (thumbnail == null) {
mHiddenPreview.setText(mContext.getString(R.string.clipboard_text_hidden));
@@ -368,6 +372,19 @@ public class ClipboardOverlayView extends DraggableConstraintLayout {
return enterAnim;
}
Animator getFadeOutAnimation() {
ValueAnimator alphaAnim = ValueAnimator.ofFloat(1, 0);
alphaAnim.addUpdateListener(animation -> {
float alpha = (float) animation.getAnimatedValue();
mActionContainer.setAlpha(alpha);
mActionContainerBackground.setAlpha(alpha);
mPreviewBorder.setAlpha(alpha);
mDismissButton.setAlpha(alpha);
});
alphaAnim.setDuration(300);
return alphaAnim;
}
Animator getExitAnimation() {
TimeInterpolator linearInterpolator = new LinearInterpolator();
TimeInterpolator scaleInterpolator = new PathInterpolator(.3f, 0, 1f, 1f);

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2023 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.app.ActivityOptions
import android.app.ExitTransitionCoordinator
import android.content.Context
import android.content.Intent
import android.os.RemoteException
import android.util.Log
import android.util.Pair
import android.view.IRemoteAnimationFinishedCallback
import android.view.IRemoteAnimationRunner
import android.view.RemoteAnimationAdapter
import android.view.RemoteAnimationTarget
import android.view.View
import android.view.Window
import android.view.WindowManagerGlobal
import com.android.internal.app.ChooserActivity
import com.android.systemui.settings.DisplayTracker
import javax.inject.Inject
class ClipboardTransitionExecutor
@Inject
constructor(val context: Context, val displayTracker: DisplayTracker) {
fun startSharedTransition(window: Window, view: View, intent: Intent, onReady: Runnable) {
val transition: Pair<ActivityOptions, ExitTransitionCoordinator> =
ActivityOptions.startSharedElementAnimation(
window,
object : ExitTransitionCoordinator.ExitTransitionCallbacks {
override fun isReturnTransitionAllowed(): Boolean {
return false
}
override fun hideSharedElements() {
onReady.run()
}
override fun onFinish() {}
},
null,
Pair.create(view, ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)
)
transition.second.startExit()
context.startActivity(intent, transition.first.toBundle())
val runner = RemoteAnimationAdapter(NULL_ACTIVITY_TRANSITION, 0, 0)
try {
WindowManagerGlobal.getWindowManagerService()
.overridePendingAppTransitionRemote(runner, displayTracker.defaultDisplayId)
} catch (e: Exception) {
Log.e(TAG, "Error overriding clipboard app transition", e)
}
}
private val TAG: String = "ClipboardTransitionExec"
/**
* This is effectively a no-op, but we need something non-null to pass in, in order to
* successfully override the pending activity entrance animation.
*/
private val NULL_ACTIVITY_TRANSITION: IRemoteAnimationRunner.Stub =
object : IRemoteAnimationRunner.Stub() {
override fun onAnimationStart(
transit: Int,
apps: Array<RemoteAnimationTarget>,
wallpapers: Array<RemoteAnimationTarget>,
nonApps: Array<RemoteAnimationTarget>,
finishedCallback: IRemoteAnimationFinishedCallback
) {
try {
finishedCallback.onAnimationFinished()
} catch (e: RemoteException) {
Log.e(TAG, "Error finishing screenshot remote animation", e)
}
}
override fun onAnimationCancelled() {}
}
}

View File

@@ -26,6 +26,7 @@ import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBO
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
import static com.android.systemui.flags.Flags.CLIPBOARD_SHARED_TRANSITIONS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -93,12 +94,16 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Mock
private ClipboardImageLoader mClipboardImageLoader;
@Mock
private ClipboardTransitionExecutor mClipboardTransitionExecutor;
@Mock
private UiEventLogger mUiEventLogger;
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock
private Animator mAnimator;
private ArgumentCaptor<Animator.AnimatorListener> mAnimatorListenerCaptor =
ArgumentCaptor.forClass(Animator.AnimatorListener.class);
private ClipData mSampleClipData;
@@ -117,6 +122,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
when(mClipboardOverlayView.getEnterAnimation()).thenReturn(mAnimator);
when(mClipboardOverlayView.getExitAnimation()).thenReturn(mAnimator);
when(mClipboardOverlayView.getFadeOutAnimation()).thenReturn(mAnimator);
when(mClipboardOverlayWindow.getWindowInsets()).thenReturn(
getImeInsets(new Rect(0, 0, 0, 0)));
@@ -124,7 +130,16 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
new ClipData.Item("Test Item"));
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, true); // turned off for legacy tests
mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, true); // turned off for old tests
}
/**
* Needs to be done after setting flags for legacy tests, since the value of
* CLIPBOARD_SHARED_TRANSITIONS is checked during construction. This can be moved back into
* the setup method once CLIPBOARD_SHARED_TRANSITIONS is fully released and the tests where it
* is false are removed.[
*/
private void initController() {
mOverlayController = new ClipboardOverlayController(
mContext,
mClipboardOverlayView,
@@ -136,6 +151,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
mClipboardUtils,
mExecutor,
mClipboardImageLoader,
mClipboardTransitionExecutor,
mUiEventLogger);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue();
@@ -148,6 +164,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_invalidImageData_legacy() {
initController();
ClipData clipData = new ClipData("", new String[]{"image/png"},
new ClipData.Item(Uri.parse("")));
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
@@ -161,6 +179,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_nonImageUri_legacy() {
initController();
ClipData clipData = new ClipData("", new String[]{"resource/png"},
new ClipData.Item(Uri.parse("")));
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
@@ -175,6 +195,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_textData_legacy() {
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
initController();
mOverlayController.setClipData(mSampleClipData, "abc");
verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false);
@@ -186,6 +208,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_sensitiveTextData_legacy() {
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
initController();
ClipDescription description = mSampleClipData.getDescription();
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
@@ -202,6 +226,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
public void test_setClipData_repeatedCalls_legacy() {
when(mAnimator.isRunning()).thenReturn(true);
mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
initController();
mOverlayController.setClipData(mSampleClipData, "");
mOverlayController.setClipData(mSampleClipData, "");
@@ -211,6 +236,8 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_invalidImageData() {
initController();
ClipData clipData = new ClipData("", new String[]{"image/png"},
new ClipData.Item(Uri.parse("")));
@@ -223,6 +250,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_nonImageUri() {
initController();
ClipData clipData = new ClipData("", new String[]{"resource/png"},
new ClipData.Item(Uri.parse("")));
@@ -235,6 +263,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_textData() {
initController();
mOverlayController.setClipData(mSampleClipData, "abc");
verify(mClipboardOverlayView, times(1)).showTextPreview("Test Item", false);
@@ -245,6 +274,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_sensitiveTextData() {
initController();
ClipDescription description = mSampleClipData.getDescription();
PersistableBundle b = new PersistableBundle();
b.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
@@ -259,6 +289,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_setClipData_repeatedCalls() {
initController();
when(mAnimator.isRunning()).thenReturn(true);
mOverlayController.setClipData(mSampleClipData, "");
@@ -268,7 +299,9 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
}
@Test
public void test_viewCallbacks_onShareTapped() {
public void test_viewCallbacks_onShareTapped_sharedTransitionsOff() {
mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, false);
initController();
mOverlayController.setClipData(mSampleClipData, "");
mCallbacks.onShareButtonTapped();
@@ -278,7 +311,22 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
}
@Test
public void test_viewCallbacks_onDismissTapped() {
public void test_viewCallbacks_onShareTapped() {
initController();
mOverlayController.setClipData(mSampleClipData, "");
mCallbacks.onShareButtonTapped();
verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
mAnimatorListenerCaptor.getValue().onAnimationEnd(mAnimator);
verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "");
verify(mClipboardOverlayView, times(1)).getFadeOutAnimation();
}
@Test
public void test_viewCallbacks_onDismissTapped_sharedTransitionsOff() {
mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, false);
initController();
mOverlayController.setClipData(mSampleClipData, "");
mCallbacks.onDismissButtonTapped();
@@ -287,8 +335,36 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
verify(mClipboardOverlayView, times(1)).getExitAnimation();
}
@Test
public void test_viewCallbacks_onDismissTapped() {
initController();
mCallbacks.onDismissButtonTapped();
verify(mAnimator).addListener(mAnimatorListenerCaptor.capture());
mAnimatorListenerCaptor.getValue().onAnimationEnd(mAnimator);
// package name is null since we haven't actually set a source for this test
verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, null);
verify(mClipboardOverlayView, times(1)).getExitAnimation();
}
@Test
public void test_multipleDismissals_dismissesOnce_sharedTransitionsOff() {
mFeatureFlags.set(CLIPBOARD_SHARED_TRANSITIONS, false);
initController();
mCallbacks.onSwipeDismissInitiated(mAnimator);
mCallbacks.onDismissButtonTapped();
mCallbacks.onSwipeDismissInitiated(mAnimator);
mCallbacks.onDismissButtonTapped();
verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED, 0, null);
verify(mUiEventLogger, never()).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
}
@Test
public void test_multipleDismissals_dismissesOnce() {
initController();
mCallbacks.onSwipeDismissInitiated(mAnimator);
mCallbacks.onDismissButtonTapped();
mCallbacks.onSwipeDismissInitiated(mAnimator);
@@ -300,6 +376,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_remoteCopy_withFlagOn() {
initController();
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
mOverlayController.setClipData(mSampleClipData, "");
@@ -309,6 +386,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_nonRemoteCopy() {
initController();
when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(false);
mOverlayController.setClipData(mSampleClipData, "");
@@ -318,13 +396,16 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_logsUseLastClipSource() {
mOverlayController.setClipData(mSampleClipData, "first.package");
mCallbacks.onDismissButtonTapped();
mOverlayController.setClipData(mSampleClipData, "second.package");
mCallbacks.onDismissButtonTapped();
initController();
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "first.package");
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED, 0, "second.package");
mOverlayController.setClipData(mSampleClipData, "first.package");
mCallbacks.onShareButtonTapped();
mOverlayController.setClipData(mSampleClipData, "second.package");
mCallbacks.onShareButtonTapped();
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "first.package");
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHARE_TAPPED, 0, "second.package");
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "first.package");
verify(mUiEventLogger).log(CLIPBOARD_OVERLAY_SHOWN_EXPANDED, 0, "second.package");
verifyNoMoreInteractions(mUiEventLogger);
@@ -332,6 +413,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_logOnClipboardActionsShown() {
initController();
ClipData.Item item = mSampleClipData.getItemAt(0);
item.setTextLinks(Mockito.mock(TextLinks.class));
when(mClipboardUtils.isRemoteCopy(any(Context.class), any(ClipData.class), anyString()))
@@ -357,6 +439,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_noInsets_showsExpanded() {
initController();
mOverlayController.setClipData(mSampleClipData, "");
verify(mClipboardOverlayView, never()).setMinimized(true);
@@ -366,6 +449,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_insets_showsMinimized() {
initController();
when(mClipboardOverlayWindow.getWindowInsets()).thenReturn(
getImeInsets(new Rect(0, 0, 0, 1)));
mOverlayController.setClipData(mSampleClipData, "abc");
@@ -389,6 +473,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase {
@Test
public void test_insetsChanged_minimizes() {
initController();
mOverlayController.setClipData(mSampleClipData, "");
verify(mClipboardOverlayView, never()).setMinimized(true);