diff options
10 files changed, 200 insertions, 6 deletions
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index 13a5248e193b..66eb62a9ead4 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1578,6 +1578,13 @@ flag { } flag { + name: "show_clipboard_indication" + namespace: "systemui" + description: "Show indication text under the clipboard overlay when copied something" + bug: "361199935" +} + +flag { name: "media_projection_dialog_behind_lockscreen" namespace: "systemui" description: "Ensure MediaProjection Dialog appears behind the lockscreen" diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml index 65005f840598..572f063c20c4 100644 --- a/packages/SystemUI/res/layout/clipboard_overlay.xml +++ b/packages/SystemUI/res/layout/clipboard_overlay.xml @@ -32,6 +32,34 @@ android:id="@+id/min_edge_guideline" app:layout_constraintGuide_begin="@dimen/overlay_action_container_minimum_edge_spacing" android:orientation="vertical"/> + <!-- This toast-like indication layout was forked from text_toast.xml and will have the same + appearance as system toast. --> + <FrameLayout + android:id="@+id/indication_container" + android:visibility="gone" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:gravity="center" + android:maxWidth="@*android:dimen/toast_width" + android:background="@android:drawable/toast_frame" + android:elevation="@*android:dimen/toast_elevation" + android:paddingStart="16dp" + android:paddingEnd="16dp" + android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal" + android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" + android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintBottom_toBottomOf="parent"> + <TextView + android:id="@+id/indication_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:ellipsize="end" + android:maxLines="2" + android:paddingTop="12dp" + android:paddingBottom="12dp" + android:textAppearance="@*android:style/TextAppearance.Toast"/> + </FrameLayout> <!-- Negative horizontal margin because this container background must render beyond the thing it's constrained by (the actions themselves). --> <FrameLayout @@ -47,7 +75,7 @@ app:layout_constraintStart_toStartOf="@id/min_edge_guideline" app:layout_constraintTop_toTopOf="@id/actions_container" app:layout_constraintEnd_toEndOf="@id/actions_container" - app:layout_constraintBottom_toBottomOf="parent"/> + app:layout_constraintBottom_toTopOf="@id/indication_container"/> <HorizontalScrollView android:id="@+id/actions_container" android:layout_width="0dp" @@ -144,7 +172,7 @@ android:visibility="gone" android:elevation="7dp" android:padding="8dp" - app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintBottom_toTopOf="@id/indication_container" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom" diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationCallback.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationCallback.kt new file mode 100644 index 000000000000..ddd6bc9ef16b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationCallback.kt @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 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 + +/** Interface for listening to indication text changed from [ClipboardIndicationProvider]. */ +interface ClipboardIndicationCallback { + + /** Notifies the indication text changed. */ + fun onIndicationTextChanged(text: CharSequence) +} diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationProvider.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationProvider.kt new file mode 100644 index 000000000000..be3272369d46 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationProvider.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 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 + +/** Interface to provide the clipboard indication to be shown under the overlay. */ +interface ClipboardIndicationProvider { + + /** + * Gets the indication text async. + * + * @param callback callback for getting the indication text. + */ + fun getIndicationText(callback: ClipboardIndicationCallback) +} diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationProviderImpl.kt new file mode 100644 index 000000000000..da94d5b518b7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardIndicationProviderImpl.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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 com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject + +@SysUISingleton +open class ClipboardIndicationProviderImpl @Inject constructor() : ClipboardIndicationProvider { + + override fun getIndicationText(callback: ClipboardIndicationCallback) {} +} diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java index 65c01ed9eecd..ac747845267c 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java @@ -21,6 +21,7 @@ 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.Flags.clipboardImageTimeout; import static com.android.systemui.Flags.clipboardSharedTransitions; +import static com.android.systemui.Flags.showClipboardIndication; 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_DISMISSED_OTHER; @@ -99,6 +100,7 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv private final ClipboardTransitionExecutor mTransitionExecutor; private final ClipboardOverlayView mView; + private final ClipboardIndicationProvider mClipboardIndicationProvider; private Runnable mOnSessionCompleteListener; private Runnable mOnRemoteCopyTapped; @@ -173,6 +175,13 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv } }; + private ClipboardIndicationCallback mIndicationCallback = new ClipboardIndicationCallback() { + @Override + public void onIndicationTextChanged(@NonNull CharSequence text) { + mView.setIndicationText(text); + } + }; + @Inject public ClipboardOverlayController(@OverlayWindowContext Context context, ClipboardOverlayView clipboardOverlayView, @@ -185,11 +194,13 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv @Background Executor bgExecutor, ClipboardImageLoader clipboardImageLoader, ClipboardTransitionExecutor transitionExecutor, + ClipboardIndicationProvider clipboardIndicationProvider, UiEventLogger uiEventLogger) { mContext = context; mBroadcastDispatcher = broadcastDispatcher; mClipboardImageLoader = clipboardImageLoader; mTransitionExecutor = transitionExecutor; + mClipboardIndicationProvider = clipboardIndicationProvider; mClipboardLogger = new ClipboardLogger(uiEventLogger); @@ -288,6 +299,9 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv boolean shouldAnimate = !model.dataMatches(mClipboardModel) || wasExiting; mClipboardModel = model; mClipboardLogger.setClipSource(mClipboardModel.getSource()); + if (showClipboardIndication()) { + mClipboardIndicationProvider.getIndicationText(mIndicationCallback); + } if (clipboardImageTimeout()) { if (shouldAnimate) { reset(); diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java index 1762d82b3237..7e4d76280909 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java @@ -18,6 +18,8 @@ package com.android.systemui.clipboardoverlay; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; +import static com.android.systemui.Flags.showClipboardIndication; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -53,6 +55,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.view.ViewCompat; import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; @@ -103,6 +106,8 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { private View mShareChip; private View mRemoteCopyChip; private View mActionContainerBackground; + private View mIndicationContainer; + private TextView mIndicationText; private View mDismissButton; private LinearLayout mActionContainer; private ClipboardOverlayCallbacks mClipboardCallbacks; @@ -136,6 +141,8 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { mShareChip = requireViewById(R.id.share_chip); mRemoteCopyChip = requireViewById(R.id.remote_copy_chip); mDismissButton = requireViewById(R.id.dismiss_button); + mIndicationContainer = requireViewById(R.id.indication_container); + mIndicationText = mIndicationContainer.findViewById(R.id.indication_text); bindDefaultActionChips(); @@ -208,6 +215,14 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { } } + void setIndicationText(CharSequence text) { + mIndicationText.setText(text); + + // Set the visibility of clipboard indication based on the text is empty or not. + int visibility = text.isEmpty() ? View.GONE : View.VISIBLE; + mIndicationContainer.setVisibility(visibility); + } + void setMinimized(boolean minimized) { if (minimized) { mMinimizedPreview.setVisibility(View.VISIBLE); @@ -221,6 +236,18 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { mPreviewBorder.setVisibility(View.VISIBLE); mActionContainer.setVisibility(View.VISIBLE); } + + if (showClipboardIndication()) { + // Adjust the margin of clipboard indication based on the minimized state. + int marginStart = minimized ? getResources().getDimensionPixelSize( + R.dimen.overlay_action_container_margin_horizontal) + : getResources().getDimensionPixelSize( + R.dimen.overlay_action_container_minimum_edge_spacing); + ConstraintLayout.LayoutParams params = + (ConstraintLayout.LayoutParams) mIndicationContainer.getLayoutParams(); + params.setMarginStart(marginStart); + mIndicationContainer.setLayoutParams(params); + } } void setInsets(WindowInsets insets, int orientation) { @@ -313,6 +340,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { setTranslationX(0); setAlpha(0); mActionContainerBackground.setVisibility(View.GONE); + mIndicationContainer.setVisibility(View.GONE); mDismissButton.setVisibility(View.GONE); mShareChip.setVisibility(View.GONE); mRemoteCopyChip.setVisibility(View.GONE); diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlaySuppressionModule.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayOverrideModule.kt index 527819c73e2f..c81f0d98f3ad 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlaySuppressionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayOverrideModule.kt @@ -15,18 +15,26 @@ */ package com.android.systemui.clipboardoverlay.dagger +import com.android.systemui.clipboardoverlay.ClipboardIndicationProvider +import com.android.systemui.clipboardoverlay.ClipboardIndicationProviderImpl import com.android.systemui.clipboardoverlay.ClipboardOverlaySuppressionController import com.android.systemui.clipboardoverlay.ClipboardOverlaySuppressionControllerImpl import dagger.Binds import dagger.Module -/** Dagger Module for code in the clipboard overlay package. */ +/** Dagger Module to provide default implementations which could be overridden. */ @Module -interface ClipboardOverlaySuppressionModule { +interface ClipboardOverlayOverrideModule { /** Provides implementation for [ClipboardOverlaySuppressionController]. */ @Binds fun provideClipboardOverlaySuppressionController( clipboardOverlaySuppressionControllerImpl: ClipboardOverlaySuppressionControllerImpl ): ClipboardOverlaySuppressionController + + /** Provides implementation for [ClipboardIndicationProvider]. */ + @Binds + fun provideClipboardIndicationProvider( + clipboardIndicationProviderImpl: ClipboardIndicationProviderImpl + ): ClipboardIndicationProvider } diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java index 609b7330b600..2e323d40edcd 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java @@ -29,7 +29,7 @@ import com.android.systemui.accessibility.AccessibilityModule; import com.android.systemui.accessibility.SystemActionsModule; import com.android.systemui.accessibility.data.repository.AccessibilityRepositoryModule; import com.android.systemui.battery.BatterySaverModule; -import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlaySuppressionModule; +import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayOverrideModule; import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; @@ -125,7 +125,7 @@ import javax.inject.Named; AospPolicyModule.class, BatterySaverModule.class, CentralSurfacesModule.class, - ClipboardOverlaySuppressionModule.class, + ClipboardOverlayOverrideModule.class, CollapsedStatusBarFragmentStartableModule.class, ConnectingDisplayViewModel.StartableModule.class, DefaultBlueprintModule.class, 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 6061063db903..562481567536 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java @@ -20,6 +20,7 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static com.android.systemui.Flags.FLAG_CLIPBOARD_SHARED_TRANSITIONS; import static com.android.systemui.Flags.FLAG_CLIPBOARD_USE_DESCRIPTION_MIMETYPE; +import static com.android.systemui.Flags.FLAG_SHOW_CLIPBOARD_INDICATION; 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_EXPANDED_FROM_MINIMIZED; @@ -121,6 +122,24 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); + private class FakeClipboardIndicationProvider implements ClipboardIndicationProvider { + private ClipboardIndicationCallback mIndicationCallback; + + public void notifyIndicationTextChanged(CharSequence indicationText) { + if (mIndicationCallback != null) { + mIndicationCallback.onIndicationTextChanged(indicationText); + } + } + + @Override + public void getIndicationText(ClipboardIndicationCallback callback) { + mIndicationCallback = callback; + } + } + + private FakeClipboardIndicationProvider mClipboardIndicationProvider = + new FakeClipboardIndicationProvider(); + @Before public void setup() { MockitoAnnotations.initMocks(this); @@ -156,6 +175,7 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { mExecutor, mClipboardImageLoader, mClipboardTransitionExecutor, + mClipboardIndicationProvider, mUiEventLogger); verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture()); mCallbacks = mOverlayCallbacksCaptor.getValue(); @@ -305,6 +325,17 @@ public class ClipboardOverlayControllerTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_SHOW_CLIPBOARD_INDICATION) + public void test_onIndicationTextChanged_setIndicationTextCorrectly() { + initController(); + mOverlayController.setClipData(mSampleClipData, ""); + + mClipboardIndicationProvider.notifyIndicationTextChanged("copied"); + + verify(mClipboardOverlayView).setIndicationText("copied"); + } + + @Test @DisableFlags(FLAG_CLIPBOARD_SHARED_TRANSITIONS) public void test_viewCallbacks_onShareTapped_sharedTransitionsOff() { initController(); |