Merge changes from topic "p-shortcut-impl" into main
* changes:
Widget Picker: Update the launcher integration to support shortcuts
Widget Picker: Update UI layer to support shortcuts
Widget Picker: Update data layer to support shortcuts
diff --git a/compose/features/com/android/launcher3/widgetpicker/WidgetPickerComposeWrapperImpl.kt b/compose/features/com/android/launcher3/widgetpicker/WidgetPickerComposeWrapperImpl.kt
index 22a47e9..c408620 100644
--- a/compose/features/com/android/launcher3/widgetpicker/WidgetPickerComposeWrapperImpl.kt
+++ b/compose/features/com/android/launcher3/widgetpicker/WidgetPickerComposeWrapperImpl.kt
@@ -18,8 +18,8 @@
import android.app.Activity.RESULT_OK
import android.content.Context
-import androidx.compose.foundation.isSystemInDarkTheme
import android.content.Intent
+import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
@@ -33,7 +33,6 @@
import com.android.launcher3.concurrent.annotations.BackgroundContext
import com.android.launcher3.dagger.ApplicationContext
import com.android.launcher3.util.ApiWrapper
-import com.android.launcher3.widgetpicker.WidgetPickerConfig
import com.android.launcher3.widgetpicker.WidgetPickerConfig.Companion.EXTRA_IS_PENDING_WIDGET_DRAG
import com.android.launcher3.widgetpicker.data.repository.WidgetAppIconsRepository
import com.android.launcher3.widgetpicker.data.repository.WidgetUsersRepository
@@ -42,15 +41,16 @@
import com.android.launcher3.widgetpicker.listeners.WidgetPickerDragItemListener
import com.android.launcher3.widgetpicker.shared.model.HostConstraint
import com.android.launcher3.widgetpicker.shared.model.WidgetHostInfo
+import com.android.launcher3.widgetpicker.shared.model.isAppWidget
+import com.android.launcher3.widgetpicker.theme.darkWidgetPickerColors
+import com.android.launcher3.widgetpicker.theme.lightWidgetPickerColors
import com.android.launcher3.widgetpicker.ui.WidgetInteractionInfo
import com.android.launcher3.widgetpicker.ui.WidgetPickerEventListeners
import com.android.launcher3.widgetpicker.ui.theme.WidgetPickerTheme
-import com.android.launcher3.widgetpicker.theme.darkWidgetPickerColors
-import com.android.launcher3.widgetpicker.theme.lightWidgetPickerColors
-import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Provider
import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.launch
/**
* An helper that bootstraps widget picker UI (from [WidgetPickerComponent]) in to
@@ -58,21 +58,21 @@
*
* Sets up the bindings necessary for widget picker component.
*/
-class WidgetPickerComposeWrapperImpl @Inject constructor(
+class WidgetPickerComposeWrapperImpl
+@Inject
+constructor(
private val widgetPickerComponentProvider: Provider<WidgetPickerComponent.Factory>,
private val widgetsRepository: WidgetsRepository,
private val widgetUsersRepository: WidgetUsersRepository,
private val widgetAppIconsRepository: WidgetAppIconsRepository,
- @BackgroundContext
- private val backgroundContext: CoroutineContext,
- @ApplicationContext
- private val appContext: Context,
+ @BackgroundContext private val backgroundContext: CoroutineContext,
+ @ApplicationContext private val appContext: Context,
private val apiWrapper: ApiWrapper,
) : WidgetPickerComposeWrapper {
override fun showAllWidgets(
activity: WidgetPickerActivity,
- widgetPickerConfig: WidgetPickerConfig
+ widgetPickerConfig: WidgetPickerConfig,
) {
val widgetPickerComponent = newWidgetPickerComponent(widgetPickerConfig)
val callbacks = activity.buildEventListeners(widgetPickerConfig, apiWrapper)
@@ -85,11 +85,12 @@
val scope = rememberCoroutineScope()
val view = LocalView.current
- val widgetPickerColors = if (isSystemInDarkTheme()) {
- darkWidgetPickerColors()
- } else {
- lightWidgetPickerColors()
- }
+ val widgetPickerColors =
+ if (isSystemInDarkTheme()) {
+ darkWidgetPickerColors()
+ } else {
+ lightWidgetPickerColors()
+ }
MaterialTheme { // TODO(b/408283627): Use launcher theme.
WidgetPickerTheme(colors = widgetPickerColors) {
@@ -99,13 +100,9 @@
}
DisposableEffect(view) {
- scope.launch {
- initializeRepositories()
- }
+ scope.launch { initializeRepositories() }
- onDispose {
- cleanUpRepositories()
- }
+ onDispose { cleanUpRepositories() }
}
}
}
@@ -116,19 +113,22 @@
private fun newWidgetPickerComponent(
widgetPickerConfig: WidgetPickerConfig
): WidgetPickerComponent {
- return widgetPickerComponentProvider.get()
+ return widgetPickerComponentProvider
+ .get()
.build(
widgetsRepository = widgetsRepository,
widgetUsersRepository = widgetUsersRepository,
widgetAppIconsRepository = widgetAppIconsRepository,
- widgetHostInfo = WidgetHostInfo(
- title = widgetPickerConfig.title
- ?: appContext.resources.getString(R.string.widget_button_text),
- description = widgetPickerConfig.description,
- constraints = widgetPickerConfig.asHostConstraints(),
- showDragShadow = !widgetPickerConfig.isForHomeScreen
- ),
- backgroundContext = backgroundContext
+ widgetHostInfo =
+ WidgetHostInfo(
+ title =
+ widgetPickerConfig.title
+ ?: appContext.resources.getString(R.string.widget_button_text),
+ description = widgetPickerConfig.description,
+ constraints = widgetPickerConfig.asHostConstraints(),
+ showDragShadow = !widgetPickerConfig.isForHomeScreen,
+ ),
+ backgroundContext = backgroundContext,
)
}
@@ -150,20 +150,21 @@
private fun WidgetPickerActivity.buildEventListeners(
widgetPickerConfig: WidgetPickerConfig,
- apiWrapper: ApiWrapper
- ) = object : WidgetPickerEventListeners {
- override fun onClose() {
- finish()
- }
+ apiWrapper: ApiWrapper,
+ ) =
+ object : WidgetPickerEventListeners {
+ override fun onClose() {
+ finish()
+ }
- override fun onWidgetInteraction(widgetInteractionInfo: WidgetInteractionInfo) {
- if (widgetPickerConfig.isForHomeScreen) {
- handleWidgetInteractionForHomeScreen(widgetInteractionInfo, apiWrapper)
- } else {
- handleWidgetInteractionForExternalHost(widgetInteractionInfo)
+ override fun onWidgetInteraction(widgetInteractionInfo: WidgetInteractionInfo) {
+ if (widgetPickerConfig.isForHomeScreen) {
+ handleWidgetInteractionForHomeScreen(widgetInteractionInfo, apiWrapper)
+ } else {
+ handleWidgetInteractionForExternalHost(widgetInteractionInfo)
+ }
}
}
- }
/**
* Handles communication with the home screen about the "add" and "drag" interactions on
@@ -171,37 +172,38 @@
*
* For home screen, we register a listener that is called back when home screen is shown;
* - WidgetPickerDragItemListener: bootstraps the drag helper that displays the shadow and
- * handles the drag until completion.
+ * handles the drag until completion.
* - WidgetPickerAddItemListener: once launcher is shown, triggers the flow to add the
- * widget to workspace.
+ * widget to workspace.
*/
private fun WidgetPickerActivity.handleWidgetInteractionForHomeScreen(
interactionInfo: WidgetInteractionInfo,
- apiWrapper: ApiWrapper
+ apiWrapper: ApiWrapper,
) {
- val interactionListener = when (interactionInfo) {
- is WidgetInteractionInfo.WidgetDragInfo ->
- WidgetPickerDragItemListener(
- mimeType = interactionInfo.mimeType,
- appWidgetProviderInfo = interactionInfo.providerInfo,
- widgetPreview = interactionInfo.previewInfo,
- previewRect = interactionInfo.bounds,
- previewWidth = interactionInfo.widthPx
- )
+ val interactionListener =
+ when (interactionInfo) {
+ is WidgetInteractionInfo.WidgetDragInfo ->
+ WidgetPickerDragItemListener(
+ mimeType = interactionInfo.mimeType,
+ widgetInfo = interactionInfo.widgetInfo,
+ widgetPreview = interactionInfo.previewInfo,
+ previewRect = interactionInfo.bounds,
+ previewWidth = interactionInfo.widthPx,
+ )
- is WidgetInteractionInfo.WidgetAddInfo ->
- WidgetPickerAddItemListener(interactionInfo.providerInfo)
- }
+ is WidgetInteractionInfo.WidgetAddInfo ->
+ WidgetPickerAddItemListener(interactionInfo.widgetInfo)
+ }
Launcher.ACTIVITY_TRACKER.registerCallback(
interactionListener,
- HOME_SCREEN_WIDGET_INTERACTION_REASON_STRING
+ HOME_SCREEN_WIDGET_INTERACTION_REASON_STRING,
)
startActivity(
/*intent=*/ Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setPackage(packageName)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
- /*options=*/ apiWrapper.createFadeOutAnimOptions().toBundle()
+ /*options=*/ apiWrapper.createFadeOutAnimOptions().toBundle(),
)
finish()
}
@@ -209,30 +211,35 @@
/**
* Handles communication with the external host about the "add" and "drag" interactions on
* widgets within widget picker.
- *
* - In case of drag and drop, finishes the activity with result indicating that there is a
- * pending drag [EXTRA_IS_PENDING_WIDGET_DRAG] (that would contain the widget info as part
- * of clip data) that the host should be handling.
+ * pending drag [EXTRA_IS_PENDING_WIDGET_DRAG] (that would contain the widget info as part
+ * of clip data) that the host should be handling.
* - In case of add, finishes the activity with result containing extra information about
- * the widget being added (namely [Intent.EXTRA_COMPONENT_NAME] and [Intent.EXTRA_USER].
+ * the widget being added (namely [Intent.EXTRA_COMPONENT_NAME] and [Intent.EXTRA_USER].
*/
private fun WidgetPickerActivity.handleWidgetInteractionForExternalHost(
- widgetInteractionInfo: WidgetInteractionInfo,
+ widgetInteractionInfo: WidgetInteractionInfo
) {
when (widgetInteractionInfo) {
is WidgetInteractionInfo.WidgetDragInfo ->
- setResult(
- RESULT_OK,
- Intent().putExtra(EXTRA_IS_PENDING_WIDGET_DRAG, true)
- )
+ setResult(RESULT_OK, Intent().putExtra(EXTRA_IS_PENDING_WIDGET_DRAG, true))
is WidgetInteractionInfo.WidgetAddInfo -> {
- val providerInfo = widgetInteractionInfo.providerInfo
- setResult(
- RESULT_OK, Intent()
- .putExtra(Intent.EXTRA_COMPONENT_NAME, providerInfo.provider)
- .putExtra(Intent.EXTRA_USER, providerInfo.profile)
- )
+ val widgetInfo = widgetInteractionInfo.widgetInfo
+ if (widgetInfo.isAppWidget()) {
+ val providerInfo = widgetInfo.appWidgetProviderInfo
+ setResult(
+ RESULT_OK,
+ Intent().apply {
+ putExtra(Intent.EXTRA_COMPONENT_NAME, providerInfo.provider)
+ putExtra(Intent.EXTRA_USER, providerInfo.profile)
+ },
+ )
+ } else {
+ throw IllegalStateException(
+ "AppWidgetInfo not provided for external host drag"
+ )
+ }
}
}
@@ -240,21 +247,21 @@
}
/** Builds the host constraints to provide to the widget picker module. */
- fun WidgetPickerConfig.asHostConstraints() =
- buildList {
- if (filteredUsers.isNotEmpty()) {
- add(HostConstraint.HostUserConstraint(filteredUsers))
- }
- if (categoryInclusionFilter != 0
- || categoryExclusionFilter != 0
- ) {
- add(
- HostConstraint.HostCategoryConstraint(
- categoryInclusionMask = categoryInclusionFilter,
- categoryExclusionMask = categoryExclusionFilter,
- )
- )
- }
+ fun WidgetPickerConfig.asHostConstraints() = buildList {
+ if (filteredUsers.isNotEmpty()) {
+ add(HostConstraint.HostUserConstraint(filteredUsers))
}
+ if (!isForHomeScreen) {
+ add(HostConstraint.NoShortcutsConstraint)
+ }
+ if (categoryInclusionFilter != 0 || categoryExclusionFilter != 0) {
+ add(
+ HostConstraint.HostCategoryConstraint(
+ categoryInclusionMask = categoryInclusionFilter,
+ categoryExclusionMask = categoryExclusionFilter,
+ )
+ )
+ }
+ }
}
}
diff --git a/compose/features/com/android/launcher3/widgetpicker/datasource/ConfigResourceFeaturedWidgetsDataSource.kt b/compose/features/com/android/launcher3/widgetpicker/datasource/ConfigResourceFeaturedWidgetsDataSource.kt
index d361452..5c11c7f 100644
--- a/compose/features/com/android/launcher3/widgetpicker/datasource/ConfigResourceFeaturedWidgetsDataSource.kt
+++ b/compose/features/com/android/launcher3/widgetpicker/datasource/ConfigResourceFeaturedWidgetsDataSource.kt
@@ -24,6 +24,7 @@
import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize
import com.android.launcher3.widgetpicker.shared.model.PickableWidget
import com.android.launcher3.widgetpicker.shared.model.WidgetApp
+import com.android.launcher3.widgetpicker.shared.model.isAppWidget
import java.util.Arrays
import java.util.stream.Collectors
import javax.inject.Inject
@@ -31,47 +32,61 @@
/**
* An implementation of [FeaturedWidgetsDataSource] that provides featured widgets based on a static
* configuration from resources and pre-defined size templates.
+ *
+ * Only appwidgets; no shortcuts
*/
@LauncherAppSingleton
-class ConfigResourceFeaturedWidgetsDataSource @Inject constructor(
+class ConfigResourceFeaturedWidgetsDataSource
+@Inject
+constructor(
@ApplicationContext private val appContext: Context,
- private val idp: InvariantDeviceProfile
+ private val idp: InvariantDeviceProfile,
) : FeaturedWidgetsDataSource {
// the package part in component name e.g. "com.example" in {com.example/widget.Provider}
private var eligiblePackages: Set<String> = emptySet()
override suspend fun initialize() {
if (eligiblePackages.isEmpty()) {
- eligiblePackages = Arrays.stream(
- appContext.resources.getStringArray(R.array.default_featured_widget_apps)
- ).collect(Collectors.toSet())
+ eligiblePackages =
+ Arrays.stream(
+ appContext.resources.getStringArray(R.array.default_featured_widget_apps)
+ )
+ .collect(Collectors.toSet())
}
}
override suspend fun getFeaturedWidgets(widgetApps: List<WidgetApp>): List<PickableWidget> {
- val widgetsByContainerSize = widgetApps
- .shuffled()
- // pick only one of user profiles
- .distinctBy { Pair(it.id.packageName, it.id.category) }
- .flatMap { it.widgets }
- .filter { eligiblePackages.contains(it.id.componentName.packageName) }
- .groupBy {
- WidgetPreviewContainerSize(
- it.sizeInfo.containerSpanX,
- it.sizeInfo.containerSpanY
- )
- }
+ val widgetsByContainerSize =
+ widgetApps
+ .shuffled()
+ // pick only one of user profiles
+ .distinctBy { Pair(it.id.packageName, it.id.category) }
+ .flatMap { it.widgets }
+ .filter {
+ eligiblePackages.isEmpty() ||
+ eligiblePackages.contains(it.id.componentName.packageName)
+ }
+ .groupBy {
+ WidgetPreviewContainerSize(
+ it.sizeInfo.containerSpanX,
+ it.sizeInfo.containerSpanY,
+ )
+ }
val selected: MutableList<PickableWidget> = mutableListOf()
val usedAppIds: MutableSet<String> = mutableSetOf()
- val sizesToPick = WidgetPreviewContainerSize.pickTemplateForFeaturedWidgets(
- idp.getDeviceProfile(appContext)
- )
+ val sizesToPick =
+ WidgetPreviewContainerSize.pickTemplateForFeaturedWidgets(
+ idp.getDeviceProfile(appContext)
+ )
for (sizeToPick in sizesToPick) {
widgetsByContainerSize[sizeToPick]?.shuffled()?.let { items ->
for (item in items) {
- if (!usedAppIds.contains(item.appId.packageName)) {
+ if (
+ item.widgetInfo.isAppWidget() &&
+ !usedAppIds.contains(item.appId.packageName)
+ ) {
selected.add(item)
usedAppIds.add(item.appId.packageName)
break
diff --git a/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerAddItemListener.kt b/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerAddItemListener.kt
index 330b66a..988d016 100644
--- a/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerAddItemListener.kt
+++ b/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerAddItemListener.kt
@@ -16,14 +16,17 @@
package com.android.launcher3.widgetpicker.listeners
-import android.appwidget.AppWidgetProviderInfo
import android.view.View
import com.android.launcher3.Launcher
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY
+import com.android.launcher3.PendingAddItemInfo
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
+import com.android.launcher3.pm.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO
import com.android.launcher3.util.ContextTracker.SchedulerCallback
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.android.launcher3.widget.PendingAddShortcutInfo
import com.android.launcher3.widget.PendingAddWidgetInfo
+import com.android.launcher3.widgetpicker.shared.model.WidgetInfo
/**
* A callback listener (for tap-to-add flow) that handles adding a widget from a separate widget
@@ -31,26 +34,38 @@
*
* Also logs to stats logger once widget is added.
*/
-class WidgetPickerAddItemListener(private val providerInfo: AppWidgetProviderInfo) :
+class WidgetPickerAddItemListener(private val widgetInfo: WidgetInfo) :
SchedulerCallback<Launcher> {
override fun init(launcher: Launcher?, isHomeStarted: Boolean): Boolean {
checkNotNull(launcher)
- val launcherProviderInfo =
- LauncherAppWidgetProviderInfo.fromProviderInfo(launcher, providerInfo)
- val pendingAddWidgetInfo =
- PendingAddWidgetInfo(launcherProviderInfo, CONTAINER_WIDGETS_TRAY)
+ val pendingAddItemInfo: PendingAddItemInfo =
+ when (widgetInfo) {
+ is WidgetInfo.AppWidgetInfo -> {
+ val launcherProviderInfo =
+ LauncherAppWidgetProviderInfo.fromProviderInfo(
+ launcher,
+ widgetInfo.appWidgetProviderInfo,
+ )
+ PendingAddWidgetInfo(launcherProviderInfo, CONTAINER_WIDGETS_TRAY)
+ }
+
+ is WidgetInfo.ShortcutInfo ->
+ PendingAddShortcutInfo(
+ ShortcutConfigActivityInfoVO(widgetInfo.launcherActivityInfo)
+ )
+ }
val view = View(launcher)
- view.tag = pendingAddWidgetInfo
+ view.tag = pendingAddItemInfo
launcher.accessibilityDelegate?.addToWorkspace(
- /*item=*/ pendingAddWidgetInfo,
- /*accessibility=*/ false
+ /*item=*/ pendingAddItemInfo,
+ /*accessibility=*/ false,
) {
launcher.statsLogManager
.logger()
- .withItemInfo(pendingAddWidgetInfo)
+ .withItemInfo(pendingAddItemInfo)
.log(LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP)
}
return false // don't receive any more callbacks as we got launcher and handled it
diff --git a/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerDragItemListener.kt b/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerDragItemListener.kt
index 3b3e8c3..9d13b9b 100644
--- a/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerDragItemListener.kt
+++ b/compose/features/com/android/launcher3/widgetpicker/listeners/WidgetPickerDragItemListener.kt
@@ -16,72 +16,100 @@
package com.android.launcher3.widgetpicker.listeners
-import android.appwidget.AppWidgetProviderInfo
import android.graphics.Rect
import android.view.View
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY
+import com.android.launcher3.PendingAddItemInfo
import com.android.launcher3.dragndrop.BaseItemDragListener
+import com.android.launcher3.pm.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO
import com.android.launcher3.widget.DatabaseWidgetPreviewLoader.WidgetPreviewInfo
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.android.launcher3.widget.PendingAddShortcutInfo
import com.android.launcher3.widget.PendingAddWidgetInfo
import com.android.launcher3.widget.PendingItemDragHelper
+import com.android.launcher3.widgetpicker.shared.model.WidgetInfo
import com.android.launcher3.widgetpicker.shared.model.WidgetPreview
+import com.android.launcher3.widgetpicker.shared.model.isAppWidget
/**
* A callback listener of type [BaseItemDragListener] that handles widget drag and drop from widget
* picker hosted in a separate activity than home screen.
*
- * Responsible for initializing the [PendingItemDragHelper] that then handles the rest of the
- * drag and drop (including showing a drag shadow for the widget).
+ * Responsible for initializing the [PendingItemDragHelper] that then handles the rest of the drag
+ * and drop (including showing a drag shadow for the widget).
*
* @param mimeType a mime type used by widget picker when attaching this listener for a specific
- * widget's drag and drop session.
- * @param appWidgetProviderInfo provider info of the widget being dragged
+ * widget's drag and drop session.
+ * @param widgetInfo metadata of the widget being dragged
+ * @param widgetPreview provides the preview information for widgets
* @param previewRect the bounds of widget's preview offset by the point of long press
* @param previewWidth width of the preview as it appears in the widget picker.
*/
class WidgetPickerDragItemListener(
private val mimeType: String,
- private val appWidgetProviderInfo: AppWidgetProviderInfo,
+ private val widgetInfo: WidgetInfo,
private val widgetPreview: WidgetPreview,
previewRect: Rect,
- previewWidth: Int
+ previewWidth: Int,
) : BaseItemDragListener(previewRect, previewWidth, previewWidth) {
override fun getMimeType(): String = mimeType
override fun createDragHelper(): PendingItemDragHelper {
- val launcherProviderInfo =
- LauncherAppWidgetProviderInfo.fromProviderInfo(mLauncher, appWidgetProviderInfo)
- val pendingAddWidgetInfo =
- PendingAddWidgetInfo(launcherProviderInfo, CONTAINER_WIDGETS_TRAY)
+ val pendingAddItemInfo: PendingAddItemInfo =
+ when (widgetInfo) {
+ is WidgetInfo.AppWidgetInfo -> {
+ val launcherProviderInfo =
+ LauncherAppWidgetProviderInfo.fromProviderInfo(
+ mLauncher,
+ widgetInfo.appWidgetProviderInfo,
+ )
+ PendingAddWidgetInfo(launcherProviderInfo, CONTAINER_WIDGETS_TRAY)
+ }
+
+ is WidgetInfo.ShortcutInfo ->
+ PendingAddShortcutInfo(
+ ShortcutConfigActivityInfoVO(widgetInfo.launcherActivityInfo)
+ )
+ }
val view = View(mLauncher)
- view.tag = pendingAddWidgetInfo
+ view.tag = pendingAddItemInfo
val dragHelper = PendingItemDragHelper(view)
+ if (widgetInfo.isAppWidget()) {
+ setAppWidgetPreviewInfo(widgetPreview, widgetInfo, dragHelper)
+ } // shortcut preview is fetched by home screen.
+
+ return dragHelper
+ }
+
+ private fun setAppWidgetPreviewInfo(
+ appWidgetPreview: WidgetPreview,
+ widgetInfo: WidgetInfo.AppWidgetInfo,
+ dragHelper: PendingItemDragHelper,
+ ) {
val info = WidgetPreviewInfo()
- when (widgetPreview) {
+ when (appWidgetPreview) {
is WidgetPreview.BitmapWidgetPreview -> {
- info.previewBitmap = widgetPreview.bitmap
- info.providerInfo = appWidgetProviderInfo
+ info.previewBitmap = appWidgetPreview.bitmap
+ info.providerInfo = widgetInfo.appWidgetProviderInfo
}
is WidgetPreview.ProviderInfoWidgetPreview -> {
- info.providerInfo = widgetPreview.providerInfo
+ info.providerInfo = appWidgetPreview.providerInfo
}
is WidgetPreview.RemoteViewsWidgetPreview -> {
- info.remoteViews = widgetPreview.remoteViews
- info.providerInfo = appWidgetProviderInfo
+ info.remoteViews = appWidgetPreview.remoteViews
+ info.providerInfo = widgetInfo.appWidgetProviderInfo
}
- else -> throw IllegalStateException(
- "Unsupported preview type when dropping widget to launcher"
- )
+ else ->
+ throw IllegalStateException(
+ "Unsupported preview type when dropping widget to launcher"
+ )
}
dragHelper.setWidgetPreviewInfo(info)
-
- return dragHelper
}
}
diff --git a/compose/features/com/android/launcher3/widgetpicker/repository/WidgetsRepositoryImpl.kt b/compose/features/com/android/launcher3/widgetpicker/repository/WidgetsRepositoryImpl.kt
index a49fbc4..23ab585 100644
--- a/compose/features/com/android/launcher3/widgetpicker/repository/WidgetsRepositoryImpl.kt
+++ b/compose/features/com/android/launcher3/widgetpicker/repository/WidgetsRepositoryImpl.kt
@@ -24,6 +24,7 @@
import com.android.launcher3.model.WidgetItem
import com.android.launcher3.model.WidgetsModel
import com.android.launcher3.model.data.PackageItemInfo
+import com.android.launcher3.pm.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.widget.DatabaseWidgetPreviewLoader
@@ -36,8 +37,11 @@
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 javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
@@ -51,76 +55,73 @@
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import javax.inject.Inject
-import kotlin.coroutines.CoroutineContext
/**
* An implementation of the [WidgetsRepository] that provides widgets for widget picker using the
* [WidgetsModel], [FeaturedWidgetsDataSource] & enables search using the provided
* [WidgetsSearchAlgorithm].
*/
-class WidgetsRepositoryImpl @Inject constructor(
+class WidgetsRepositoryImpl
+@Inject
+constructor(
@ApplicationContext private val appContext: Context,
idp: InvariantDeviceProfile,
private val widgetsModel: WidgetsModel,
private val featuredWidgetsDataSource: FeaturedWidgetsDataSource,
private val searchAlgorithm: WidgetsSearchAlgorithm,
- @BackgroundContext
- private val backgroundContext: CoroutineContext,
+ @BackgroundContext private val backgroundContext: CoroutineContext,
) : WidgetsRepository {
private val deviceProfile = idp.getDeviceProfile(appContext)
- private val backgroundScope = CoroutineScope(
- SupervisorJob() + backgroundContext + CoroutineName("WidgetsRepository")
- )
+ private val backgroundScope =
+ CoroutineScope(SupervisorJob() + backgroundContext + CoroutineName("WidgetsRepository"))
- private val _widgetItemsByPackage =
- MutableStateFlow<List<WidgetApp>>(emptyList())
+ private val _widgetItemsByPackage = MutableStateFlow<List<WidgetApp>>(emptyList())
private val databaseWidgetPreviewLoader = DatabaseWidgetPreviewLoader(appContext, deviceProfile)
override fun initialize() {
// TODO(b/419495339): Remove the model executor requirement from widgets model and replace
// with scope.launch
MODEL_EXECUTOR.execute {
- widgetsModel.update(/*packageUser=*/ null)
+ widgetsModel.update(/* packageUser= */ null)
_widgetItemsByPackage.update {
widgetsModel.widgetsByPackageItemForPicker.toPickableWidgets(deviceProfile)
}
}
- backgroundScope.launch {
- featuredWidgetsDataSource.initialize()
- }
+ backgroundScope.launch { featuredWidgetsDataSource.initialize() }
}
override fun observeWidgets(): Flow<List<WidgetApp>> = _widgetItemsByPackage.asStateFlow()
override suspend fun getWidgetPreview(id: WidgetId): WidgetPreview {
val componentKey = ComponentKey(id.componentName, id.userHandle)
- val widgetItem = widgetsModel.widgetsByComponentKey[componentKey]
- ?: return WidgetPreview.PlaceholderWidgetPreview
+ val widgetItem =
+ widgetsModel.widgetsByComponentKey[componentKey]
+ ?: return WidgetPreview.PlaceholderWidgetPreview
val previewSizePx =
WidgetSizes.getWidgetSizePx(deviceProfile, widgetItem.spanX, widgetItem.spanY)
- val preview = withContext(backgroundContext) {
- val result =
- databaseWidgetPreviewLoader.generatePreviewInfoBg(
- widgetItem,
- previewSizePx.width,
- previewSizePx.height
- )
- when {
- result.remoteViews != null ->
- WidgetPreview.RemoteViewsWidgetPreview(result.remoteViews)
+ val preview =
+ withContext(backgroundContext) {
+ val result =
+ databaseWidgetPreviewLoader.generatePreviewInfoBg(
+ widgetItem,
+ previewSizePx.width,
+ previewSizePx.height,
+ )
+ when {
+ result.remoteViews != null ->
+ WidgetPreview.RemoteViewsWidgetPreview(result.remoteViews)
- result.providerInfo != null ->
- WidgetPreview.ProviderInfoWidgetPreview(result.providerInfo)
+ result.providerInfo != null ->
+ WidgetPreview.ProviderInfoWidgetPreview(result.providerInfo)
- result.previewBitmap != null ->
- WidgetPreview.BitmapWidgetPreview(result.previewBitmap)
+ result.previewBitmap != null ->
+ WidgetPreview.BitmapWidgetPreview(result.previewBitmap)
- else -> WidgetPreview.PlaceholderWidgetPreview
+ else -> WidgetPreview.PlaceholderWidgetPreview
+ }
}
- }
return preview
}
@@ -138,29 +139,32 @@
}
override fun getFeaturedWidgets(): Flow<List<PickableWidget>> {
- return _widgetItemsByPackage.map { widgets ->
- featuredWidgetsDataSource.getFeaturedWidgets(widgets)
- }.flowOn(backgroundContext)
+ return _widgetItemsByPackage
+ .map { widgets -> featuredWidgetsDataSource.getFeaturedWidgets(widgets) }
+ .flowOn(backgroundContext)
}
companion object {
- private fun Map<PackageItemInfo, List<WidgetItem>>.toPickableWidgets(deviceProfile: DeviceProfile) =
- map { (packageItemInfo, widgetItems) ->
- val widgetAppId = WidgetAppId(
+ private fun Map<PackageItemInfo, List<WidgetItem>>.toPickableWidgets(
+ deviceProfile: DeviceProfile
+ ) = map { (packageItemInfo, widgetItems) ->
+ val widgetAppId =
+ WidgetAppId(
packageName = packageItemInfo.packageName,
userHandle = packageItemInfo.user,
- category = packageItemInfo.widgetCategory
+ category = packageItemInfo.widgetCategory,
)
- WidgetApp(
- id = widgetAppId,
- title = packageItemInfo.title,
- widgets = widgetItems.filter { it.widgetInfo != null }.map { widgetItem ->
+ WidgetApp(
+ id = widgetAppId,
+ title = packageItemInfo.title,
+ widgets =
+ widgetItems.map { widgetItem ->
val previewSize =
WidgetSizes.getWidgetSizePx(
deviceProfile,
widgetItem.spanX,
- widgetItem.spanY
+ widgetItem.spanY,
)
val containerSpan =
WidgetPreviewContainerSize.forItem(widgetItem, deviceProfile)
@@ -168,31 +172,43 @@
WidgetSizes.getWidgetSizePx(
deviceProfile,
containerSpan.spanX,
- containerSpan.spanY
+ containerSpan.spanY,
)
PickableWidget(
- id = WidgetId(
- componentName = widgetItem.componentName,
- userHandle = widgetItem.user
- ),
+ id =
+ WidgetId(
+ componentName = widgetItem.componentName,
+ userHandle = widgetItem.user,
+ ),
appId = widgetAppId,
label = widgetItem.label,
description = widgetItem.description,
- appWidgetProviderInfo = widgetItem.widgetInfo.clone(),
- sizeInfo = WidgetSizeInfo(
- spanX = widgetItem.widgetInfo.spanX,
- spanY = widgetItem.widgetInfo.spanY,
- widthPx = previewSize.width,
- heightPx = previewSize.height,
- containerSpanX = containerSpan.spanX,
- containerSpanY = containerSpan.spanY,
- containerWidthPx = containerSize.width,
- containerHeightPx = containerSize.height
- )
+ widgetInfo =
+ if (widgetItem.widgetInfo != null) {
+ WidgetInfo.AppWidgetInfo(
+ appWidgetProviderInfo = widgetItem.widgetInfo.clone()
+ )
+ } else {
+ check(widgetItem.activityInfo is ShortcutConfigActivityInfoVO)
+ WidgetInfo.ShortcutInfo(
+ launcherActivityInfo = widgetItem.activityInfo.mInfo
+ )
+ },
+ sizeInfo =
+ WidgetSizeInfo(
+ spanX = widgetItem.spanX,
+ spanY = widgetItem.spanY,
+ widthPx = previewSize.width,
+ heightPx = previewSize.height,
+ containerSpanX = containerSpan.spanX,
+ containerSpanY = containerSpan.spanY,
+ containerWidthPx = containerSize.width,
+ containerHeightPx = containerSize.height,
+ ),
)
- }
- )
- }
+ },
+ )
+ }
}
}
diff --git a/compose/tests/com/android/launcher3/widget/AddWidgetConfigTest.kt b/compose/tests/com/android/launcher3/widget/AddWidgetConfigTest.kt
index 73daacd..288604f 100644
--- a/compose/tests/com/android/launcher3/widget/AddWidgetConfigTest.kt
+++ b/compose/tests/com/android/launcher3/widget/AddWidgetConfigTest.kt
@@ -34,6 +34,7 @@
import com.android.launcher3.util.ui.TestViewHelpers
import com.android.launcher3.util.workspace.FavoriteItemsTransaction
import com.android.launcher3.widgetpicker.listeners.WidgetPickerAddItemListener
+import com.android.launcher3.widgetpicker.shared.model.WidgetInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -83,10 +84,10 @@
// Add widget to home screen
val monitor = WidgetConfigStartupMonitor()
- launcherActivity.executeOnLauncher({ l: Launcher ->
- val addItemListener = WidgetPickerAddItemListener(widgetInfo)
+ launcherActivity.executeOnLauncher { l: Launcher ->
+ val addItemListener = WidgetPickerAddItemListener(WidgetInfo.AppWidgetInfo(widgetInfo))
addItemListener.init(l, /* isHomeStarted= */ true)
- })
+ }
uiDevice.waitForIdle()
diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/domain/usecase/FilterWidgetsForHostUseCase.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/domain/usecase/FilterWidgetsForHostUseCase.kt
index 07de348..45f7427 100644
--- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/domain/usecase/FilterWidgetsForHostUseCase.kt
+++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/domain/usecase/FilterWidgetsForHostUseCase.kt
@@ -21,8 +21,9 @@
import com.android.launcher3.widgetpicker.shared.model.HostConstraint
import com.android.launcher3.widgetpicker.shared.model.PickableWidget
import com.android.launcher3.widgetpicker.shared.model.WidgetHostInfo
+import com.android.launcher3.widgetpicker.shared.model.isAppWidget
+import com.android.launcher3.widgetpicker.shared.model.isShortcut
import javax.inject.Inject
-import javax.inject.Named
/**
* A usecase that hosts the business logic of filtering widgets based on host constraints and
@@ -34,16 +35,28 @@
constructor(@WidgetPickerHostInfo private val hostInfo: WidgetHostInfo) {
operator fun invoke(widgets: List<PickableWidget>) =
widgets.filter { widget ->
+ val widgetInfo = widget.widgetInfo
+
val eligibleForHost =
hostInfo.constraints.all { constraint ->
when (constraint) {
+ is HostConstraint.NoShortcutsConstraint -> !widgetInfo.isShortcut()
+
is HostConstraint.HostUserConstraint ->
!constraint.userFilters.contains(widget.id.userHandle)
is HostConstraint.HostCategoryConstraint -> {
- val widgetCategory = widget.appWidgetProviderInfo.widgetCategory
- matchesCategory(constraint.categoryInclusionMask, widgetCategory) &&
- matchesCategory(constraint.categoryExclusionMask, widgetCategory)
+ // category applies only to widgets
+ if (widgetInfo.isAppWidget()) {
+ val widgetCategory = widgetInfo.appWidgetProviderInfo.widgetCategory
+ matchesCategory(constraint.categoryInclusionMask, widgetCategory) &&
+ matchesCategory(
+ constraint.categoryExclusionMask,
+ widgetCategory,
+ )
+ } else {
+ true
+ }
}
}
}
diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/PickableWidget.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/PickableWidget.kt
index 75cee6a..146692e 100644
--- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/PickableWidget.kt
+++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/PickableWidget.kt
@@ -17,6 +17,11 @@
package com.android.launcher3.widgetpicker.shared.model
import android.appwidget.AppWidgetProviderInfo
+import android.content.pm.LauncherActivityInfo
+import com.android.launcher3.widgetpicker.shared.model.WidgetInfo.AppWidgetInfo
+import com.android.launcher3.widgetpicker.shared.model.WidgetInfo.ShortcutInfo
+import kotlin.contracts.ExperimentalContracts
+import kotlin.contracts.contract
/**
* Raw information about a widget that can be considered for display in widget picker list.
@@ -28,22 +33,22 @@
* @property appId a unique identifier for the app group that this widget could belong to
* @property label a user friendly label for the widget.
* @property description a user friendly description for the widget
- * @property appWidgetProviderInfo widget info associated with the widget as configured by the
- * developer; note: this should be a local clone and not the object that was received from
- * appwidget manager.
+ * @property widgetInfo info associated with the widget as configured by the developer shared with
+ * host when adding a widget; note: this should be a local clone and not the object that was
+ * received from appwidget manager or package manager.
*/
data class PickableWidget(
val id: WidgetId,
val appId: WidgetAppId,
val label: String,
val description: CharSequence?,
- val appWidgetProviderInfo: AppWidgetProviderInfo,
+ val widgetInfo: WidgetInfo,
val sizeInfo: WidgetSizeInfo,
) {
// Custom toString to account for the appWidgetProviderInfo.
override fun toString(): String =
"PickableWidget(id=$id,appId=$appId,label=$label,description=$description," +
- "sizeInfo=$sizeInfo,provider=${appWidgetProviderInfo.provider})"
+ "sizeInfo=$sizeInfo,widgetInfo=${widgetInfo})"
}
/**
@@ -73,3 +78,40 @@
val containerWidthPx: Int,
val containerHeightPx: Int,
)
+
+/** Information of the widget as configured by the developer. */
+sealed class WidgetInfo {
+ /**
+ * @param appWidgetProviderInfo metadata of an installed widgets as received from the appwidget
+ * manager.
+ */
+ data class AppWidgetInfo(val appWidgetProviderInfo: AppWidgetProviderInfo) : WidgetInfo()
+
+ /**
+ * @param launcherActivityInfo metadata of an installed deep shortcut as received from the
+ * package manager.
+ */
+ data class ShortcutInfo(val launcherActivityInfo: LauncherActivityInfo) : WidgetInfo()
+
+ override fun toString(): String {
+ when (this) {
+ is AppWidgetInfo -> "WidgetInfo(provider=${this.appWidgetProviderInfo.provider})"
+ is ShortcutInfo -> "WidgetInfo(activityInfo=${this.launcherActivityInfo.componentName})"
+ }
+ return super.toString()
+ }
+}
+
+/** Returns true if the info is about an app widget. */
+@OptIn(ExperimentalContracts::class)
+fun WidgetInfo.isAppWidget(): Boolean {
+ contract { returns(true) implies (this@isAppWidget is AppWidgetInfo) }
+ return this is AppWidgetInfo
+}
+
+/** Returns true if the info is about a deep shortcut. */
+@OptIn(ExperimentalContracts::class)
+fun WidgetInfo.isShortcut(): Boolean {
+ contract { returns(true) implies (this@isShortcut is ShortcutInfo) }
+ return this is ShortcutInfo
+}
diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/WidgetHostInfo.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/WidgetHostInfo.kt
index 3622f9f..f6b1249 100644
--- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/WidgetHostInfo.kt
+++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/shared/model/WidgetHostInfo.kt
@@ -23,17 +23,17 @@
*
* @param title an optional title that should be shown in place of default "Widgets" title.
* @param description an optional 1-2 line description to be shown below the title. If not set, no
- * description is shown.
+ * description is shown.
* @param constraints constraints around which widgets can be shown in the picker.
* @param showDragShadow indicates whether to show drag shadow for the widgets when dragging them;
- * can be set to false if host manages drag shadow on its own (e.g. home screen to animate the
- * shadow with actual content)
+ * can be set to false if host manages drag shadow on its own (e.g. home screen to animate the
+ * shadow with actual content)
*/
data class WidgetHostInfo(
val title: String? = null,
val description: String? = null,
val constraints: List<HostConstraint> = emptyList(),
- val showDragShadow: Boolean = true
+ val showDragShadow: Boolean = true,
)
/** Various constraints for the widget host. */
@@ -60,4 +60,7 @@
* such case, the profile tab shows a generic no widgets available message.
*/
data class HostUserConstraint(val userFilters: List<UserHandle>) : HostConstraint()
+
+ /** Indicates that the host doesn't support shortcuts. */
+ data object NoShortcutsConstraint : HostConstraint()
}
diff --git a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/WidgetPickerEventListeners.kt b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/WidgetPickerEventListeners.kt
index 9973b79..e515e22 100644
--- a/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/WidgetPickerEventListeners.kt
+++ b/modules/widgetpicker/src/com/android/launcher3/widgetpicker/ui/WidgetPickerEventListeners.kt
@@ -16,13 +16,13 @@
package com.android.launcher3.widgetpicker.ui
-import android.appwidget.AppWidgetProviderInfo
import android.graphics.Rect
+import com.android.launcher3.widgetpicker.shared.model.WidgetInfo
import com.android.launcher3.widgetpicker.shared.model.WidgetPreview
/**
- * General interface that clients can implement to listen to events from different types of
- * widget picker.
+ * General interface that clients can implement to listen to events from different types of widget
+ * picker.
*/
interface WidgetPickerEventListeners {
/** Called when the widget picker is dismissed. */
@@ -37,7 +37,7 @@
/**
* Information passed in event listener when a widget is dragged.
*
- * @param providerInfo metadata for the provider of the widget being dragged.
+ * @param widgetInfo metadata for the provider of the widget being dragged.
* @param bounds current bounds of the widget's preview considering the drag offset and scale.
* @param widthPx measured width of the preview.
* @param heightPx measured height of the preview.
@@ -45,7 +45,7 @@
* @param mimeType a unique mime type set on clip data for the drag session
*/
data class WidgetDragInfo(
- val providerInfo: AppWidgetProviderInfo,
+ val widgetInfo: WidgetInfo,
val bounds: Rect,
val widthPx: Int,
val heightPx: Int,
@@ -56,9 +56,7 @@
/**
* Information passed in event listener when a widget is added using tap to add.
*
- * @param providerInfo metadata for the provider of the widget being added.
+ * @param widgetInfo metadata for the provider of the widget being added.
*/
- data class WidgetAddInfo(
- val providerInfo: AppWidgetProviderInfo
- ) : WidgetInteractionInfo()
+ data class WidgetAddInfo(val widgetInfo: WidgetInfo) : WidgetInteractionInfo()
}
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 309eb0f..8dc7938 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.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 @@
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 4edcdfd..0ad64f8 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.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 @@
) {
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 @@
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 @@
}
@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 @@
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 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 7977dd2..2647ef7 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.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 @@
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 @@
}
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 @@
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 @@
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 BitmapWidgetPreview(
bitmap: Bitmap,
size: DpSize,
- widgetInfo: AppWidgetProviderInfo,
+ widgetInfo: WidgetInfo,
widgetRadius: Dp,
showDragShadow: Boolean,
onWidgetInteraction: (WidgetInteractionInfo) -> Unit,
@@ -170,22 +175,24 @@
val density = LocalDensity.current
val haptic = LocalHapticFeedback.current
- 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 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
+ },
+ )
+ }
+ }
var imagePositionInParent by remember { mutableStateOf(Offset.Zero) }
@@ -199,8 +206,7 @@
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 @@
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 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 @@
// 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 @@
scaledSizePx = scaledPxSize,
scaledSizeDp = scaledDpSize,
scaledRadiusDp = scaledRadius,
- scaledRadiusPx = scaledRadius.toPx()
+ scaledRadiusPx = scaledRadius.toPx(),
)
}
@@ -298,7 +296,7 @@
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 @@
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 @@
// 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 5e0ecf8..4426ab7 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 @@
* @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 @@
addButtonWidgetId = addButtonWidgetId,
onWidgetInteraction = onWidgetInteraction,
onAddButtonToggle = { id ->
- addButtonWidgetId = if (id != addButtonWidgetId) {
- id
- } else {
- null
- }
- }
+ addButtonWidgetId =
+ if (id != addButtonWidgetId) {
+ id
+ } else {
+ null
+ }
+ },
)
}
}
@@ -155,7 +156,7 @@
appIcons = appIcons,
addButtonWidgetId = addButtonWidgetId,
onWidgetInteraction = onWidgetInteraction,
- onAddButtonToggle = onAddButtonToggle
+ onAddButtonToggle = onAddButtonToggle,
)
},
previewContainerWidthPx = widgetSizeGroup.previewContainerWidthPx,
@@ -184,21 +185,19 @@
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 @@
addButtonWidgetId: WidgetId?,
appIcons: Map<WidgetAppId, WidgetAppIcon>,
onWidgetInteraction: (WidgetInteractionInfo) -> Unit,
- onAddButtonToggle: (WidgetId) -> Unit
+ onAddButtonToggle: (WidgetId) -> Unit,
) {
widgets.forEachIndexed { index, widgetItem ->
val appId = widgetItem.appId
@@ -376,8 +375,8 @@
// 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 f86e0ab..29a15ca 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 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 @@
containerWidthPx = cellWidth,
containerHeightPx = cellHeight,
),
- appWidgetProviderInfo = newAppWidgetInfo("OneByOneProvider"),
+ widgetInfo = WidgetInfo.AppWidgetInfo(newAppWidgetInfo("OneByOneProvider")),
)
private fun twoByTwo(cellWidth: Int, cellHeight: Int) =
@@ -262,7 +263,7 @@
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 @@
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 @@
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 d656701..890191b 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.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 @@
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 6e2fb01..83991fa 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 @@
@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<ComponentActivity>()
+ @get:Rule val composeTestRule = createAndroidComposeRule<ComponentActivity>()
@Test
fun tapPreview_andClickAdd() {
@@ -66,7 +64,8 @@
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 @@
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 @@
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 @@
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 @@
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 @@
showDragShadow = false,
onWidgetInteraction = { widgetInteractionInfo ->
if (widgetInteractionInfo is WidgetInteractionInfo.WidgetAddInfo) {
- provider = widgetInteractionInfo.providerInfo.provider.toString()
+ provider = widgetInteractionInfo.widgetInfo.toString()
}
},
)
@@ -160,16 +163,18 @@
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"
diff --git a/res/values/config.xml b/res/values/config.xml
index 05f489c..674b093 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -139,13 +139,6 @@
<string-array name="filtered_components" ></string-array>
<string-array name="default_featured_widget_apps" translatable="false">
- <item>com.google.android.calendar</item>
- <item>com.google.android.deskclock</item>
- <item>com.google.android.apps.maps</item>
- <item>com.google.android.contacts</item>
- <item>com.google.android.apps.chromecast.app</item>
- <item>com.google.android.gm</item>
- <item>com.google.android.videos</item>
</string-array>
<!-- Swipe back to home related -->
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 89c6351..8a76f85 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -635,7 +636,8 @@
// When widgets are dropped from another window, we don't want to remove the
// dragView on resume of launcher.
if (Flags.enableWidgetPickerRefactor()
- && ((DragView<?>) child).mItemType != ITEM_TYPE_APPWIDGET) {
+ && ((DragView<?>) child).mItemType != ITEM_TYPE_APPWIDGET
+ && ((DragView<?>) child).mItemType != ITEM_TYPE_DEEP_SHORTCUT) {
dragLayer.removeView(child);
}
}
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index 409174e..235a46c 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -134,7 +134,7 @@
@TargetApi(26)
public static class ShortcutConfigActivityInfoVO extends ShortcutConfigActivityInfo {
- private final LauncherActivityInfo mInfo;
+ public final LauncherActivityInfo mInfo;
public ShortcutConfigActivityInfoVO(LauncherActivityInfo info) {
super(info.getComponentName(), info.getUser(),
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 55404d6..48f75c7 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -51,7 +51,6 @@
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.util.WidgetSizes;
import java.util.concurrent.ExecutionException;
@@ -272,8 +271,7 @@
private Bitmap generateShortcutPreview(
ShortcutConfigActivityInfo info, int maxWidth, int maxHeight) {
- int iconSize = ActivityContext.lookupContext(
- mContext).getDeviceProfile().getAllAppsProfile().getIconSizePx();
+ int iconSize = mDeviceProfile.getAllAppsProfile().getIconSizePx();
int padding = mContext.getResources()
.getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);