Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81a9ac4d authored by Matt Casey's avatar Matt Casey
Browse files

Add action revealing to screenshot entrance animation.

The actions vertical entrance animation is a single animation, but
at a 200ms milestone during this animation, additional actions may be
(horizontally) revealed.

This change does two things:
1. Give each action a showDuringEntrance bool that indicates whether it
   should be included in the container from the very beginning.
2. 200ms into the actions entrance, add the remaining actions to the
   actions bar.

This puts some animation state into the viewmodel, which really should
be internal to the viewbinder, but we're not ready to move that due to
various flag/legacy constraints.

Bug: 329659738
Test: Manual inspection with slowed-down animations
Flag: ACONFIG com.android.sysui.screenshot_shelf_ui2 TRUNKFOOD
Change-Id: Ide4ee39117a5e80eaaa981a3ca10f40924c49ef9
parent 6610b194
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -87,7 +87,8 @@ constructor(
                AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_edit),
                context.resources.getString(R.string.screenshot_edit_label),
                context.resources.getString(R.string.screenshot_edit_description),
            )
            ),
            showDuringEntrance = true,
        ) {
            debugLog(LogConfig.DEBUG_ACTIONS) { "Edit tapped" }
            uiEventLogger.log(SCREENSHOT_EDIT_TAPPED, 0, request.packageNameString)
@@ -105,7 +106,8 @@ constructor(
                AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_share),
                context.resources.getString(R.string.screenshot_share_label),
                context.resources.getString(R.string.screenshot_share_description),
            )
            ),
            showDuringEntrance = true,
        ) {
            debugLog(LogConfig.DEBUG_ACTIONS) { "Share tapped" }
            uiEventLogger.log(SCREENSHOT_SHARE_TAPPED, 0, request.packageNameString)
@@ -125,7 +127,8 @@ constructor(
                AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_scroll),
                context.resources.getString(R.string.screenshot_scroll_label),
                context.resources.getString(R.string.screenshot_scroll_label),
            )
            ),
            showDuringEntrance = true,
        ) {
            onClick.run()
        }
