Switch to callback version of ScreenshotActionsProvider

Bug: 329659738
Test: manual
Flag: ACONFIG com.android.systemui.screenshot_shelf_ui DEVELOPMENT

Change-Id: I19a098248c8be5c6b768a8a2e9709ad87f131e62
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
index abdbd68..97acccd 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 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>
-}
-
-class DefaultScreenshotActionsProvider @Inject constructor() : ScreenshotActionsProvider {
-    override fun getPreviewAction(context: Context, uri: Uri, user: UserHandle): Intent {
-        return ActionIntentCreator.createEdit(uri, context)
+    interface ScreenshotActionsCallback {
+        fun setPreviewAction(overrideTransition: Boolean = false, retrieveIntent: (Uri) -> Intent)
+        fun addAction(action: ScreenshotAction) = addActions(listOf(action))
+        fun addActions(actions: List<ScreenshotAction>)
     }
 
-    override fun getActions(
-        context: Context,
-        user: UserHandle
-    ): List<ScreenshotActionsProvider.ScreenshotAction> {
+    interface Factory {
+        fun create(
+            context: Context,
+            user: UserHandle?,
+            callback: ScreenshotActionsCallback
+        ): ScreenshotActionsProvider
+    }
+}
+
+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 @@
             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 c8e13bb..b796a20 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 @@
 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 @@
     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 @@
     private boolean mScreenshotTakenInPortrait;
     private boolean mBlockAttach;
 
+    private ScreenshotActionsProvider mActionsProvider;
+
     private Animator mScreenshotAnimation;
     private RequestCallback mCurrentRequestCallback;
     private String mPackageName = "";
@@ -298,6 +302,7 @@
             Context context,
             FeatureFlags flags,
             ScreenshotViewProxy.Factory viewProxyFactory,
+            ScreenshotActionsProvider.Factory actionsProviderFactory,
             ScreenshotSmartActions screenshotSmartActions,
             ScreenshotNotificationsController.Factory screenshotNotificationsControllerFactory,
             ScrollCaptureClient scrollCaptureClient,
@@ -349,6 +354,7 @@
         mAssistContentRequester = assistContentRequester;
 
         mViewProxy = viewProxyFactory.getProxy(mContext, mDisplayId);
+        mActionsProviderFactory = actionsProviderFactory;
 
         mScreenshotHandler.setOnTimeoutRunnable(() -> {
             if (DEBUG_UI) {
@@ -393,6 +399,7 @@
     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 @@
         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 @@
 
         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 @@
                         @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 9354fd2..88bca95 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.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_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 @@
 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 @@
     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 @@
     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 @@
 
     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 @@
     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 9118ee1..2ce6d83 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 @@
             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 a5825b5..c7fe3f6 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 @@
         } 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 3bcd52c..d878200 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 @@
                         }
                     }
                     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 6ee9705..05bfed1 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 @@
 
 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 3a652d9..dc61d1e 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 @@
 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 @@
         _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()
     }
 }