Loading packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt +21 −2 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,7 @@ import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHE import com.android.systemui.screenshot.scroll.ScrollCaptureController import com.android.systemui.screenshot.scroll.ScrollCaptureController import com.android.systemui.screenshot.ui.ScreenshotAnimationController import com.android.systemui.screenshot.ui.ScreenshotAnimationController import com.android.systemui.screenshot.ui.ScreenshotShelfView import com.android.systemui.screenshot.ui.ScreenshotShelfView import com.android.systemui.screenshot.ui.SwipeGestureListener import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import dagger.assisted.Assisted import dagger.assisted.Assisted Loading Loading @@ -75,9 +76,17 @@ constructor( override var isPendingSharedTransition = false override var isPendingSharedTransition = false private val animationController = ScreenshotAnimationController(view) private val animationController = ScreenshotAnimationController(view) private val swipeGestureListener = SwipeGestureListener( view, onDismiss = { requestDismissal(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, it) }, onCancel = { animationController.getSwipeReturnAnimation().start() } ) init { init { ScreenshotShelfViewBinder.bind(view, viewModel, LayoutInflater.from(context)) ScreenshotShelfViewBinder.bind(view, viewModel, LayoutInflater.from(context)) { swipeGestureListener.onMotionEvent(it) } addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } debugLog(DEBUG_WINDOW) { "adding OnComputeInternalInsetsListener" } debugLog(DEBUG_WINDOW) { "adding OnComputeInternalInsetsListener" } Loading Loading @@ -111,6 +120,10 @@ constructor( override fun setChipIntents(imageData: SavedImageData) {} override fun setChipIntents(imageData: SavedImageData) {} override fun requestDismissal(event: ScreenshotEvent?) { override fun requestDismissal(event: ScreenshotEvent?) { requestDismissal(event, getDismissalVelocity()) } private fun requestDismissal(event: ScreenshotEvent?, velocity: Float) { debugLog(DEBUG_DISMISS) { "screenshot dismissal requested: $event" } debugLog(DEBUG_DISMISS) { "screenshot dismissal requested: $event" } // If we're already animating out, don't restart the animation // If we're already animating out, don't restart the animation Loading @@ -119,7 +132,7 @@ constructor( return return } } event?.let { logger.log(it, 0, packageName) } event?.let { logger.log(it, 0, packageName) } val animator = animationController.getExitAnimation() val animator = animationController.getSwipeDismissAnimation(velocity) animator.addListener( animator.addListener( object : AnimatorListenerAdapter() { object : AnimatorListenerAdapter() { override fun onAnimationStart(animator: Animator) { override fun onAnimationStart(animator: Animator) { Loading Loading @@ -222,6 +235,12 @@ constructor( ) ) } } private fun getDismissalVelocity(): Float { val isLTR = view.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR // dismiss to the left in LTR locales, to the right in RTL return if (isLTR) -1.5f else 1.5f } @AssistedFactory @AssistedFactory interface Factory : ScreenshotViewProxy.Factory { interface Factory : ScreenshotViewProxy.Factory { override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy Loading packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt +29 −13 Original line number Original line Diff line number Diff line Loading @@ -20,9 +20,12 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.animation.ValueAnimator import android.view.View import android.view.View import com.android.systemui.res.R import kotlin.math.abs class ScreenshotAnimationController(private val view: View) { class ScreenshotAnimationController(private val view: ScreenshotShelfView) { private var animator: Animator? = null private var animator: Animator? = null private val actionContainer = view.requireViewById<View>(R.id.actions_container_background) fun getEntranceAnimation(): Animator { fun getEntranceAnimation(): Animator { val animator = ValueAnimator.ofFloat(0f, 1f) val animator = ValueAnimator.ofFloat(0f, 1f) Loading @@ -41,19 +44,32 @@ class ScreenshotAnimationController(private val view: View) { return animator return animator } } fun getExitAnimation(): Animator { fun getSwipeReturnAnimation(): Animator { val animator = ValueAnimator.ofFloat(1f, 0f) animator?.cancel() animator.addUpdateListener { view.alpha = it.animatedValue as Float } val animator = ValueAnimator.ofFloat(view.translationX, 0f) animator.addListener( animator.addUpdateListener { view.translationX = it.animatedValue as Float } object : AnimatorListenerAdapter() { this.animator = animator override fun onAnimationStart(animator: Animator) { return animator view.alpha = 1f } } override fun onAnimationEnd(animator: Animator) { view.alpha = 0f fun getSwipeDismissAnimation(velocity: Float): Animator { val screenWidth = view.resources.displayMetrics.widthPixels // translation at which point the visible UI is fully off the screen (in the direction // according to velocity) val endX = if (velocity < 0) { -1f * actionContainer.right } else { (screenWidth - actionContainer.left).toFloat() } } val distance = endX - view.translationX val animator = ValueAnimator.ofFloat(view.translationX, endX) animator.addUpdateListener { view.translationX = it.animatedValue as Float view.alpha = 1f - it.animatedFraction } } ) animator.duration = ((abs(distance / velocity))).toLong() this.animator = animator this.animator = animator return animator return animator } } Loading packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.graphics.Insets import android.graphics.Rect import android.graphics.Rect import android.graphics.Region import android.graphics.Region import android.util.AttributeSet import android.util.AttributeSet import android.view.MotionEvent import android.view.View import android.view.View import android.widget.ImageView import android.widget.ImageView import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout Loading @@ -30,6 +31,7 @@ import com.android.systemui.screenshot.FloatingWindowUtil class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : ConstraintLayout(context, attrs) { ConstraintLayout(context, attrs) { lateinit var screenshotPreview: ImageView lateinit var screenshotPreview: ImageView var onTouchInterceptListener: ((MotionEvent) -> Boolean)? = null private val displayMetrics = context.resources.displayMetrics private val displayMetrics = context.resources.displayMetrics private val tmpRect = Rect() private val tmpRect = Rect() Loading Loading @@ -83,4 +85,11 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : companion object { companion object { private const val TOUCH_PADDING_DP = 12f private const val TOUCH_PADDING_DP = 12f } } override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (onTouchInterceptListener?.invoke(ev) == true) { return true } return super.onInterceptTouchEvent(ev) } } } packages/SystemUI/src/com/android/systemui/screenshot/ui/SwipeGestureListener.kt 0 → 100644 +74 −0 Original line number Original line Diff line number Diff line /* * 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.screenshot.ui import android.view.MotionEvent import android.view.VelocityTracker import android.view.View import com.android.systemui.screenshot.FloatingWindowUtil import kotlin.math.abs import kotlin.math.sign class SwipeGestureListener( private val view: View, private val onDismiss: (Float) -> Unit, private val onCancel: () -> Unit ) { private val velocityTracker = VelocityTracker.obtain() private val displayMetrics = view.resources.displayMetrics private var startX = 0f fun onMotionEvent(ev: MotionEvent): Boolean { ev.offsetLocation(view.translationX, 0f) when (ev.actionMasked) { MotionEvent.ACTION_DOWN -> { velocityTracker.addMovement(ev) startX = ev.rawX } MotionEvent.ACTION_UP -> { velocityTracker.computeCurrentVelocity(1) val xVelocity = velocityTracker.xVelocity if ( abs(xVelocity) > FloatingWindowUtil.dpToPx(displayMetrics, FLING_THRESHOLD_DP) ) { onDismiss.invoke(xVelocity) return true } else if ( abs(view.translationX) > FloatingWindowUtil.dpToPx(displayMetrics, DISMISS_THRESHOLD_DP) ) { onDismiss.invoke(1.5f * sign(view.translationX)) return true } else { velocityTracker.clear() onCancel.invoke() } } MotionEvent.ACTION_MOVE -> { velocityTracker.addMovement(ev) view.translationX = ev.rawX - startX } } return false } companion object { private const val DISMISS_THRESHOLD_DP = 80f private const val FLING_THRESHOLD_DP = .8f // dp per ms } } packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt +6 −2 Original line number Original line Diff line number Diff line Loading @@ -17,8 +17,8 @@ package com.android.systemui.screenshot.ui.binder package com.android.systemui.screenshot.ui.binder import android.view.LayoutInflater import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.ImageView import android.widget.LinearLayout import android.widget.LinearLayout import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle Loading @@ -26,16 +26,20 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R import com.android.systemui.res.R import com.android.systemui.screenshot.ui.ScreenshotShelfView import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.util.children import com.android.systemui.util.children import kotlinx.coroutines.launch import kotlinx.coroutines.launch object ScreenshotShelfViewBinder { object ScreenshotShelfViewBinder { fun bind( fun bind( view: ViewGroup, view: ScreenshotShelfView, viewModel: ScreenshotViewModel, viewModel: ScreenshotViewModel, layoutInflater: LayoutInflater, layoutInflater: LayoutInflater, onTouchListener: (MotionEvent) -> Boolean, ) { ) { view.onTouchInterceptListener = onTouchListener val previewView: ImageView = view.requireViewById(R.id.screenshot_preview) val previewView: ImageView = view.requireViewById(R.id.screenshot_preview) val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border) val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border) previewView.clipToOutline = true previewView.clipToOutline = true Loading Loading
packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt +21 −2 Original line number Original line Diff line number Diff line Loading @@ -42,6 +42,7 @@ import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DISMISSED_OTHE import com.android.systemui.screenshot.scroll.ScrollCaptureController import com.android.systemui.screenshot.scroll.ScrollCaptureController import com.android.systemui.screenshot.ui.ScreenshotAnimationController import com.android.systemui.screenshot.ui.ScreenshotAnimationController import com.android.systemui.screenshot.ui.ScreenshotShelfView import com.android.systemui.screenshot.ui.ScreenshotShelfView import com.android.systemui.screenshot.ui.SwipeGestureListener import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder import com.android.systemui.screenshot.ui.binder.ScreenshotShelfViewBinder import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import dagger.assisted.Assisted import dagger.assisted.Assisted Loading Loading @@ -75,9 +76,17 @@ constructor( override var isPendingSharedTransition = false override var isPendingSharedTransition = false private val animationController = ScreenshotAnimationController(view) private val animationController = ScreenshotAnimationController(view) private val swipeGestureListener = SwipeGestureListener( view, onDismiss = { requestDismissal(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, it) }, onCancel = { animationController.getSwipeReturnAnimation().start() } ) init { init { ScreenshotShelfViewBinder.bind(view, viewModel, LayoutInflater.from(context)) ScreenshotShelfViewBinder.bind(view, viewModel, LayoutInflater.from(context)) { swipeGestureListener.onMotionEvent(it) } addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } setOnKeyListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } debugLog(DEBUG_WINDOW) { "adding OnComputeInternalInsetsListener" } debugLog(DEBUG_WINDOW) { "adding OnComputeInternalInsetsListener" } Loading Loading @@ -111,6 +120,10 @@ constructor( override fun setChipIntents(imageData: SavedImageData) {} override fun setChipIntents(imageData: SavedImageData) {} override fun requestDismissal(event: ScreenshotEvent?) { override fun requestDismissal(event: ScreenshotEvent?) { requestDismissal(event, getDismissalVelocity()) } private fun requestDismissal(event: ScreenshotEvent?, velocity: Float) { debugLog(DEBUG_DISMISS) { "screenshot dismissal requested: $event" } debugLog(DEBUG_DISMISS) { "screenshot dismissal requested: $event" } // If we're already animating out, don't restart the animation // If we're already animating out, don't restart the animation Loading @@ -119,7 +132,7 @@ constructor( return return } } event?.let { logger.log(it, 0, packageName) } event?.let { logger.log(it, 0, packageName) } val animator = animationController.getExitAnimation() val animator = animationController.getSwipeDismissAnimation(velocity) animator.addListener( animator.addListener( object : AnimatorListenerAdapter() { object : AnimatorListenerAdapter() { override fun onAnimationStart(animator: Animator) { override fun onAnimationStart(animator: Animator) { Loading Loading @@ -222,6 +235,12 @@ constructor( ) ) } } private fun getDismissalVelocity(): Float { val isLTR = view.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_LTR // dismiss to the left in LTR locales, to the right in RTL return if (isLTR) -1.5f else 1.5f } @AssistedFactory @AssistedFactory interface Factory : ScreenshotViewProxy.Factory { interface Factory : ScreenshotViewProxy.Factory { override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy override fun getProxy(context: Context, displayId: Int): ScreenshotShelfViewProxy Loading
packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotAnimationController.kt +29 −13 Original line number Original line Diff line number Diff line Loading @@ -20,9 +20,12 @@ import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.animation.ValueAnimator import android.view.View import android.view.View import com.android.systemui.res.R import kotlin.math.abs class ScreenshotAnimationController(private val view: View) { class ScreenshotAnimationController(private val view: ScreenshotShelfView) { private var animator: Animator? = null private var animator: Animator? = null private val actionContainer = view.requireViewById<View>(R.id.actions_container_background) fun getEntranceAnimation(): Animator { fun getEntranceAnimation(): Animator { val animator = ValueAnimator.ofFloat(0f, 1f) val animator = ValueAnimator.ofFloat(0f, 1f) Loading @@ -41,19 +44,32 @@ class ScreenshotAnimationController(private val view: View) { return animator return animator } } fun getExitAnimation(): Animator { fun getSwipeReturnAnimation(): Animator { val animator = ValueAnimator.ofFloat(1f, 0f) animator?.cancel() animator.addUpdateListener { view.alpha = it.animatedValue as Float } val animator = ValueAnimator.ofFloat(view.translationX, 0f) animator.addListener( animator.addUpdateListener { view.translationX = it.animatedValue as Float } object : AnimatorListenerAdapter() { this.animator = animator override fun onAnimationStart(animator: Animator) { return animator view.alpha = 1f } } override fun onAnimationEnd(animator: Animator) { view.alpha = 0f fun getSwipeDismissAnimation(velocity: Float): Animator { val screenWidth = view.resources.displayMetrics.widthPixels // translation at which point the visible UI is fully off the screen (in the direction // according to velocity) val endX = if (velocity < 0) { -1f * actionContainer.right } else { (screenWidth - actionContainer.left).toFloat() } } val distance = endX - view.translationX val animator = ValueAnimator.ofFloat(view.translationX, endX) animator.addUpdateListener { view.translationX = it.animatedValue as Float view.alpha = 1f - it.animatedFraction } } ) animator.duration = ((abs(distance / velocity))).toLong() this.animator = animator this.animator = animator return animator return animator } } Loading
packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.graphics.Insets import android.graphics.Rect import android.graphics.Rect import android.graphics.Region import android.graphics.Region import android.util.AttributeSet import android.util.AttributeSet import android.view.MotionEvent import android.view.View import android.view.View import android.widget.ImageView import android.widget.ImageView import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout Loading @@ -30,6 +31,7 @@ import com.android.systemui.screenshot.FloatingWindowUtil class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : ConstraintLayout(context, attrs) { ConstraintLayout(context, attrs) { lateinit var screenshotPreview: ImageView lateinit var screenshotPreview: ImageView var onTouchInterceptListener: ((MotionEvent) -> Boolean)? = null private val displayMetrics = context.resources.displayMetrics private val displayMetrics = context.resources.displayMetrics private val tmpRect = Rect() private val tmpRect = Rect() Loading Loading @@ -83,4 +85,11 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : companion object { companion object { private const val TOUCH_PADDING_DP = 12f private const val TOUCH_PADDING_DP = 12f } } override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { if (onTouchInterceptListener?.invoke(ev) == true) { return true } return super.onInterceptTouchEvent(ev) } } }
packages/SystemUI/src/com/android/systemui/screenshot/ui/SwipeGestureListener.kt 0 → 100644 +74 −0 Original line number Original line Diff line number Diff line /* * 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.screenshot.ui import android.view.MotionEvent import android.view.VelocityTracker import android.view.View import com.android.systemui.screenshot.FloatingWindowUtil import kotlin.math.abs import kotlin.math.sign class SwipeGestureListener( private val view: View, private val onDismiss: (Float) -> Unit, private val onCancel: () -> Unit ) { private val velocityTracker = VelocityTracker.obtain() private val displayMetrics = view.resources.displayMetrics private var startX = 0f fun onMotionEvent(ev: MotionEvent): Boolean { ev.offsetLocation(view.translationX, 0f) when (ev.actionMasked) { MotionEvent.ACTION_DOWN -> { velocityTracker.addMovement(ev) startX = ev.rawX } MotionEvent.ACTION_UP -> { velocityTracker.computeCurrentVelocity(1) val xVelocity = velocityTracker.xVelocity if ( abs(xVelocity) > FloatingWindowUtil.dpToPx(displayMetrics, FLING_THRESHOLD_DP) ) { onDismiss.invoke(xVelocity) return true } else if ( abs(view.translationX) > FloatingWindowUtil.dpToPx(displayMetrics, DISMISS_THRESHOLD_DP) ) { onDismiss.invoke(1.5f * sign(view.translationX)) return true } else { velocityTracker.clear() onCancel.invoke() } } MotionEvent.ACTION_MOVE -> { velocityTracker.addMovement(ev) view.translationX = ev.rawX - startX } } return false } companion object { private const val DISMISS_THRESHOLD_DP = 80f private const val FLING_THRESHOLD_DP = .8f // dp per ms } }
packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt +6 −2 Original line number Original line Diff line number Diff line Loading @@ -17,8 +17,8 @@ package com.android.systemui.screenshot.ui.binder package com.android.systemui.screenshot.ui.binder import android.view.LayoutInflater import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.ImageView import android.widget.LinearLayout import android.widget.LinearLayout import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle Loading @@ -26,16 +26,20 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R import com.android.systemui.res.R import com.android.systemui.screenshot.ui.ScreenshotShelfView import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.util.children import com.android.systemui.util.children import kotlinx.coroutines.launch import kotlinx.coroutines.launch object ScreenshotShelfViewBinder { object ScreenshotShelfViewBinder { fun bind( fun bind( view: ViewGroup, view: ScreenshotShelfView, viewModel: ScreenshotViewModel, viewModel: ScreenshotViewModel, layoutInflater: LayoutInflater, layoutInflater: LayoutInflater, onTouchListener: (MotionEvent) -> Boolean, ) { ) { view.onTouchInterceptListener = onTouchListener val previewView: ImageView = view.requireViewById(R.id.screenshot_preview) val previewView: ImageView = view.requireViewById(R.id.screenshot_preview) val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border) val previewBorder = view.requireViewById<View>(R.id.screenshot_preview_border) previewView.clipToOutline = true previewView.clipToOutline = true Loading