+10 −2
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.systemui.screenshot.scroll.ScrollCaptureController
import com.android.systemui.screenshot.ui.ScreenshotAnimationController
import com.android.systemui.screenshot.ui.ScreenshotShelfView
import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder
import com.android.systemui.screenshot.ui.viewmodel.AnimationState
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
@@ -119,12 +120,19 @@ constructor(
    override fun updateOrientation(insets: WindowInsets) {}

    override fun createScreenshotDropInAnimation(screenRect: Rect, showFlash: Boolean): Animator {
        val entrance = animationController.getEntranceAnimation(screenRect, showFlash)
        entrance.doOnStart { thumbnailObserver.onEntranceStarted() }
        val entrance =
            animationController.getEntranceAnimation(screenRect, showFlash) {
                viewModel.setAnimationState(AnimationState.ENTRANCE_REVEAL)
            }
        entrance.doOnStart {
            thumbnailObserver.onEntranceStarted()
            viewModel.setAnimationState(AnimationState.ENTRANCE_STARTED)
        }
        entrance.doOnEnd {
            // reset the timeout when animation finishes
            callbacks?.onUserInteraction()
            thumbnailObserver.onEntranceComplete()
            viewModel.setAnimationState(AnimationState.ENTRANCE_COMPLETE)
        }
        return entrance
    }
+19 −2
Original line number Diff line number Diff line
@@ -47,7 +47,11 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
            view.requireViewById(R.id.screenshot_dismiss_button)
        )

    fun getEntranceAnimation(bounds: Rect, showFlash: Boolean): Animator {
    fun getEntranceAnimation(
        bounds: Rect,
        showFlash: Boolean,
        onRevealMilestone: () -> Unit
    ): Animator {
        val entranceAnimation = AnimatorSet()

        val previewAnimator = getPreviewAnimator(bounds)
@@ -70,7 +74,19 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
            entranceAnimation.doOnStart { screenshotPreview.visibility = View.INVISIBLE }
        }

        entranceAnimation.play(getActionsAnimator()).with(previewAnimator)
        val actionsAnimator = getActionsAnimator()
        entranceAnimation.play(actionsAnimator).with(previewAnimator)

        // This isn't actually animating anything but is basically a timer for the first 200ms of
        // the entrance animation. Using an animator here ensures that this is scaled if we change
        // animator duration scales.
        val revealMilestoneAnimator =
            ValueAnimator.ofFloat(0f).apply {
                duration = 0
                startDelay = ACTION_REVEAL_DELAY_MS
                doOnEnd { onRevealMilestone() }
            }
        entranceAnimation.play(revealMilestoneAnimator).with(actionsAnimator)

        val fadeInAnimator = ValueAnimator.ofFloat(0f, 1f)
        fadeInAnimator.addUpdateListener {
@@ -198,5 +214,6 @@ class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
        private const val FLASH_OUT_DURATION_MS: Long = 217
        private const val PREVIEW_X_ANIMATION_DURATION_MS: Long = 234
        private const val PREVIEW_Y_ANIMATION_DURATION_MS: Long = 500
        private const val ACTION_REVEAL_DELAY_MS: Long = 200
    }
}
+64 −38
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import com.android.systemui.res.R
import com.android.systemui.screenshot.ScreenshotEvent
import com.android.systemui.screenshot.ui.ScreenshotShelfView
import com.android.systemui.screenshot.ui.SwipeGestureListener
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
import com.android.systemui.screenshot.ui.viewmodel.AnimationState
import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import com.android.systemui.util.children
import kotlinx.coroutines.Dispatchers
@@ -59,7 +61,6 @@ object ScreenshotShelfViewBinder {
        val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border)
        previewView.clipToOutline = true
        previewViewBlur.clipToOutline = true
        val actionsContainer: LinearLayout = view.requireViewById(R.id.screenshot_actions)
        val dismissButton = view.requireViewById<View>(R.id.screenshot_dismiss_button)
        dismissButton.visibility = if (viewModel.showDismissButton) View.VISIBLE else View.GONE
        dismissButton.setOnClickListener {
@@ -90,12 +91,46 @@ object ScreenshotShelfViewBinder {
                    }
                    launch {
                        viewModel.actions.collect { actions ->
                            val visibleActions = actions.filter { it.visible }
                            updateActions(
                                actions,
                                viewModel.animationState.value,
                                view,
                                layoutInflater
                            )
                        }
                    }
                    launch {
                        viewModel.animationState.collect { animationState ->
                            updateActions(
                                viewModel.actions.value,
                                animationState,
                                view,
                                layoutInflater
                            )
                        }
                    }
                }
            }
        }
    }

    private fun updateActions(
        actions: List<ActionButtonViewModel>,
        animationState: AnimationState,
        view: ScreenshotShelfView,
        layoutInflater: LayoutInflater
    ) {
        val actionsContainer: LinearLayout = view.requireViewById(R.id.screenshot_actions)
        val visibleActions =
            actions.filter {
                it.visible &&
                    (animationState == AnimationState.ENTRANCE_COMPLETE ||
                        animationState == AnimationState.ENTRANCE_REVEAL ||
                        it.showDuringEntrance)
            }

        if (visibleActions.isNotEmpty()) {
                                view
                                    .requireViewById<View>(R.id.actions_container_background)
                                    .visibility = View.VISIBLE
            view.requireViewById<View>(R.id.actions_container_background).visibility = View.VISIBLE
        }

        // Remove any buttons not in the new list, then do another pass to add
@@ -119,21 +154,12 @@ object ScreenshotShelfViewBinder {
                // Different ID. Removals have already happened so this must
                // mean that the new action must be inserted here.
                val actionButton =
                                        layoutInflater.inflate(
                                            R.layout.shelf_action_chip,
                                            actionsContainer,
                                            false
                                        )
                    layoutInflater.inflate(R.layout.shelf_action_chip, actionsContainer, false)
                actionsContainer.addView(actionButton, index)
                ActionButtonViewBinder.bind(actionButton, action)
            }
        }
    }
                    }
                }
            }
        }
    }

    private fun setScreenshotBitmap(screenshotPreview: ImageView, bitmap: Bitmap) {
        screenshotPreview.setImageBitmap(bitmap)
+9 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ data class ActionButtonViewModel(
    val appearance: ActionButtonAppearance,
    val id: Int,
    val visible: Boolean,
    val showDuringEntrance: Boolean,
    val onClicked: (() -> Unit)?,
) {
    companion object {
@@ -29,7 +30,14 @@ data class ActionButtonViewModel(

        fun withNextId(
            appearance: ActionButtonAppearance,
            showDuringEntrance: Boolean,
            onClicked: (() -> Unit)?
        ): ActionButtonViewModel = ActionButtonViewModel(appearance, getId(), true, onClicked)
        ): ActionButtonViewModel =
            ActionButtonViewModel(appearance, getId(), true, showDuringEntrance, onClicked)

        fun withNextId(
            appearance: ActionButtonAppearance,
            onClicked: (() -> Unit)?
        ): ActionButtonViewModel = withNextId(appearance, showDuringEntrance = true, onClicked)
    }
}
Loading