diff --git a/flexera/res/values/flexera_strings.xml b/flexera/res/values/flexera_strings.xml index 992554af03..6be25043c7 100644 --- a/flexera/res/values/flexera_strings.xml +++ b/flexera/res/values/flexera_strings.xml @@ -97,6 +97,9 @@ %1$s is hidden Blur behind open folders + + Line up with icons + The edges of every widget meet the edges of the icons above, below and beside it Blurs the home screen while a folder is open Quick launch Swipe on from the first or the last home screen page, as if there were one more, to open an app or do something else. Has no effect while Infinite scrolling is on. diff --git a/flexera/src/app/flexera/widget/FlexeraWidgets.kt b/flexera/src/app/flexera/widget/FlexeraWidgets.kt index 9bef202a14..a3132cbadd 100644 --- a/flexera/src/app/flexera/widget/FlexeraWidgets.kt +++ b/flexera/src/app/flexera/widget/FlexeraWidgets.kt @@ -5,9 +5,13 @@ import android.content.ComponentName import android.graphics.Rect import android.view.View import android.widget.FrameLayout +import com.android.launcher3.DeviceProfile +import com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR import com.android.launcher3.model.data.LauncherAppWidgetInfo import com.android.launcher3.widget.LauncherAppWidgetHostView import com.android.launcher3.widget.PendingAppWidgetHostView +import kotlin.math.max +import kotlin.math.roundToInt /** * The widgets that come with the launcher: Pictures ([PictureWidgetProvider]) and Clock @@ -16,7 +20,8 @@ import com.android.launcher3.widget.PendingAppWidgetHostView * Android knows each as an ordinary app widget, so they are added, moved, resized and removed * like any other. What they show is not sent through Android, though: the launcher draws them * itself with a view of its own, which is what lets them line up with the icons ([IconFrame]). - * This is where Launcher3's widget code asks about them. + * This is where Launcher3's widget code asks about them, and about the room every other widget + * keeps in its cells, which by default lines those up with the icons as well. */ object FlexeraWidgets { @@ -26,14 +31,54 @@ object FlexeraWidgets { provider == PictureWidgetProvider.componentName || provider == ClockWidgetProvider.componentName /** - * The room a home screen cell keeps free around a widget. Launcher3 gives every widget the - * same ([standard]); the launcher's own take none, because they place what they draw - * against the icons of their cells by themselves. + * The room a widget's cells keep free around it, on each side; one cell is [cellWidth] by + * [cellHeight]. The launcher's own widgets take none, because they place what they draw + * against the icons of their cells by themselves ([IconFrame]); every other widget gets + * [appWidgetPadding]. */ @JvmStatic - fun cellInset(child: View, standard: Rect): Rect { - val info = child.tag as? LauncherAppWidgetInfo ?: return standard - return if (isOwn(info.providerName)) noInset else standard + fun cellInset(child: View, profile: DeviceProfile, cellWidth: Int, cellHeight: Int): Rect { + val info = child.tag as? LauncherAppWidgetInfo + if (info != null && isOwn(info.providerName)) return noInset + return appWidgetPadding(profile, cellWidth, cellHeight) + } + + /** [appWidgetPadding] for the cells of [profile]'s home screen. */ + @JvmStatic + fun appWidgetPadding(profile: DeviceProfile): Rect { + val cell = profile.cellSize + return appWidgetPadding(profile, cell.x, cell.y) + } + + /** + * The room a widget of another app keeps free inside its cells, on each side, where one + * cell is [cellWidth] by [cellHeight]. Lined up with the icons (the default), it is the + * distance from the cells' edges to the edges of the icons that would sit in them: the + * same box the launcher's own widgets draw in ([IconFrame]), so that every widget's edges + * meet the edges of the icons above, below and beside it. Otherwise it is Launcher3's own, + * which the Widget padding setting scales. + */ + @JvmStatic + fun appWidgetPadding(profile: DeviceProfile, cellWidth: Int, cellHeight: Int): Rect { + if (!profile.alignWidgetsWithIcons || cellWidth <= 0 || cellHeight <= 0) { + return profile.widgetPadding + } + // As in IconFrame: the icon is centred sideways in its cell and sits a set distance + // below the cell's top; what is seen of it leaves a little air inside its square. + val icon = profile.iconSizePx.toFloat() + val air = icon * (1f - ICON_VISIBLE_AREA_FACTOR) / 2f + val iconTop = if (profile.cellYPaddingPx >= 0) { + profile.cellYPaddingPx.toFloat() + } else { + max(0f, (cellHeight - profile.cellHeightPx) / 2f) + } + val side = max(0, ((cellWidth - icon) / 2f + air).roundToInt()) + return Rect( + side, + max(0, (iconTop + air).roundToInt()), + side, + max(0, (cellHeight - iconTop - icon + air).roundToInt()), + ) } /** diff --git a/flexera/src/app/flexera/widget/IconFrame.kt b/flexera/src/app/flexera/widget/IconFrame.kt index 95c45fd2ae..e2c4d7f7e2 100644 --- a/flexera/src/app/flexera/widget/IconFrame.kt +++ b/flexera/src/app/flexera/widget/IconFrame.kt @@ -41,7 +41,8 @@ internal class IconFrame private constructor( // The cells the widget covers, measured from the corner of the host view. Undoes // what CellLayoutLayoutParams.setup took off them. - val inset = FlexeraWidgets.cellInset(host, profile.widgetPadding) + val cell = profile.cellSize + val inset = FlexeraWidgets.cellInset(host, profile, cell.x, cell.y) val spanLeft = -(lp.leftMargin + inset.left).toFloat() val spanTop = -(lp.topMargin + inset.top).toFloat() val spanWidth = (lp.width + lp.leftMargin + lp.rightMargin + inset.left + inset.right).toFloat() diff --git a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt index f9ddae8435..598a7584a7 100644 --- a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt +++ b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt @@ -886,6 +886,15 @@ class PreferenceManager2 @Inject constructor( defaultValue = GestureHandlerConfig.NoOp, ) + // Flexera Launcher: whether the edges of every widget meet the edges of the icons in the + // rows and columns it covers, as the launcher's own widgets do + // (app.flexera.widget.FlexeraWidgets.appWidgetPadding). Read with the grid. + val alignWidgetsWithIcons = preference( + key = booleanPreferencesKey(name = "flexera_align_widgets_with_icons"), + defaultValue = true, + onSet = { reloadHelper.reloadGrid() }, + ) + // Flexera Launcher: whether the home screen behind an open folder is blurred // (app.flexera.home.FolderBlur). Read when a folder opens, so nothing has to be reloaded. val folderBlur = preference( diff --git a/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenPreferences.kt index 875c987381..52ab0fdf71 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenPreferences.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/destinations/HomeScreenPreferences.kt @@ -285,13 +285,23 @@ fun HomeScreenPreferences( label = stringResource(id = R.string.force_widget_resize_label), description = stringResource(id = R.string.force_widget_resize_description), ) - SliderPreference( - label = stringResource(id = R.string.widget_padding_label), - adapter = prefs2.widgetPaddingFactor.getAdapter(), - step = 0.05f, - valueRange = 0F..2F, - showAsPercentage = true, + // Flexera Launcher: widgets lined up with the icons; Lawnchair's padding is for + // when they are not (app.flexera.widget.FlexeraWidgets.appWidgetPadding). + val alignWidgetsAdapter = prefs2.alignWidgetsWithIcons.getAdapter() + SwitchPreference( + adapter = alignWidgetsAdapter, + label = stringResource(id = R.string.flexera_align_widgets), + description = stringResource(id = R.string.flexera_align_widgets_description), ) + ExpandAndShrink(visible = !alignWidgetsAdapter.state.value) { + SliderPreference( + label = stringResource(id = R.string.widget_padding_label), + adapter = prefs2.widgetPaddingFactor.getAdapter(), + step = 0.05f, + valueRange = 0F..2F, + showAsPercentage = true, + ) + } } } } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 2bf7f0ce2f..27bda4a4b9 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -349,6 +349,8 @@ public class DeviceProfile { private float workspacePaddingHorizontalFactor; private float workspacePaddingVerticalFactor; private float widgetPaddingFactor; + // Flexera Launcher: widgets lined up with the icons (app.flexera.widget.FlexeraWidgets). + public boolean alignWidgetsWithIcons; private float drawerPaddingTopFactor; private PreferenceManager2 preferenceManager2 = null; @@ -373,6 +375,8 @@ public class DeviceProfile { .firstCached(preferenceManager2.getWorkspacePaddingVerticalFactor()), 0f, 2f); widgetPaddingFactor = Utilities.boundToRange(PreferenceCacheExtensionsKt .firstCached(preferenceManager2.getWidgetPaddingFactor()), 0f, 2f); + alignWidgetsWithIcons = PreferenceCacheExtensionsKt + .firstCached(preferenceManager2.getAlignWidgetsWithIcons()); drawerPaddingTopFactor = Utilities.boundToRange(PreferenceCacheExtensionsKt .firstCached(preferenceManager2.getDrawerPaddingTopFactor()), 1f, 2f); this.inv = inv; diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index 98bcd05f75..cc14fee0dd 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -151,9 +151,10 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag()); lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, appWidgetScale.x, appWidgetScale.y, mBorderSpace, - // Flexera Launcher: the launcher's own widgets take their cells whole. - app.flexera.widget.FlexeraWidgets.cellInset(child, - profile.widgetPadding)); + // Flexera Launcher: the launcher's own widgets take their cells whole; + // the others are lined up with the icons. + app.flexera.widget.FlexeraWidgets.cellInset(child, profile, + mCellWidth, mCellHeight)); } else { lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, mBorderSpace); @@ -179,8 +180,10 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag()); lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, appWidgetScale.x, appWidgetScale.y, mBorderSpace, - // Flexera Launcher: the launcher's own widgets take their cells whole. - app.flexera.widget.FlexeraWidgets.cellInset(child, dp.widgetPadding)); + // Flexera Launcher: the launcher's own widgets take their cells whole; + // the others are lined up with the icons. + app.flexera.widget.FlexeraWidgets.cellInset(child, dp, + mCellWidth, mCellHeight)); } else if (isChildQsb(child)) { lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, mBorderSpace); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index b09e9e7078..04c79c359e 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3300,7 +3300,10 @@ public class Workspace extends PagedView if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { DeviceProfile profile = mLauncher.getDeviceProfile(); if (finalView instanceof NavigableAppWidgetHostView) { - Rect widgetPadding = profile.widgetPadding; + // Flexera Launcher: the room this widget keeps in its cells. + Point cell = profile.getCellSize(); + Rect widgetPadding = app.flexera.widget.FlexeraWidgets.cellInset( + finalView, profile, cell.x, cell.y); r.left -= widgetPadding.left; r.right += widgetPadding.right; r.top -= widgetPadding.top; diff --git a/src/com/android/launcher3/widget/util/WidgetSizes.java b/src/com/android/launcher3/widget/util/WidgetSizes.java index f5125fb59e..48458e632d 100644 --- a/src/com/android/launcher3/widget/util/WidgetSizes.java +++ b/src/com/android/launcher3/widget/util/WidgetSizes.java @@ -61,7 +61,8 @@ public final class WidgetSizes { final int vBorderSpacing = (spanY - 1) * profile.cellLayoutBorderSpacePx.y; Point cellSize = profile.getCellSize(); - Rect padding = profile.widgetPadding; + // Flexera Launcher: the size the widget really gets, lined up with the icons. + Rect padding = app.flexera.widget.FlexeraWidgets.appWidgetPadding(profile); return new Size( (spanX * cellSize.x) + hBorderSpacing - padding.left - padding.right,