diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/DragAndDrop.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/DragAndDrop.kt index 309eb0f863..8dc79382e7 100644 --- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/DragAndDrop.kt +++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/DragAndDrop.kt @@ -16,15 +16,16 @@ package com.android.launcher3.widgetpicker.ui.components -import android.appwidget.AppWidgetProviderInfo import android.content.ClipData import android.content.ClipDescription +import android.content.ComponentName import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Point import android.graphics.Rect +import android.os.UserHandle import android.view.View import android.view.View.DragShadowBuilder import androidx.compose.ui.unit.Dp @@ -32,33 +33,31 @@ import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.IntSize import androidx.core.graphics.drawable.RoundedBitmapDrawable import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory +import com.android.launcher3.widgetpicker.shared.model.WidgetInfo import java.util.UUID -/** - * Information about the image's dimensions post scaling. - */ +/** Information about the image's dimensions post scaling. */ data class ImageScaledDimensions( val scale: Float, val scaledSizeDp: DpSize, val scaledSizePx: IntSize, val scaledRadiusDp: Dp, - val scaledRadiusPx: Float + val scaledRadiusPx: Float, ) -/** - * A [DragShadowBuilder] that draws drag shadow using the provided bitmap and image dimensions. - */ +/** A [DragShadowBuilder] that draws drag shadow using the provided bitmap and image dimensions. */ class ImageBitmapDragShadowBuilder( context: Context, bitmap: Bitmap, - imageScaledDimensions: ImageScaledDimensions + imageScaledDimensions: ImageScaledDimensions, ) : DragShadowBuilder() { private val shadowWidth = imageScaledDimensions.scaledSizePx.width private val shadowHeight = imageScaledDimensions.scaledSizePx.height private val shadowDrawable: RoundedBitmapDrawable = - RoundedBitmapDrawableFactory.create(context.resources, bitmap) - .apply { cornerRadius = imageScaledDimensions.scaledRadiusPx } + RoundedBitmapDrawableFactory.create(context.resources, bitmap).apply { + cornerRadius = imageScaledDimensions.scaledRadiusPx + } override fun onProvideShadowMetrics(outShadowSize: Point?, outShadowTouchPoint: Point?) { outShadowSize?.set(shadowWidth, shadowHeight) @@ -84,48 +83,62 @@ object TransparentDragShadowBuilder : DragShadowBuilder() { private const val SHADOW_SIZE = 10 override fun onDrawShadow(canvas: Canvas) {} + override fun onProvideShadowMetrics(outShadowSize: Point, outShadowTouchPoint: Point) { - outShadowSize.set(SHADOW_SIZE, SHADOW_SIZE); - outShadowTouchPoint.set(SHADOW_SIZE / 2, SHADOW_SIZE / 2); + outShadowSize.set(SHADOW_SIZE, SHADOW_SIZE) + outShadowTouchPoint.set(SHADOW_SIZE / 2, SHADOW_SIZE / 2) } } -/** State containing information to start a drag for a widget. */ +/** State containing information to start a drag for a widget. */ class DragState( - private val widgetInfo: AppWidgetProviderInfo, - private val dragShadowBuilder: DragShadowBuilder + private val widgetInfo: WidgetInfo, + private val dragShadowBuilder: DragShadowBuilder, ) { private val uniqueId = UUID.randomUUID().toString() val pickerMimeType = "com.android.launcher3.widgetpicker.drag_and_drop/$uniqueId" fun startDrag(view: View) { - val clipData = ClipData( - ClipDescription( - // not displayed anywhere; so, set to empty. - /* label= */ "", - arrayOf( - // unique picker specific mime type. - pickerMimeType, - // indicates that the clip item contains an intent (with extras about widget - // info). - ClipDescription.MIMETYPE_TEXT_INTENT - ) - ), - ClipData.Item( - Intent() - .putExtra(Intent.EXTRA_USER, widgetInfo.profile) - .putExtra( - Intent.EXTRA_COMPONENT_NAME, - widgetInfo.provider - ) + val clipData = + ClipData( + ClipDescription( + // not displayed anywhere; so, set to empty. + /* label= */ "", + arrayOf( + // unique picker specific mime type. + pickerMimeType, + // indicates that the clip item contains an intent (with extras about widget + // info). + ClipDescription.MIMETYPE_TEXT_INTENT, + ), + ), + ClipData.Item( + when (widgetInfo) { + is WidgetInfo.AppWidgetInfo -> + buildIntentForClipData( + user = widgetInfo.appWidgetProviderInfo.profile, + componentName = widgetInfo.appWidgetProviderInfo.provider, + ) + + is WidgetInfo.ShortcutInfo -> + buildIntentForClipData( + user = widgetInfo.launcherActivityInfo.user, + componentName = widgetInfo.launcherActivityInfo.componentName, + ) + } + ), ) - ) view.startDragAndDrop( clipData, /*shadowBuilder=*/ dragShadowBuilder, /*myLocalState=*/ null, - View.DRAG_FLAG_GLOBAL + View.DRAG_FLAG_GLOBAL, ) } + + private fun buildIntentForClipData(user: UserHandle, componentName: ComponentName): Intent = + Intent() + .putExtra(Intent.EXTRA_USER, user) + .putExtra(Intent.EXTRA_COMPONENT_NAME, componentName) } diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetDetails.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetDetails.kt index 4edcdfd40c..0ad64f804e 100644 --- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetDetails.kt +++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetDetails.kt @@ -36,7 +36,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.Text @@ -90,61 +89,56 @@ fun WidgetDetails( ) { val haptic = LocalHapticFeedback.current val interactionSource = remember { MutableInteractionSource() } - val contentDescription = stringResource( - R.string.widget_details_accessibility_label, - widget.label, - widget.sizeInfo.spanX, - widget.sizeInfo.spanY - ) + val contentDescription = + stringResource( + R.string.widget_details_accessibility_label, + widget.label, + widget.sizeInfo.spanX, + widget.sizeInfo.spanY, + ) - val detailsAlpha: Float by animateFloatAsState( - targetValue = if (showAddButton) INVISIBLE_ALPHA else VISIBLE_ALPHA, - animationSpec = tween(durationMillis = TOGGLE_ANIMATION_DURATION), - label = "detailsAlphaAnimation" - ) + val detailsAlpha: Float by + animateFloatAsState( + targetValue = if (showAddButton) INVISIBLE_ALPHA else VISIBLE_ALPHA, + animationSpec = tween(durationMillis = TOGGLE_ANIMATION_DURATION), + label = "detailsAlphaAnimation", + ) Box( contentAlignment = Alignment.Center, - modifier = modifier - .fillMaxSize() - .clickable( - onClickLabel = if (showAddButton) { - stringResource(R.string.widget_tap_to_hide_add_button_label) - } else { - stringResource(R.string.widget_tap_to_show_add_button_label) - }, - interactionSource = interactionSource, - indication = null - ) { - haptic.performHapticFeedback(HapticFeedbackType.VirtualKey) - onAddButtonToggle( - widget.id - ) - } - .padding( - horizontal = WidgetDetailsDimensions.horizontalPadding, - vertical = WidgetDetailsDimensions.verticalPadding - ) + modifier = + modifier + .fillMaxSize() + .clickable( + onClickLabel = + if (showAddButton) { + stringResource(R.string.widget_tap_to_hide_add_button_label) + } else { + stringResource(R.string.widget_tap_to_show_add_button_label) + }, + interactionSource = interactionSource, + indication = null, + ) { + haptic.performHapticFeedback(HapticFeedbackType.VirtualKey) + onAddButtonToggle(widget.id) + } + .padding( + horizontal = WidgetDetailsDimensions.horizontalPadding, + vertical = WidgetDetailsDimensions.verticalPadding, + ), ) { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top, - modifier = Modifier - .clearAndSetSemantics { this.contentDescription = contentDescription } - .minimumInteractiveComponentSize() - .graphicsLayer { alpha = detailsAlpha } - .fillMaxSize() + modifier = + Modifier.clearAndSetSemantics { this.contentDescription = contentDescription } + .minimumInteractiveComponentSize() + .graphicsLayer { alpha = detailsAlpha } + .fillMaxSize(), ) { - WidgetLabel( - label = widget.label, - appIcon = appIcon, - modifier = Modifier - ) + WidgetLabel(label = widget.label, appIcon = appIcon, modifier = Modifier) if (showAllDetails) { - WidgetSpanSizeLabel( - spanX = widget.sizeInfo.spanX, - spanY = widget.sizeInfo.spanY - ) + WidgetSpanSizeLabel(spanX = widget.sizeInfo.spanX, spanY = widget.sizeInfo.spanY) widget.description?.let { WidgetDescription(it) } } } @@ -152,16 +146,12 @@ fun WidgetDetails( visible = showAddButton, modifier = Modifier.fillMaxSize(), enter = AddButtonDefaults.enterTransition, - exit = AddButtonDefaults.exitTransition + exit = AddButtonDefaults.exitTransition, ) { AddButton( widget = widget, onClick = { - onWidgetAddClick( - WidgetInteractionInfo.WidgetAddInfo( - widget.appWidgetProviderInfo - ) - ) + onWidgetAddClick(WidgetInteractionInfo.WidgetAddInfo(widget.widgetInfo)) haptic.performHapticFeedback(HapticFeedbackType.Confirm) }, ) @@ -170,33 +160,28 @@ fun WidgetDetails( } @Composable -private fun AddButton( - widget: PickableWidget, - onClick: () -> Unit, -) { +private fun AddButton(widget: PickableWidget, onClick: () -> Unit) { val accessibleDescription = stringResource(R.string.widget_tap_to_add_button_content_description, widget.label) - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Button( modifier = Modifier.minimumInteractiveComponentSize(), contentPadding = AddButtonDimensions.paddingValues, - colors = ButtonDefaults.buttonColors( - containerColor = WidgetPickerTheme.colors.addButtonBackground, - contentColor = WidgetPickerTheme.colors.addButtonContent - ), + colors = + ButtonDefaults.buttonColors( + containerColor = WidgetPickerTheme.colors.addButtonBackground, + contentColor = WidgetPickerTheme.colors.addButtonContent, + ), onClick = onClick, ) { Icon( imageVector = Icons.Filled.Add, - contentDescription = null // decorative + contentDescription = null, // decorative ) Text( modifier = Modifier.semantics { this.contentDescription = accessibleDescription }, - text = stringResource(R.string.widget_tap_to_add_button_label) + text = stringResource(R.string.widget_tap_to_add_button_label), ) } } @@ -208,15 +193,13 @@ private fun WidgetLabel(label: String, appIcon: (@Composable () -> Unit)?, modif Row( modifier = modifier, horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, ) { if (appIcon != null) { appIcon() Spacer( modifier = - Modifier - .width(WidgetDetailsDimensions.appIconLabelSpacing) - .fillMaxHeight() + Modifier.width(WidgetDetailsDimensions.appIconLabelSpacing).fillMaxHeight() ) } Text( @@ -272,12 +255,7 @@ private object WidgetDetailsDimensions { } private object AddButtonDimensions { - val paddingValues = PaddingValues( - start = 8.dp, - top = 11.dp, - end = 16.dp, - bottom = 11.dp - ) + val paddingValues = PaddingValues(start = 8.dp, top = 11.dp, end = 16.dp, bottom = 11.dp) } private object AddButtonDefaults { diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetPreview.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetPreview.kt index 7977dd2ddc..2647ef77e8 100644 --- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetPreview.kt +++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetPreview.kt @@ -63,8 +63,10 @@ import androidx.compose.ui.unit.coerceAtMost import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import com.android.launcher3.widgetpicker.shared.model.WidgetId +import com.android.launcher3.widgetpicker.shared.model.WidgetInfo import com.android.launcher3.widgetpicker.shared.model.WidgetPreview import com.android.launcher3.widgetpicker.shared.model.WidgetSizeInfo +import com.android.launcher3.widgetpicker.shared.model.isAppWidget import com.android.launcher3.widgetpicker.ui.WidgetInteractionInfo import com.android.launcher3.widgetpicker.ui.theme.WidgetPickerTheme import kotlin.math.roundToInt @@ -75,11 +77,11 @@ fun WidgetPreview( id: WidgetId, sizeInfo: WidgetSizeInfo, preview: WidgetPreview, - appwidgetInfo: AppWidgetProviderInfo, + widgetInfo: WidgetInfo, modifier: Modifier = Modifier, showDragShadow: Boolean, onWidgetInteraction: (WidgetInteractionInfo) -> Unit, - onAddButtonToggle: (WidgetId) -> Unit + onAddButtonToggle: (WidgetId) -> Unit, ) { val interactionSource = remember { MutableInteractionSource() } val haptic = LocalHapticFeedback.current @@ -93,16 +95,16 @@ fun WidgetPreview( } Box( - modifier = modifier - .wrapContentSize() - .clickable( + modifier = + modifier.wrapContentSize().clickable( interactionSource = interactionSource, // no ripples for preview taps that toggle the add button. - indication = null + indication = null, ) { haptic.performHapticFeedback(HapticFeedbackType.VirtualKey) onAddButtonToggle(id) - }) { + } + ) { when (preview) { is WidgetPreview.PlaceholderWidgetPreview -> PlaceholderWidgetPreview(size = containerSize, widgetRadius = widgetRadius) @@ -112,30 +114,34 @@ fun WidgetPreview( bitmap = preview.bitmap, size = containerSize, widgetRadius = widgetRadius, - widgetInfo = appwidgetInfo, + widgetInfo = widgetInfo, showDragShadow = showDragShadow, onWidgetInteraction = onWidgetInteraction, ) - is WidgetPreview.RemoteViewsWidgetPreview -> + is WidgetPreview.RemoteViewsWidgetPreview -> { + check(widgetInfo.isAppWidget()) RemoteViewsWidgetPreview( remoteViews = preview.remoteViews, - widgetInfo = appwidgetInfo, + widgetInfo = widgetInfo, sizeInfo = sizeInfo, widgetRadius = widgetRadius, showDragShadow = showDragShadow, onWidgetInteraction = onWidgetInteraction, ) + } - is WidgetPreview.ProviderInfoWidgetPreview -> + is WidgetPreview.ProviderInfoWidgetPreview -> { + check(widgetInfo.isAppWidget()) RemoteViewsWidgetPreview( previewLayoutProviderInfo = preview.providerInfo, - widgetInfo = appwidgetInfo, + widgetInfo = widgetInfo, sizeInfo = sizeInfo, widgetRadius = widgetRadius, showDragShadow = showDragShadow, onWidgetInteraction = onWidgetInteraction, ) + } } } } @@ -145,8 +151,7 @@ private fun PlaceholderWidgetPreview(size: DpSize, widgetRadius: Dp) { Box( contentAlignment = Alignment.Center, modifier = - Modifier - .width(size.width) + Modifier.width(size.width) .height(size.height) .background( color = WidgetPickerTheme.colors.widgetPlaceholderBackground, @@ -161,7 +166,7 @@ private fun PlaceholderWidgetPreview(size: DpSize, widgetRadius: Dp) { private fun BitmapWidgetPreview( bitmap: Bitmap, size: DpSize, - widgetInfo: AppWidgetProviderInfo, + widgetInfo: WidgetInfo, widgetRadius: Dp, showDragShadow: Boolean, onWidgetInteraction: (WidgetInteractionInfo) -> Unit, @@ -170,22 +175,24 @@ private fun BitmapWidgetPreview( val density = LocalDensity.current val haptic = LocalHapticFeedback.current - val scaledBitmapDimensions by remember(bitmap, density, size) { - derivedStateOf { bitmap.calculateScaledDimensions(density, size, widgetRadius) } - } + val scaledBitmapDimensions by + remember(bitmap, density, size) { + derivedStateOf { bitmap.calculateScaledDimensions(density, size, widgetRadius) } + } - val dragState by remember(widgetInfo, showDragShadow) { - derivedStateOf { - DragState( - widgetInfo, - if (showDragShadow) { - ImageBitmapDragShadowBuilder(context, bitmap, scaledBitmapDimensions) - } else { - TransparentDragShadowBuilder - } - ) + val dragState by + remember(widgetInfo, showDragShadow) { + derivedStateOf { + DragState( + widgetInfo, + if (showDragShadow) { + ImageBitmapDragShadowBuilder(context, bitmap, scaledBitmapDimensions) + } else { + TransparentDragShadowBuilder + }, + ) + } } - } var imagePositionInParent by remember { mutableStateOf(Offset.Zero) } @@ -199,8 +206,7 @@ private fun BitmapWidgetPreview( contentDescription = null, // only visual (widget details provides the readable info) contentScale = ContentScale.FillBounds, modifier = - Modifier - .onGloballyPositioned { coordinates -> + Modifier.onGloballyPositioned { coordinates -> imagePositionInParent = coordinates.positionInParent() } .pointerInput(bitmap) { @@ -215,21 +221,19 @@ private fun BitmapWidgetPreview( calculateImageDragBounds( scaledBitmapDimensions = scaledBitmapDimensions, imagePositionInParent = imagePositionInParent, - offset = offset + offset = offset, ) onWidgetInteraction( WidgetInteractionInfo.WidgetDragInfo( mimeType = dragState.pickerMimeType, - providerInfo = widgetInfo, + widgetInfo = widgetInfo, bounds = bounds, widthPx = scaledBitmapDimensions.scaledSizePx.width, heightPx = scaledBitmapDimensions.scaledSizePx.height, - previewInfo = WidgetPreview.BitmapWidgetPreview( - bitmap = bitmap, - ), + previewInfo = WidgetPreview.BitmapWidgetPreview(bitmap = bitmap), ) ) - } + }, ) } .width(scaledBitmapDimensions.scaledSizeDp.width) @@ -242,26 +246,20 @@ private fun BitmapWidgetPreview( private fun calculateImageDragBounds( scaledBitmapDimensions: ImageScaledDimensions, imagePositionInParent: Offset, - offset: Offset + offset: Offset, ): Rect { val bounds = Rect() bounds.left = 0 bounds.top = 0 bounds.right = scaledBitmapDimensions.scaledSizePx.width bounds.bottom = scaledBitmapDimensions.scaledSizePx.height - val xOffset: Int = - (imagePositionInParent.x - offset.x).roundToInt() - val yOffset: Int = - (imagePositionInParent.y - offset.y).roundToInt() + val xOffset: Int = (imagePositionInParent.x - offset.x).roundToInt() + val yOffset: Int = (imagePositionInParent.y - offset.y).roundToInt() bounds.offset(xOffset, yOffset) return bounds } -private fun Bitmap.calculateScaledDimensions( - density: Density, - size: DpSize, - widgetRadius: Dp -) = +private fun Bitmap.calculateScaledDimensions(density: Density, size: DpSize, widgetRadius: Dp) = with(density) { val bitmapSize = DpSize(width = width.toDp(), height = height.toDp()) val bitmapAspectRatio = bitmapSize.width / bitmapSize.height @@ -269,20 +267,20 @@ private fun Bitmap.calculateScaledDimensions( // Scale by width if image has larger aspect ratio than the container else by // height; and avoid cropping the previews. - val scale = if (bitmapAspectRatio > containerAspectRatio) { - size.width / bitmapSize.width - } else { - size.height / bitmapSize.height - } + val scale = + if (bitmapAspectRatio > containerAspectRatio) { + size.width / bitmapSize.width + } else { + size.height / bitmapSize.height + } - val scaledDpSize = DpSize( - width = bitmapSize.width * scale, - height = bitmapSize.height * scale - ) - val scaledPxSize = IntSize( - width = scaledDpSize.width.roundToPx(), - height = scaledDpSize.height.roundToPx() - ) + val scaledDpSize = + DpSize(width = bitmapSize.width * scale, height = bitmapSize.height * scale) + val scaledPxSize = + IntSize( + width = scaledDpSize.width.roundToPx(), + height = scaledDpSize.height.roundToPx(), + ) val scaledRadius = (widgetRadius * scale).coerceAtMost(widgetRadius).value.roundToInt().dp ImageScaledDimensions( @@ -290,7 +288,7 @@ private fun Bitmap.calculateScaledDimensions( scaledSizePx = scaledPxSize, scaledSizeDp = scaledDpSize, scaledRadiusDp = scaledRadius, - scaledRadiusPx = scaledRadius.toPx() + scaledRadiusPx = scaledRadius.toPx(), ) } @@ -298,7 +296,7 @@ private fun Bitmap.calculateScaledDimensions( private fun RemoteViewsWidgetPreview( remoteViews: RemoteViews? = null, previewLayoutProviderInfo: AppWidgetProviderInfo? = null, - widgetInfo: AppWidgetProviderInfo, + widgetInfo: WidgetInfo.AppWidgetInfo, sizeInfo: WidgetSizeInfo, widgetRadius: Dp, onWidgetInteraction: (WidgetInteractionInfo) -> Unit, @@ -308,67 +306,71 @@ private fun RemoteViewsWidgetPreview( val haptic = LocalHapticFeedback.current val appWidgetHostView by - remember(sizeInfo, widgetInfo) { - derivedStateOf { - WidgetPreviewHostView(context).apply { - setContainerSizePx( - IntSize(sizeInfo.containerWidthPx, sizeInfo.containerHeightPx) - ) + remember(sizeInfo, widgetInfo) { + derivedStateOf { + WidgetPreviewHostView(context).apply { + setContainerSizePx( + IntSize(sizeInfo.containerWidthPx, sizeInfo.containerHeightPx) + ) + } } } - } val dragState by remember { derivedStateOf { DragState( widgetInfo = widgetInfo, - dragShadowBuilder = if (showDragShadow) { - DragShadowBuilder(appWidgetHostView) - } else { - TransparentDragShadowBuilder - } + dragShadowBuilder = + if (showDragShadow) { + DragShadowBuilder(appWidgetHostView) + } else { + TransparentDragShadowBuilder + }, ) } } key(appWidgetHostView) { AndroidView( - modifier = Modifier - .pointerInput(appWidgetHostView) { - detectDragGesturesAfterLongPress( - onDrag = { change, _ -> change.consume() }, - onDragStart = { offset -> - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - dragState.startDrag(appWidgetHostView) + modifier = + Modifier.pointerInput(appWidgetHostView) { + detectDragGesturesAfterLongPress( + onDrag = { change, _ -> change.consume() }, + onDragStart = { offset -> + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + dragState.startDrag(appWidgetHostView) - onWidgetInteraction( - WidgetInteractionInfo.WidgetDragInfo( - mimeType = dragState.pickerMimeType, - providerInfo = widgetInfo, - bounds = appWidgetHostView.getDragBoundsForOffset(offset), - widthPx = appWidgetHostView.measuredWidth, - heightPx = appWidgetHostView.measuredHeight, - previewInfo = when { - remoteViews != null -> - WidgetPreview.RemoteViewsWidgetPreview( - remoteViews = remoteViews, - ) + onWidgetInteraction( + WidgetInteractionInfo.WidgetDragInfo( + mimeType = dragState.pickerMimeType, + widgetInfo = widgetInfo, + bounds = appWidgetHostView.getDragBoundsForOffset(offset), + widthPx = appWidgetHostView.measuredWidth, + heightPx = appWidgetHostView.measuredHeight, + previewInfo = + when { + remoteViews != null -> + WidgetPreview.RemoteViewsWidgetPreview( + remoteViews = remoteViews + ) - previewLayoutProviderInfo != null -> - WidgetPreview.ProviderInfoWidgetPreview( - providerInfo = previewLayoutProviderInfo - ) + previewLayoutProviderInfo != null -> + WidgetPreview.ProviderInfoWidgetPreview( + providerInfo = previewLayoutProviderInfo + ) - else -> - throw IllegalStateException("No preview during drag") - } + else -> + throw IllegalStateException( + "No preview during drag" + ) + }, + ) ) - ) - }, - ) - } - .wrapContentSize() - .clip(RoundedCornerShape(widgetRadius)), + }, + ) + } + .wrapContentSize() + .clip(RoundedCornerShape(widgetRadius)), factory = { appWidgetHostView }, update = { view -> // if preview.remoteViews is null, initial layout will render. @@ -376,7 +378,7 @@ private fun RemoteViewsWidgetPreview( // to be the previewLayout. view.setAppWidget( /*appWidgetId=*/ NO_OP_APP_WIDGET_ID, - /*info=*/ previewLayoutProviderInfo ?: widgetInfo, + /*info=*/ previewLayoutProviderInfo ?: widgetInfo.appWidgetProviderInfo, ) view.updateAppWidget(remoteViews) }, diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGrid.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGrid.kt index 5e0ecf8a94..4426ab7254 100644 --- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGrid.kt +++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGrid.kt @@ -61,10 +61,10 @@ import kotlin.math.max * @param appIcons optional map containing app icons to show in the widget details besides the label * (when showing the widgets outside of app context e.g. recommendations) * @param showDragShadow indicates if in a drag and drop session, widget picker should show drag - * shadow containing the preview; if not set, a transparent shadow is rendered and host should - * manage providing a shadow on its own. + * shadow containing the preview; if not set, a transparent shadow is rendered and host should + * manage providing a shadow on its own. * @param onWidgetInteraction callback invoked when a widget is being dragged and picker has started - * global drag and drop session. + * global drag and drop session. * @param modifier modifier with parent constraints and additional modifications */ @Composable @@ -93,12 +93,13 @@ fun WidgetsGrid( addButtonWidgetId = addButtonWidgetId, onWidgetInteraction = onWidgetInteraction, onAddButtonToggle = { id -> - addButtonWidgetId = if (id != addButtonWidgetId) { - id - } else { - null - } - } + addButtonWidgetId = + if (id != addButtonWidgetId) { + id + } else { + null + } + }, ) } } @@ -155,7 +156,7 @@ private fun WidgetsFlowRow( appIcons = appIcons, addButtonWidgetId = addButtonWidgetId, onWidgetInteraction = onWidgetInteraction, - onAddButtonToggle = onAddButtonToggle + onAddButtonToggle = onAddButtonToggle, ) }, previewContainerWidthPx = widgetSizeGroup.previewContainerWidthPx, @@ -184,21 +185,19 @@ private fun Previews( Box( contentAlignment = Alignment.BottomCenter, modifier = - Modifier - .fillMaxSize() - .clearAndSetSemantics { - traversalIndex = index.toFloat() - testTag = buildWidgetPickerTestTag(WIDGET_PREVIEW_TEST_TAG) - }, + Modifier.fillMaxSize().clearAndSetSemantics { + traversalIndex = index.toFloat() + testTag = buildWidgetPickerTestTag(WIDGET_PREVIEW_TEST_TAG) + }, ) { WidgetPreview( id = widgetItem.id, sizeInfo = widgetItem.sizeInfo, preview = widgetPreview, - appwidgetInfo = widgetItem.appWidgetProviderInfo, + widgetInfo = widgetItem.widgetInfo, showDragShadow = showDragShadow, onWidgetInteraction = onWidgetInteraction, - onAddButtonToggle = onAddButtonToggle + onAddButtonToggle = onAddButtonToggle, ) } } @@ -211,7 +210,7 @@ private fun Details( addButtonWidgetId: WidgetId?, appIcons: Map, onWidgetInteraction: (WidgetInteractionInfo) -> Unit, - onAddButtonToggle: (WidgetId) -> Unit + onAddButtonToggle: (WidgetId) -> Unit, ) { widgets.forEachIndexed { index, widgetItem -> val appId = widgetItem.appId @@ -376,8 +375,8 @@ private fun Placeable.PlacementScope.placeRows( // Move to next row yPosition += measuredRow.tallestPreviewHeight + - measuredRow.tallestDetailsHeight + - rowVerticalSpacingPx + measuredRow.tallestDetailsHeight + + rowVerticalSpacingPx } } diff --git a/modules/widgetpicker/tests/multivalentScreenshotTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGridTestSamples.kt b/modules/widgetpicker/tests/multivalentScreenshotTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGridTestSamples.kt index f86e0ab4f4..29a15cab93 100644 --- a/modules/widgetpicker/tests/multivalentScreenshotTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGridTestSamples.kt +++ b/modules/widgetpicker/tests/multivalentScreenshotTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetsGridTestSamples.kt @@ -30,6 +30,7 @@ import androidx.compose.ui.unit.IntSize import com.android.launcher3.widgetpicker.shared.model.PickableWidget import com.android.launcher3.widgetpicker.shared.model.WidgetAppId import com.android.launcher3.widgetpicker.shared.model.WidgetId +import com.android.launcher3.widgetpicker.shared.model.WidgetInfo import com.android.launcher3.widgetpicker.shared.model.WidgetPreview import com.android.launcher3.widgetpicker.shared.model.WidgetSizeInfo import com.android.launcher3.widgetpicker.tests.R @@ -253,7 +254,7 @@ object WidgetsGridTestSamples { containerWidthPx = cellWidth, containerHeightPx = cellHeight, ), - appWidgetProviderInfo = newAppWidgetInfo("OneByOneProvider"), + widgetInfo = WidgetInfo.AppWidgetInfo(newAppWidgetInfo("OneByOneProvider")), ) private fun twoByTwo(cellWidth: Int, cellHeight: Int) = @@ -262,7 +263,7 @@ object WidgetsGridTestSamples { appId = TEST_WIDGET_APP_ID, label = "Two by Two", description = null, - appWidgetProviderInfo = newAppWidgetInfo("TwoByTwoProvider"), + widgetInfo = WidgetInfo.AppWidgetInfo(newAppWidgetInfo("TwoByTwoProvider")), sizeInfo = WidgetSizeInfo( spanX = 2, @@ -283,7 +284,7 @@ object WidgetsGridTestSamples { appId = TEST_WIDGET_APP_ID, label = "Three by two", description = null, - appWidgetProviderInfo = newAppWidgetInfo("threeByTwoProvider"), + widgetInfo = WidgetInfo.AppWidgetInfo(newAppWidgetInfo("threeByTwoProvider")), sizeInfo = WidgetSizeInfo( spanX = 3, @@ -304,7 +305,7 @@ object WidgetsGridTestSamples { appId = TEST_WIDGET_APP_ID, label = "Four by two", description = null, - appWidgetProviderInfo = newAppWidgetInfo("FourByTwoProvider"), + widgetInfo = WidgetInfo.AppWidgetInfo(newAppWidgetInfo("FourByTwoProvider")), sizeInfo = WidgetSizeInfo( spanX = 4, diff --git a/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/TestUtils.kt b/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/TestUtils.kt index d65670177c..890191bea3 100644 --- a/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/TestUtils.kt +++ b/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/TestUtils.kt @@ -27,6 +27,7 @@ import com.android.launcher3.widgetpicker.shared.model.PickableWidget import com.android.launcher3.widgetpicker.shared.model.WidgetApp import com.android.launcher3.widgetpicker.shared.model.WidgetAppId import com.android.launcher3.widgetpicker.shared.model.WidgetId +import com.android.launcher3.widgetpicker.shared.model.WidgetInfo import com.android.launcher3.widgetpicker.shared.model.WidgetPreview import com.android.launcher3.widgetpicker.shared.model.WidgetSizeInfo import com.android.launcher3.widgetpicker.shared.model.WidgetUserProfile @@ -118,10 +119,13 @@ object TestUtils { appId = finalWidgetAppId, label = providerClassName, description = null, - appWidgetProviderInfo = AppWidgetProviderInfo().apply { - widgetCategory = category - provider = ComponentName.createRelative(PACKAGE_NAME, providerClassName) - }, + widgetInfo = + WidgetInfo.AppWidgetInfo( + AppWidgetProviderInfo().apply { + widgetCategory = category + provider = ComponentName.createRelative(PACKAGE_NAME, providerClassName) + } + ), sizeInfo = WidgetSizeInfo( spanX = 2, diff --git a/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetInteractionsTest.kt b/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetInteractionsTest.kt index 6e2fb01f08..83991fab0c 100644 --- a/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetInteractionsTest.kt +++ b/modules/widgetpicker/tests/multivalentTests/src/com/android/launcher3/widgetpicker/ui/components/WidgetInteractionsTest.kt @@ -53,11 +53,9 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) @AllowedDevices(allowed = [DeviceProduct.CF_PHONE]) class WidgetInteractionsTest { - @get:Rule - val limitDevicesRule = LimitDevicesRule() + @get:Rule val limitDevicesRule = LimitDevicesRule() - @get:Rule - val composeTestRule = createAndroidComposeRule() + @get:Rule val composeTestRule = createAndroidComposeRule() @Test fun tapPreview_andClickAdd() { @@ -66,7 +64,8 @@ class WidgetInteractionsTest { composeTestRule.waitForIdle() // tap on preview for widget 1 - composeTestRule.onAllNodesWithTag(PREVIEW_TEST_TAG) + composeTestRule + .onAllNodesWithTag(PREVIEW_TEST_TAG) .assertCountEquals(2) .onFirst() .performClick() @@ -74,18 +73,19 @@ class WidgetInteractionsTest { composeTestRule.waitForIdle() composeTestRule.onNodeWithText(WIDGET_ONE.label).isNotDisplayed() // label text not shown composeTestRule.onAllNodesWithText(ADD_BUTTON_TEXT).assertCountEquals(1) - composeTestRule.onNodeWithContentDescription(WIDGET_ONE_ADD_BUTTON_CONTENT_DESC) + composeTestRule + .onNodeWithContentDescription(WIDGET_ONE_ADD_BUTTON_CONTENT_DESC) .assertExists() .performClick() composeTestRule.waitForIdle() // widget interaction callback invoked and correct provider info returned. - composeTestRule.onNodeWithText(WIDGET_ONE.appWidgetProviderInfo.provider.toString()) - .assertExists() + composeTestRule.onNodeWithText(WIDGET_ONE.widgetInfo.toString()).assertExists() // tap again on preview for widget 1 - composeTestRule.onAllNodesWithTag(PREVIEW_TEST_TAG) + composeTestRule + .onAllNodesWithTag(PREVIEW_TEST_TAG) .assertCountEquals(2) .onFirst() .performClick() @@ -103,7 +103,8 @@ class WidgetInteractionsTest { composeTestRule.waitForIdle() // tap on preview for widget 1 - composeTestRule.onAllNodesWithTag(PREVIEW_TEST_TAG) + composeTestRule + .onAllNodesWithTag(PREVIEW_TEST_TAG) .assertCountEquals(2) .onFirst() .performClick() @@ -114,11 +115,13 @@ class WidgetInteractionsTest { composeTestRule.onNodeWithText(WIDGET_ONE.label).isNotDisplayed() composeTestRule.onNodeWithText(WIDGET_TWO.label).isNotDisplayed() composeTestRule.onAllNodesWithText(ADD_BUTTON_TEXT).assertCountEquals(1) - composeTestRule.onNodeWithContentDescription(WIDGET_ONE_ADD_BUTTON_CONTENT_DESC) + composeTestRule + .onNodeWithContentDescription(WIDGET_ONE_ADD_BUTTON_CONTENT_DESC) .assertExists() // tap on preview for widget 2 - composeTestRule.onAllNodesWithTag(PREVIEW_TEST_TAG) + composeTestRule + .onAllNodesWithTag(PREVIEW_TEST_TAG) .assertCountEquals(2) .onLast() .performClick() @@ -129,11 +132,11 @@ class WidgetInteractionsTest { composeTestRule.onNodeWithText(WIDGET_ONE.label).isDisplayed() composeTestRule.onNodeWithText(WIDGET_TWO.label).isNotDisplayed() composeTestRule.onAllNodesWithText(ADD_BUTTON_TEXT).assertCountEquals(1) - composeTestRule.onNodeWithContentDescription(WIDGET_TWO_ADD_BUTTON_CONTENT_DESC) + composeTestRule + .onNodeWithContentDescription(WIDGET_TWO_ADD_BUTTON_CONTENT_DESC) .assertExists() } - @Composable fun TapToAddTestComposable() { var provider by remember { mutableStateOf("invalid") } @@ -149,7 +152,7 @@ class WidgetInteractionsTest { showDragShadow = false, onWidgetInteraction = { widgetInteractionInfo -> if (widgetInteractionInfo is WidgetInteractionInfo.WidgetAddInfo) { - provider = widgetInteractionInfo.providerInfo.provider.toString() + provider = widgetInteractionInfo.widgetInfo.toString() } }, ) @@ -160,16 +163,18 @@ class WidgetInteractionsTest { private val WIDGET_ONE = PERSONAL_TEST_APPS[0].widgets[0] private val WIDGET_TWO = PERSONAL_TEST_APPS[1].widgets[0] - private val TEST_WIDGET_GROUP = WidgetSizeGroup( - previewContainerHeightPx = 200, - previewContainerWidthPx = 200, - widgets = listOf(WIDGET_ONE, WIDGET_TWO) - ) + private val TEST_WIDGET_GROUP = + WidgetSizeGroup( + previewContainerHeightPx = 200, + previewContainerWidthPx = 200, + widgets = listOf(WIDGET_ONE, WIDGET_TWO), + ) - private val PREVIEWS = mapOf( - WIDGET_ONE.id to TestUtils.createBitmapPreview(), - WIDGET_TWO.id to TestUtils.createBitmapPreview() - ) + private val PREVIEWS = + mapOf( + WIDGET_ONE.id to TestUtils.createBitmapPreview(), + WIDGET_TWO.id to TestUtils.createBitmapPreview(), + ) private val PREVIEW_TEST_TAG = buildWidgetPickerTestTag("widget_preview") private const val ADD_BUTTON_TEXT = "Add"