From e98c450cb828fb090db3178331b39c9fbb1ef8f2 Mon Sep 17 00:00:00 2001 From: Miranda Kephart Date: Mon, 17 Apr 2023 09:01:44 -0400 Subject: [PATCH] Add shared transitions from clipboard UI Flag: CLIPBOARD_SHARED_TRANSITIONS Bug: 277948029 Test: manual Change-Id: Ic9828ef5577038698772a8c24c08ec5c94ae6eec --- .../ClipboardOverlayController.java | 177 ++++++++++++++++-- .../ClipboardOverlayView.java | 17 ++ .../ClipboardTransitionExecutor.kt | 93 +++++++++ .../ClipboardOverlayControllerTest.java | 101 +++++++++- 4 files changed, 364 insertions(+), 24 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index 757ebf45e9ade..ffd836b3230f2 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -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; diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java index 28c57d31a4f3f..a76d2ea816a71 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt new file mode 100644 index 0000000000000..0b8e83edc88a8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardTransitionExecutor.kt @@ -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.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, + wallpapers: Array, + nonApps: Array, + finishedCallback: IRemoteAnimationFinishedCallback + ) { + try { + finishedCallback.onAnimationFinished() + } catch (e: RemoteException) { + Log.e(TAG, "Error finishing screenshot remote animation", e) + } + } + + override fun onAnimationCancelled() {} + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java index 39fb7b4cda2c4..9671966896501 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -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 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);