diff options
8 files changed, 127 insertions, 43 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt index abdbd6880b33..97acccde2524 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt @@ -26,34 +26,45 @@ import com.android.systemui.res.R import javax.inject.Inject /** - * Provides static actions for screenshots. This class can be overridden by a vendor-specific SysUI + * Provides actions for screenshots. This class can be overridden by a vendor-specific SysUI * implementation. */ interface ScreenshotActionsProvider { data class ScreenshotAction( - val icon: Drawable?, - val text: String?, - val overrideTransition: Boolean, + val icon: Drawable? = null, + val text: String? = null, + val description: String, + val overrideTransition: Boolean = false, val retrieveIntent: (Uri) -> Intent ) - fun getPreviewAction(context: Context, uri: Uri, user: UserHandle): Intent - fun getActions(context: Context, user: UserHandle): List<ScreenshotAction> -} + interface ScreenshotActionsCallback { + fun setPreviewAction(overrideTransition: Boolean = false, retrieveIntent: (Uri) -> Intent) + fun addAction(action: ScreenshotAction) = addActions(listOf(action)) + fun addActions(actions: List<ScreenshotAction>) + } -class DefaultScreenshotActionsProvider @Inject constructor() : ScreenshotActionsProvider { - override fun getPreviewAction(context: Context, uri: Uri, user: UserHandle): Intent { - return ActionIntentCreator.createEdit(uri, context) + interface Factory { + fun create( + context: Context, + user: UserHandle?, + callback: ScreenshotActionsCallback + ): ScreenshotActionsProvider } +} - override fun getActions( - context: Context, - user: UserHandle - ): List<ScreenshotActionsProvider.ScreenshotAction> { +class DefaultScreenshotActionsProvider( + private val context: Context, + private val user: UserHandle?, + private val callback: ScreenshotActionsProvider.ScreenshotActionsCallback +) : ScreenshotActionsProvider { + init { + callback.setPreviewAction(true) { ActionIntentCreator.createEdit(it, context) } val editAction = ScreenshotActionsProvider.ScreenshotAction( AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_edit), context.resources.getString(R.string.screenshot_edit_label), + context.resources.getString(R.string.screenshot_edit_description), true ) { uri -> ActionIntentCreator.createEdit(uri, context) @@ -62,10 +73,21 @@ class DefaultScreenshotActionsProvider @Inject constructor() : ScreenshotActions ScreenshotActionsProvider.ScreenshotAction( AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_share), context.resources.getString(R.string.screenshot_share_label), + context.resources.getString(R.string.screenshot_share_description), false ) { uri -> ActionIntentCreator.createShare(uri) } - return listOf(editAction, shareAction) + callback.addActions(listOf(editAction, shareAction)) + } + + class Factory @Inject constructor() : ScreenshotActionsProvider.Factory { + override fun create( + context: Context, + user: UserHandle?, + callback: ScreenshotActionsProvider.ScreenshotActionsCallback + ): ScreenshotActionsProvider { + return DefaultScreenshotActionsProvider(context, user, callback) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index c8e13bb8c2fc..b796a206b5b4 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -19,6 +19,7 @@ package com.android.systemui.screenshot; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; +import static com.android.systemui.Flags.screenshotShelfUi; import static com.android.systemui.screenshot.LogConfig.DEBUG_ANIM; import static com.android.systemui.screenshot.LogConfig.DEBUG_CALLBACK; import static com.android.systemui.screenshot.LogConfig.DEBUG_INPUT; @@ -237,6 +238,7 @@ public class ScreenshotController { private final WindowContext mContext; private final FeatureFlags mFlags; private final ScreenshotViewProxy mViewProxy; + private final ScreenshotActionsProvider.Factory mActionsProviderFactory; private final ScreenshotNotificationsController mNotificationsController; private final ScreenshotSmartActions mScreenshotSmartActions; private final UiEventLogger mUiEventLogger; @@ -271,6 +273,8 @@ public class ScreenshotController { private boolean mScreenshotTakenInPortrait; private boolean mBlockAttach; + private ScreenshotActionsProvider mActionsProvider; + private Animator mScreenshotAnimation; private RequestCallback mCurrentRequestCallback; private String mPackageName = ""; @@ -298,6 +302,7 @@ public class ScreenshotController { Context context, FeatureFlags flags, ScreenshotViewProxy.Factory viewProxyFactory, + ScreenshotActionsProvider.Factory actionsProviderFactory, ScreenshotSmartActions screenshotSmartActions, ScreenshotNotificationsController.Factory screenshotNotificationsControllerFactory, ScrollCaptureClient scrollCaptureClient, @@ -349,6 +354,7 @@ public class ScreenshotController { mAssistContentRequester = assistContentRequester; mViewProxy = viewProxyFactory.getProxy(mContext, mDisplayId); + mActionsProviderFactory = actionsProviderFactory; mScreenshotHandler.setOnTimeoutRunnable(() -> { if (DEBUG_UI) { @@ -393,6 +399,7 @@ public class ScreenshotController { void handleScreenshot(ScreenshotData screenshot, Consumer<Uri> finisher, RequestCallback requestCallback) { Assert.isMainThread(); + mCurrentRequestCallback = requestCallback; if (screenshot.getType() == WindowManager.TAKE_SCREENSHOT_FULLSCREEN) { Rect bounds = getFullScreenRect(); @@ -496,7 +503,7 @@ public class ScreenshotController { return mDisplayId == Display.DEFAULT_DISPLAY || mShowUIOnExternalDisplay; } - void prepareViewForNewScreenshot(ScreenshotData screenshot, String oldPackageName) { + void prepareViewForNewScreenshot(@NonNull ScreenshotData screenshot, String oldPackageName) { withWindowAttached(() -> { if (mUserManager.isManagedProfile(screenshot.getUserHandle().getIdentifier())) { mViewProxy.announceForAccessibility(mContext.getResources().getString( @@ -509,6 +516,11 @@ public class ScreenshotController { mViewProxy.reset(); + if (screenshotShelfUi()) { + mActionsProvider = mActionsProviderFactory.create(mContext, screenshot.getUserHandle(), + ((ScreenshotActionsProvider.ScreenshotActionsCallback) mViewProxy)); + } + if (mViewProxy.isAttachedToWindow()) { // if we didn't already dismiss for another reason if (!mViewProxy.isDismissing()) { @@ -983,20 +995,16 @@ public class ScreenshotController { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - doPostAnimation(imageData); + mViewProxy.setChipIntents(imageData); } }); } else { - doPostAnimation(imageData); + mViewProxy.setChipIntents(imageData); } }); } } - private void doPostAnimation(ScreenshotController.SavedImageData imageData) { - mViewProxy.setChipIntents(imageData); - } - /** * Sets up the action shade and its entrance animation, once we get the Quick Share action data. */ diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt index 9354fd27ce5a..88bca951beb6 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt @@ -20,8 +20,10 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.app.Notification import android.content.Context +import android.content.Intent import android.graphics.Bitmap import android.graphics.Rect +import android.net.Uri import android.view.KeyEvent import android.view.LayoutInflater import android.view.ScrollCaptureResponse @@ -37,6 +39,7 @@ import com.android.systemui.screenshot.LogConfig.DEBUG_ACTIONS import com.android.systemui.screenshot.LogConfig.DEBUG_DISMISS import com.android.systemui.screenshot.LogConfig.DEBUG_INPUT import com.android.systemui.screenshot.LogConfig.DEBUG_WINDOW +import com.android.systemui.screenshot.ScreenshotController.SavedImageData import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHER import com.android.systemui.screenshot.scroll.ScrollCaptureController import com.android.systemui.screenshot.ui.ScreenshotAnimationController @@ -54,10 +57,9 @@ class ScreenshotShelfViewProxy constructor( private val logger: UiEventLogger, private val viewModel: ScreenshotViewModel, - private val staticActionsProvider: ScreenshotActionsProvider, @Assisted private val context: Context, @Assisted private val displayId: Int -) : ScreenshotViewProxy { +) : ScreenshotViewProxy, ScreenshotActionsProvider.ScreenshotActionsCallback { override val view: ScreenshotShelfView = LayoutInflater.from(context).inflate(R.layout.screenshot_shelf, null) as ScreenshotShelfView override val screenshotPreview: View @@ -75,6 +77,8 @@ constructor( override var isPendingSharedTransition = false private val animationController = ScreenshotAnimationController(view) + private var imageData: SavedImageData? = null + private var runOnImageDataAcquired: ((SavedImageData) -> Unit)? = null init { ScreenshotShelfViewBinder.bind(view, viewModel, LayoutInflater.from(context)) @@ -87,8 +91,9 @@ constructor( override fun reset() { animationController.cancel() isPendingSharedTransition = false - viewModel.setScreenshotBitmap(null) - viewModel.setActions(listOf()) + imageData = null + viewModel.reset() + runOnImageDataAcquired = null } override fun updateInsets(insets: WindowInsets) {} override fun updateOrientation(insets: WindowInsets) {} @@ -99,18 +104,9 @@ constructor( override fun addQuickShareChip(quickShareAction: Notification.Action) {} - override fun setChipIntents(imageData: ScreenshotController.SavedImageData) { - val staticActions = - staticActionsProvider.getActions(context, imageData.owner).map { - ActionButtonViewModel(it.icon, it.text) { - val intent = it.retrieveIntent(imageData.uri) - debugLog(DEBUG_ACTIONS) { "Action tapped: $intent" } - isPendingSharedTransition = true - callbacks?.onAction(intent, imageData.owner, it.overrideTransition) - } - } - - viewModel.setActions(staticActions) + override fun setChipIntents(data: SavedImageData) { + imageData = data + runOnImageDataAcquired?.invoke(data) } override fun requestDismissal(event: ScreenshotEvent) { @@ -223,4 +219,41 @@ constructor( interface Factory : ScreenshotViewProxy.Factory { override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy } + + override fun setPreviewAction(overrideTransition: Boolean, retrieveIntent: (Uri) -> Intent) { + viewModel.setPreviewAction { + imageData?.let { + val intent = retrieveIntent(it.uri) + debugLog(DEBUG_ACTIONS) { "Preview tapped: $intent" } + isPendingSharedTransition = true + callbacks?.onAction(intent, it.owner, overrideTransition) + } + } + } + + override fun addActions(actions: List<ScreenshotActionsProvider.ScreenshotAction>) { + viewModel.addActions( + actions.map { action -> + ActionButtonViewModel(action.icon, action.text, action.description) { + val actionRunnable = + getActionRunnable(action.retrieveIntent, action.overrideTransition) + imageData?.let { actionRunnable(it) } + ?: run { runOnImageDataAcquired = actionRunnable } + } + } + ) + } + + private fun getActionRunnable( + retrieveIntent: (Uri) -> Intent, + overrideTransition: Boolean + ): (SavedImageData) -> Unit { + val onClick: (SavedImageData) -> Unit = { + val intent = retrieveIntent(it.uri) + debugLog(DEBUG_ACTIONS) { "Action tapped: $intent" } + isPendingSharedTransition = true + callbacks!!.onAction(intent, it.owner, overrideTransition) + } + return onClick + } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java index 9118ee1dfc73..2ce6d8380e36 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/dagger/ScreenshotModule.java @@ -94,8 +94,8 @@ public abstract class ScreenshotModule { ScreenshotSoundControllerImpl screenshotSoundProviderImpl); @Binds - abstract ScreenshotActionsProvider bindScreenshotActionsProvider( - DefaultScreenshotActionsProvider defaultScreenshotActionsProvider); + abstract ScreenshotActionsProvider.Factory bindScreenshotActionsProviderFactory( + DefaultScreenshotActionsProvider.Factory defaultScreenshotActionsProviderFactory); @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt index a5825b5f7797..c7fe3f608a2f 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt @@ -36,6 +36,7 @@ object ActionButtonViewBinder { } else { view.setOnClickListener(null) } + view.contentDescription = viewModel.description view.visibility = View.VISIBLE view.alpha = 1f } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt index 3bcd52cbc99e..d8782009e24b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt @@ -59,6 +59,11 @@ object ScreenshotShelfViewBinder { } } launch { + viewModel.previewAction.collect { onClick -> + previewView.setOnClickListener { onClick?.run() } + } + } + launch { viewModel.actions.collect { actions -> if (actions.isNotEmpty()) { view diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt index 6ee970534352..05bfed159527 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonViewModel.kt @@ -20,6 +20,7 @@ import android.graphics.drawable.Drawable data class ActionButtonViewModel( val icon: Drawable?, - val name: String?, + val name: CharSequence?, + val description: CharSequence, val onClicked: (() -> Unit)? ) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt index 3a652d90bb78..dc61d1e9c37b 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt @@ -24,6 +24,8 @@ import kotlinx.coroutines.flow.StateFlow class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager) { private val _preview = MutableStateFlow<Bitmap?>(null) val preview: StateFlow<Bitmap?> = _preview + private val _previewAction = MutableStateFlow<Runnable?>(null) + val previewAction: StateFlow<Runnable?> = _previewAction private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>()) val actions: StateFlow<List<ActionButtonViewModel>> = _actions val showDismissButton: Boolean @@ -33,7 +35,19 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager _preview.value = bitmap } - fun setActions(actions: List<ActionButtonViewModel>) { - _actions.value = actions + fun setPreviewAction(runnable: Runnable) { + _previewAction.value = runnable + } + + fun addActions(actions: List<ActionButtonViewModel>) { + val actionList = _actions.value.toMutableList() + actionList.addAll(actions) + _actions.value = actionList + } + + fun reset() { + _preview.value = null + _previewAction.value = null + _actions.value = listOf() } } |