Merge "Fix shared transitions in screenshot shelf UI" into 24D1-dev
diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml
index 2cb4b02..49d3a8e 100644
--- a/packages/SystemUI/res/layout/screenshot_shelf.xml
+++ b/packages/SystemUI/res/layout/screenshot_shelf.xml
@@ -135,11 +135,12 @@
android:id="@+id/screenshot_scrollable_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:clipToOutline="true"
android:scaleType="matrix"
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/screenshot_preview"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
- android:elevation="7dp"/>
+ android:elevation="3dp"/>
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
@@ -170,6 +171,13 @@
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<ImageView
+ android:id="@+id/screenshot_scrolling_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"
+ android:clickable="true"
+ android:importantForAccessibility="no"/>
+ <ImageView
android:id="@+id/screenshot_flash"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
index caa67df..1868b4a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionExecutor.kt
@@ -25,7 +25,6 @@
import android.os.UserHandle
import android.util.Log
import android.util.Pair
-import android.view.View
import android.view.Window
import com.android.app.tracing.coroutines.launch
import com.android.internal.app.ChooserActivity
@@ -41,8 +40,8 @@
private val intentExecutor: ActionIntentExecutor,
@Application private val applicationScope: CoroutineScope,
@Assisted val window: Window,
- @Assisted val transitionView: View,
- @Assisted val onDismiss: (() -> Unit)
+ @Assisted val viewProxy: ScreenshotViewProxy,
+ @Assisted val finishDismiss: () -> Unit,
) {
var isPendingSharedTransition = false
@@ -50,6 +49,7 @@
fun startSharedTransition(intent: Intent, user: UserHandle, overrideTransition: Boolean) {
isPendingSharedTransition = true
+ viewProxy.fadeForSharedTransition()
val windowTransition = createWindowTransition()
applicationScope.launch("$TAG#launchIntentAsync") {
intentExecutor.launchIntent(
@@ -70,7 +70,7 @@
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
pendingIntent.send(options.toBundle())
- onDismiss.invoke()
+ viewProxy.requestDismissal(null)
} catch (e: PendingIntent.CanceledException) {
Log.e(TAG, "Intent cancelled", e)
}
@@ -89,7 +89,7 @@
override fun hideSharedElements() {
isPendingSharedTransition = false
- onDismiss.invoke()
+ finishDismiss.invoke()
}
override fun onFinish() {}
@@ -98,13 +98,20 @@
window,
callbacks,
null,
- Pair.create(transitionView, ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME)
+ Pair.create(
+ viewProxy.screenshotPreview,
+ ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME
+ )
)
}
@AssistedFactory
interface Factory {
- fun create(window: Window, transitionView: View, onDismiss: (() -> Unit)): ActionExecutor
+ fun create(
+ window: Window,
+ viewProxy: ScreenshotViewProxy,
+ finishDismiss: (() -> Unit)
+ ): ActionExecutor
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index a0cef52..15638d3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -97,6 +97,7 @@
.putExtra(LongScreenshotActivity.EXTRA_SCREENSHOT_USER_HANDLE, owner)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
}
private const val EXTRA_EDIT_SOURCE = "edit_source"
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
index 4cf18fb..3d024a6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LegacyScreenshotViewProxy.kt
@@ -157,6 +157,8 @@
override fun restoreNonScrollingUi() = view.restoreNonScrollingUi()
+ override fun fadeForSharedTransition() {} // unused
+
override fun stopInputListening() = view.stopInputListening()
override fun requestFocus() {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 71363b2..b949741 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -317,9 +317,9 @@
mConfigChanges.applyNewConfig(context.getResources());
reloadAssets();
- mActionExecutor = actionExecutorFactory.create(mWindow, mViewProxy.getScreenshotPreview(),
+ mActionExecutor = actionExecutorFactory.create(mWindow, mViewProxy,
() -> {
- requestDismissal(null);
+ finishDismiss();
return Unit.INSTANCE;
});
@@ -623,9 +623,11 @@
(response) -> {
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_LONG_SCREENSHOT_IMPRESSION,
0, response.getPackageName());
- if (screenshotShelfUi2() && mActionsProvider != null) {
- mActionsProvider.onScrollChipReady(
- () -> onScrollButtonClicked(owner, response));
+ if (screenshotShelfUi2()) {
+ if (mActionsProvider != null) {
+ mActionsProvider.onScrollChipReady(
+ () -> onScrollButtonClicked(owner, response));
+ }
} else {
mViewProxy.showScrollChip(response.getPackageName(),
() -> onScrollButtonClicked(owner, response));
@@ -657,9 +659,7 @@
() -> {
final Intent intent = ActionIntentCreator.INSTANCE.createLongScreenshotIntent(
owner, mContext);
- mActionIntentExecutor.launchIntentAsync(intent, owner, true,
- ActivityOptions.makeCustomAnimation(mContext, 0, 0), null);
-
+ mActionIntentExecutor.launchIntentAsync(intent, owner, true, null, null);
},
mViewProxy::restoreNonScrollingUi,
mViewProxy::startLongScreenshotTransition);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
index 846884f..3ac070a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt
@@ -90,15 +90,15 @@
override var isDismissing = false
override var isPendingSharedTransition = false
- private val animationController = ScreenshotAnimationController(view)
+ private val animationController = ScreenshotAnimationController(view, viewModel)
init {
shelfViewBinder.bind(
view,
viewModel,
+ animationController,
LayoutInflater.from(context),
onDismissalRequested = { event, velocity -> requestDismissal(event, velocity) },
- onDismissalCancelled = { animationController.getSwipeReturnAnimation().start() },
onUserInteraction = { callbacks?.onUserInteraction() }
)
view.updateInsets(windowManager.currentWindowMetrics.windowInsets)
@@ -188,24 +188,53 @@
override fun prepareScrollingTransition(
response: ScrollCaptureResponse,
- screenBitmap: Bitmap,
+ screenBitmap: Bitmap, // unused
newScreenshot: Bitmap,
screenshotTakenInPortrait: Boolean,
onTransitionPrepared: Runnable,
) {
- onTransitionPrepared.run()
+ viewModel.setScrollingScrimBitmap(newScreenshot)
+ viewModel.setScrollableRect(scrollableAreaOnScreen(response))
+ animationController.fadeForLongScreenshotTransition()
+ view.post { onTransitionPrepared.run() }
+ }
+
+ private fun scrollableAreaOnScreen(response: ScrollCaptureResponse): Rect {
+ val r = Rect(response.boundsInWindow)
+ val windowInScreen = response.windowBounds
+ r.offset(windowInScreen?.left ?: 0, windowInScreen?.top ?: 0)
+ r.intersect(
+ Rect(
+ 0,
+ 0,
+ context.resources.displayMetrics.widthPixels,
+ context.resources.displayMetrics.heightPixels
+ )
+ )
+ return r
}
override fun startLongScreenshotTransition(
transitionDestination: Rect,
onTransitionEnd: Runnable,
- longScreenshot: ScrollCaptureController.LongScreenshot
+ longScreenshot: ScrollCaptureController.LongScreenshot,
) {
- onTransitionEnd.run()
- callbacks?.onDismiss()
+ val transitionAnimation =
+ animationController.runLongScreenshotTransition(
+ transitionDestination,
+ longScreenshot,
+ onTransitionEnd
+ )
+ transitionAnimation.doOnEnd { callbacks?.onDismiss() }
+ transitionAnimation.start()
}
- override fun restoreNonScrollingUi() {}
+ override fun restoreNonScrollingUi() {
+ viewModel.setScrollableRect(null)
+ viewModel.setScrollingScrimBitmap(null)
+ animationController.restoreUI()
+ callbacks?.onUserInteraction() // reset the timeout
+ }
override fun stopInputListening() {}
@@ -228,6 +257,10 @@
)
}
+ override fun fadeForSharedTransition() {
+ animationController.fadeForSharedTransition()
+ }
+
private fun addPredictiveBackListener(onDismissRequested: (ScreenshotEvent) -> Unit) {
val onBackInvokedCallback = OnBackInvokedCallback {
debugLog(DEBUG_INPUT) { "Predictive Back callback dispatched" }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
index a4069d1..df93a5e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotViewProxy.kt
@@ -63,6 +63,7 @@
longScreenshot: ScrollCaptureController.LongScreenshot
)
fun restoreNonScrollingUi()
+ fun fadeForSharedTransition()
fun stopInputListening()
fun requestFocus()
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
index 06e88f4..a4906c1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt
@@ -20,6 +20,10 @@
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
+import android.content.res.ColorStateList
+import android.graphics.BlendMode
+import android.graphics.Color
+import android.graphics.Matrix
import android.graphics.PointF
import android.graphics.Rect
import android.util.MathUtils
@@ -29,13 +33,21 @@
import androidx.core.animation.doOnEnd
import androidx.core.animation.doOnStart
import com.android.systemui.res.R
+import com.android.systemui.screenshot.scroll.ScrollCaptureController
+import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.sign
-class ScreenshotAnimationController(private val view: ScreenshotShelfView) {
+class ScreenshotAnimationController(
+ private val view: ScreenshotShelfView,
+ private val viewModel: ScreenshotViewModel
+) {
private var animator: Animator? = null
private val screenshotPreview = view.requireViewById<ImageView>(R.id.screenshot_preview)
+ private val scrollingScrim = view.requireViewById<ImageView>((R.id.screenshot_scrolling_scrim))
+ private val scrollTransitionPreview =
+ view.requireViewById<ImageView>(R.id.screenshot_scrollable_preview)
private val flashView = view.requireViewById<View>(R.id.screenshot_flash)
private val actionContainer = view.requireViewById<View>(R.id.actions_container_background)
private val fastOutSlowIn =
@@ -46,6 +58,14 @@
view.requireViewById(R.id.screenshot_badge),
view.requireViewById(R.id.screenshot_dismiss_button)
)
+ private val fadeUI =
+ listOf<View>(
+ view.requireViewById(R.id.screenshot_preview_border),
+ view.requireViewById(R.id.actions_container_background),
+ view.requireViewById(R.id.screenshot_badge),
+ view.requireViewById(R.id.screenshot_dismiss_button),
+ view.requireViewById(R.id.screenshot_message_container),
+ )
fun getEntranceAnimation(
bounds: Rect,
@@ -96,15 +116,108 @@
}
entranceAnimation.play(fadeInAnimator).after(previewAnimator)
entranceAnimation.doOnStart {
+ viewModel.setIsAnimating(true)
for (child in staticUI) {
child.alpha = 0f
}
}
+ entranceAnimation.doOnEnd { viewModel.setIsAnimating(false) }
this.animator = entranceAnimation
return entranceAnimation
}
+ fun fadeForSharedTransition() {
+ animator?.cancel()
+ val fadeAnimator = ValueAnimator.ofFloat(1f, 0f)
+ fadeAnimator.addUpdateListener {
+ for (view in fadeUI) {
+ view.alpha = it.animatedValue as Float
+ }
+ }
+ animator = fadeAnimator
+ fadeAnimator.start()
+ }
+
+ fun runLongScreenshotTransition(
+ destRect: Rect,
+ longScreenshot: ScrollCaptureController.LongScreenshot,
+ onTransitionEnd: Runnable
+ ): Animator {
+ val animSet = AnimatorSet()
+
+ val scrimAnim = ValueAnimator.ofFloat(0f, 1f)
+ scrimAnim.addUpdateListener { animation: ValueAnimator ->
+ scrollingScrim.setAlpha(1 - animation.animatedFraction)
+ }
+ scrollTransitionPreview.visibility = View.VISIBLE
+ if (true) {
+ scrollTransitionPreview.setImageBitmap(longScreenshot.toBitmap())
+ val startX: Float = scrollTransitionPreview.x
+ val startY: Float = scrollTransitionPreview.y
+ val locInScreen: IntArray = scrollTransitionPreview.getLocationOnScreen()
+ destRect.offset(startX.toInt() - locInScreen[0], startY.toInt() - locInScreen[1])
+ scrollTransitionPreview.pivotX = 0f
+ scrollTransitionPreview.pivotY = 0f
+ scrollTransitionPreview.setAlpha(1f)
+ val currentScale: Float = scrollTransitionPreview.width / longScreenshot.width.toFloat()
+ val matrix = Matrix()
+ matrix.setScale(currentScale, currentScale)
+ matrix.postTranslate(
+ longScreenshot.left * currentScale,
+ longScreenshot.top * currentScale
+ )
+ scrollTransitionPreview.setImageMatrix(matrix)
+ val destinationScale: Float = destRect.width() / scrollTransitionPreview.width.toFloat()
+ val previewAnim = ValueAnimator.ofFloat(0f, 1f)
+ previewAnim.addUpdateListener { animation: ValueAnimator ->
+ val t = animation.animatedFraction
+ val currScale = MathUtils.lerp(1f, destinationScale, t)
+ scrollTransitionPreview.scaleX = currScale
+ scrollTransitionPreview.scaleY = currScale
+ scrollTransitionPreview.x = MathUtils.lerp(startX, destRect.left.toFloat(), t)
+ scrollTransitionPreview.y = MathUtils.lerp(startY, destRect.top.toFloat(), t)
+ }
+ val previewFadeAnim = ValueAnimator.ofFloat(1f, 0f)
+ previewFadeAnim.addUpdateListener { animation: ValueAnimator ->
+ scrollTransitionPreview.setAlpha(1 - animation.animatedFraction)
+ }
+ previewAnim.doOnEnd { onTransitionEnd.run() }
+ animSet.play(previewAnim).with(scrimAnim).before(previewFadeAnim)
+ } else {
+ // if we switched orientations between the original screenshot and the long screenshot
+ // capture, just fade out the scrim instead of running the preview animation
+ scrimAnim.doOnEnd { onTransitionEnd.run() }
+ animSet.play(scrimAnim)
+ }
+ animator = animSet
+ return animSet
+ }
+
+ fun fadeForLongScreenshotTransition() {
+ scrollingScrim.imageTintBlendMode = BlendMode.SRC_ATOP
+ val anim = ValueAnimator.ofFloat(0f, .3f)
+ anim.addUpdateListener {
+ scrollingScrim.setImageTintList(
+ ColorStateList.valueOf(Color.argb(it.animatedValue as Float, 0f, 0f, 0f))
+ )
+ }
+ for (view in fadeUI) {
+ view.alpha = 0f
+ }
+ screenshotPreview.alpha = 0f
+ anim.setDuration(200)
+ anim.start()
+ }
+
+ fun restoreUI() {
+ animator?.cancel()
+ for (view in fadeUI) {
+ view.alpha = 1f
+ }
+ screenshotPreview.alpha = 1f
+ }
+
fun getSwipeReturnAnimation(): Animator {
animator?.cancel()
val animator = ValueAnimator.ofFloat(view.translationX, 0f)
@@ -114,6 +227,7 @@
}
fun getSwipeDismissAnimation(requestedVelocity: Float?): Animator {
+ animator?.cancel()
val velocity = getAdjustedVelocity(requestedVelocity)
val screenWidth = view.resources.displayMetrics.widthPixels
// translation at which point the visible UI is fully off the screen (in the direction
@@ -131,6 +245,8 @@
view.alpha = 1f - it.animatedFraction
}
animator.duration = ((abs(distance / velocity))).toLong()
+ animator.doOnStart { viewModel.setIsAnimating(true) }
+ animator.doOnEnd { viewModel.setIsAnimating(false) }
this.animator = animator
return animator
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 c7bc50cb..442b387 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
@@ -16,7 +16,11 @@
package com.android.systemui.screenshot.ui.binder
+import android.content.res.Configuration
import android.graphics.Bitmap
+import android.graphics.Matrix
+import android.graphics.Rect
+import android.util.LayoutDirection
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -29,6 +33,7 @@
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
import com.android.systemui.screenshot.ScreenshotEvent
+import com.android.systemui.screenshot.ui.ScreenshotAnimationController
import com.android.systemui.screenshot.ui.ScreenshotShelfView
import com.android.systemui.screenshot.ui.SwipeGestureListener
import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel
@@ -45,9 +50,9 @@
fun bind(
view: ScreenshotShelfView,
viewModel: ScreenshotViewModel,
+ animationController: ScreenshotAnimationController,
layoutInflater: LayoutInflater,
onDismissalRequested: (event: ScreenshotEvent, velocity: Float?) -> Unit,
- onDismissalCancelled: () -> Unit,
onUserInteraction: () -> Unit
) {
val swipeGestureListener =
@@ -56,7 +61,7 @@
onDismiss = {
onDismissalRequested(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, it)
},
- onCancel = onDismissalCancelled
+ onCancel = { animationController.getSwipeReturnAnimation().start() }
)
view.onTouchInterceptListener = { swipeGestureListener.onMotionEvent(it) }
view.userInteractionCallback = onUserInteraction
@@ -66,11 +71,14 @@
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 {
onDismissalRequested(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL, null)
}
+ val scrollingScrim: ImageView = view.requireViewById(R.id.screenshot_scrolling_scrim)
+ val scrollablePreview: ImageView = view.requireViewById(R.id.screenshot_scrollable_preview)
val badgeView = view.requireViewById<ImageView>(R.id.screenshot_badge)
// use immediate dispatcher to ensure screenshot bitmap is set before animation
@@ -91,6 +99,29 @@
}
}
launch {
+ viewModel.scrollingScrim.collect { bitmap ->
+ if (bitmap != null) {
+ scrollingScrim.setImageBitmap(bitmap)
+ scrollingScrim.visibility = View.VISIBLE
+ } else {
+ scrollingScrim.visibility = View.GONE
+ }
+ }
+ }
+ launch {
+ viewModel.scrollableRect.collect { rect ->
+ if (rect != null) {
+ setScrollablePreview(
+ scrollablePreview,
+ viewModel.preview.value,
+ rect
+ )
+ } else {
+ scrollablePreview.visibility = View.GONE
+ }
+ }
+ }
+ launch {
viewModel.badge.collect { badge ->
badgeView.setImageDrawable(badge)
badgeView.visibility = if (badge != null) View.VISIBLE else View.GONE
@@ -102,6 +133,14 @@
}
}
launch {
+ viewModel.isAnimating.collect { isAnimating ->
+ previewView.isClickable = !isAnimating
+ for (child in actionsContainer.children) {
+ child.isClickable = !isAnimating
+ }
+ }
+ }
+ launch {
viewModel.actions.collect { actions ->
updateActions(
actions,
@@ -191,4 +230,35 @@
screenshotPreview.layoutParams = params
screenshotPreview.requestLayout()
}
+
+ private fun setScrollablePreview(
+ scrollablePreview: ImageView,
+ bitmap: Bitmap?,
+ scrollableRect: Rect
+ ) {
+ if (bitmap == null) {
+ return
+ }
+ val fixedSize = scrollablePreview.resources.getDimensionPixelSize(R.dimen.overlay_x_scale)
+ val inPortrait =
+ scrollablePreview.resources.configuration.orientation ==
+ Configuration.ORIENTATION_PORTRAIT
+ val scale: Float = fixedSize / ((if (inPortrait) bitmap.width else bitmap.height).toFloat())
+ val params = scrollablePreview.layoutParams
+
+ params.width = (scale * scrollableRect.width()).toInt()
+ params.height = (scale * scrollableRect.height()).toInt()
+ val matrix = Matrix()
+ matrix.setScale(scale, scale)
+ matrix.postTranslate(-scrollableRect.left * scale, -scrollableRect.top * scale)
+
+ scrollablePreview.translationX =
+ (scale *
+ if (scrollablePreview.layoutDirection == LayoutDirection.LTR) scrollableRect.left
+ else scrollableRect.right - (scrollablePreview.parent as View).width)
+ scrollablePreview.translationY = scale * scrollableRect.top
+ scrollablePreview.setImageMatrix(matrix)
+ scrollablePreview.setImageBitmap(bitmap)
+ scrollablePreview.setVisibility(View.VISIBLE)
+ }
}
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 81bc281..3f99bc4 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
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot.ui.viewmodel
import android.graphics.Bitmap
+import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.util.Log
import android.view.accessibility.AccessibilityManager
@@ -26,6 +27,8 @@
class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager) {
private val _preview = MutableStateFlow<Bitmap?>(null)
val preview: StateFlow<Bitmap?> = _preview
+ private val _scrollingScrim = MutableStateFlow<Bitmap?>(null)
+ val scrollingScrim: StateFlow<Bitmap?> = _scrollingScrim
private val _badge = MutableStateFlow<Drawable?>(null)
val badge: StateFlow<Drawable?> = _badge
private val _previewAction = MutableStateFlow<(() -> Unit)?>(null)
@@ -35,6 +38,10 @@
private val _animationState = MutableStateFlow(AnimationState.NOT_STARTED)
val animationState: StateFlow<AnimationState> = _animationState
+ private val _isAnimating = MutableStateFlow(false)
+ val isAnimating: StateFlow<Boolean> = _isAnimating
+ private val _scrollableRect = MutableStateFlow<Rect?>(null)
+ val scrollableRect: StateFlow<Rect?> = _scrollableRect
val showDismissButton: Boolean
get() = accessibilityManager.isEnabled
@@ -42,6 +49,10 @@
_preview.value = bitmap
}
+ fun setScrollingScrimBitmap(bitmap: Bitmap?) {
+ _scrollingScrim.value = bitmap
+ }
+
fun setScreenshotBadge(badge: Drawable?) {
_badge.value = badge
}
@@ -114,12 +125,23 @@
_animationState.value = state
}
+ fun setIsAnimating(isAnimating: Boolean) {
+ _isAnimating.value = isAnimating
+ }
+
+ fun setScrollableRect(rect: Rect?) {
+ _scrollableRect.value = rect
+ }
+
fun reset() {
_preview.value = null
+ _scrollingScrim.value = null
_badge.value = null
_previewAction.value = null
_actions.value = listOf()
_animationState.value = AnimationState.NOT_STARTED
+ _isAnimating.value = false
+ _scrollableRect.value = null
}
companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
index 91f3912..53b6cc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionExecutorTest.kt
@@ -21,7 +21,6 @@
import android.os.Bundle
import android.os.UserHandle
import android.testing.AndroidTestingRunner
-import android.view.View
import android.view.Window
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -50,7 +49,7 @@
private val intentExecutor = mock<ActionIntentExecutor>()
private val window = mock<Window>()
- private val view = mock<View>()
+ private val viewProxy = mock<ScreenshotShelfViewProxy>()
private val onDismiss = mock<(() -> Unit)>()
private val pendingIntent = mock<PendingIntent>()
@@ -72,16 +71,16 @@
}
@Test
- fun sendPendingIntent_dismisses() = runTest {
+ fun sendPendingIntent_requestsDismissal() = runTest {
actionExecutor = createActionExecutor()
actionExecutor.sendPendingIntent(pendingIntent)
verify(pendingIntent).send(any(Bundle::class.java))
- verify(onDismiss).invoke()
+ verify(viewProxy).requestDismissal(null)
}
private fun createActionExecutor(): ActionExecutor {
- return ActionExecutor(intentExecutor, testScope, window, view, onDismiss)
+ return ActionExecutor(intentExecutor, testScope, window, viewProxy, onDismiss)
}
}