diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index 1330ed4edd..be92c5d133 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -2,6 +2,8 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT; import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH; +import static com.android.launcher3.Utilities.ATLEAST_S; +import static com.android.launcher3.config.FeatureFlags.ENABLE_FOUR_COLUMNS; import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X; import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y; @@ -11,14 +13,19 @@ import android.animation.PropertyValuesHolder; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Point; +import android.graphics.PointF; import android.graphics.Rect; +import android.os.Bundle; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import androidx.annotation.Nullable; + import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.util.FocusLogic; @@ -352,33 +359,99 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O } public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Launcher launcher, - int spanX, int spanY) { - getWidgetSizeRanges(launcher, spanX, spanY, sTmpRect); - widgetView.updateAppWidgetSize(null, sTmpRect.left, sTmpRect.top, - sTmpRect.right, sTmpRect.bottom); + int spanX, int spanY) { + List sizes = getWidgetSizes(launcher, spanX, spanY); + if (ATLEAST_S) { + widgetView.updateAppWidgetSize(new Bundle(), sizes); + } else { + Rect bounds = getMinMaxSizes(sizes, null /* outRect */); + widgetView.updateAppWidgetSize(new Bundle(), bounds.left, bounds.top, bounds.right, + bounds.bottom); + } } - public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY, Rect rect) { - if (rect == null) { - rect = new Rect(); - } + private static PointF getWidgetSize(Context context, Point cellSize, int spanX, int spanY) { final float density = context.getResources().getDisplayMetrics().density; + float hBorderSpacing = 0; + float vBorderSpacing = 0; + if (ENABLE_FOUR_COLUMNS.get()) { + final int borderSpacing = context.getResources() + .getDimensionPixelSize(R.dimen.dynamic_grid_cell_border_spacing); + hBorderSpacing = (spanX - 1) * borderSpacing; + vBorderSpacing = (spanY - 1) * borderSpacing; + } + PointF widgetSize = new PointF(); + widgetSize.x = ((spanX * cellSize.x) + hBorderSpacing) / density; + widgetSize.y = ((spanY * cellSize.y) + vBorderSpacing) / density; + return widgetSize; + } + + /** Returns the actual widget size given its span. */ + public static PointF getWidgetSize(Context context, int spanX, int spanY) { + final Point[] cellSize = CELL_SIZE.get(context); + if (isLandscape(context)) { + return getWidgetSize(context, cellSize[0], spanX, spanY); + } + return getWidgetSize(context, cellSize[1], spanX, spanY); + } + + /** Returns true if the screen is in landscape mode. */ + private static boolean isLandscape(Context context) { + return context.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE; + } + + /** Returns the list of sizes for a widget of given span, in dp. */ + public static ArrayList getWidgetSizes(Context context, int spanX, int spanY) { final Point[] cellSize = CELL_SIZE.get(context); - final int borderSpacing = context.getResources() - .getDimensionPixelSize(R.dimen.dynamic_grid_cell_border_spacing); - final float hBorderSpacing = (spanX - 1) * borderSpacing; - final float vBorderSpacing = (spanY - 1) * borderSpacing; + PointF landSize = getWidgetSize(context, cellSize[0], spanX, spanY); + PointF portSize = getWidgetSize(context, cellSize[1], spanX, spanY); - // Compute landscape size - int landWidth = (int) (((spanX * cellSize[0].x) + hBorderSpacing) / density); - int landHeight = (int) (((spanY * cellSize[0].y) + vBorderSpacing) / density); + ArrayList sizes = new ArrayList<>(2); + sizes.add(landSize); + sizes.add(portSize); + return sizes; + } - // Compute portrait size - int portWidth = (int) (((spanX * cellSize[1].x) + hBorderSpacing) / density); - int portHeight = (int) (((spanY * cellSize[1].y) + vBorderSpacing) / density); - rect.set(portWidth, landHeight, landWidth, portHeight); - return rect; + /** + * Returns the min and max widths and heights given a list of sizes, in dp. + * + * @param sizes List of sizes to get the min/max from. + * @param outRect Rectangle in which the result can be stored, to avoid extra allocations. If + * null, a new rectangle will be allocated. + * @return A rectangle with the left (resp. top) is used for the min width (resp. height) and + * the right (resp. bottom) for the max. The returned rectangle is set with 0s if the list is + * empty. + */ + public static Rect getMinMaxSizes(List sizes, @Nullable Rect outRect) { + if (outRect == null) { + outRect = new Rect(); + } + if (sizes.isEmpty()) { + outRect.set(0, 0, 0, 0); + } else { + PointF first = sizes.get(0); + outRect.set((int) first.x, (int) first.y, (int) first.x, (int) first.y); + for (int i = 1; i < sizes.size(); i++) { + outRect.union((int) sizes.get(i).x, (int) sizes.get(i).y); + } + } + return outRect; + } + + /** + * Returns the range of sizes a widget may be displayed, given its span. + * + * @param context Context in which the View is rendered. + * @param spanX Width of the widget, in cells. + * @param spanY Height of the widget, in cells. + * @param outRect Rectangle in which the result can be stored, to avoid extra allocations. If + * null, a new rectangle will be allocated. + */ + public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY, + @Nullable Rect outRect) { + return getMinMaxSizes(getWidgetSizes(context, spanX, spanY), outRect); } @Override diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index cd4616a967..db7fd3feca 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -357,10 +357,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme } layout.markCellsAsOccupiedForView(host); - Rect sizeRange = new Rect(); - AppWidgetResizeFrame.getWidgetSizeRanges(mLauncher, info.spanX, info.spanY, sizeRange); - ((LauncherAppWidgetHostView) host).updateAppWidgetSize(null, - sizeRange.left, sizeRange.top, sizeRange.right, sizeRange.bottom); + AppWidgetResizeFrame.updateWidgetSizeRanges(((LauncherAppWidgetHostView) host), mLauncher, + info.spanX, info.spanY); host.requestLayout(); mLauncher.getModelWriter().updateItemInDatabase(info); announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY)); diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java index 289e0d84c0..459aefe2c0 100644 --- a/src/com/android/launcher3/qsb/QsbContainerView.java +++ b/src/com/android/launcher3/qsb/QsbContainerView.java @@ -20,6 +20,8 @@ import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_BIND; import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID; import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER; +import static com.android.launcher3.Utilities.ATLEAST_S; + import android.app.Activity; import android.app.Fragment; import android.app.SearchManager; @@ -30,6 +32,7 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.graphics.PointF; import android.graphics.Rect; import android.os.Bundle; import android.provider.Settings; @@ -50,6 +53,8 @@ import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.FragmentWithPreview; +import java.util.ArrayList; + /** * A frame layout which contains a QSB. This internally uses fragment to bind the view, which * allows it to contain the logic for {@link Fragment#startActivityForResult(Intent, int)}. @@ -294,12 +299,16 @@ public class QsbContainerView extends FrameLayout { InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext()); Bundle opts = new Bundle(); - Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(getContext(), - idp.numColumns, 1, null); + ArrayList sizes = AppWidgetResizeFrame + .getWidgetSizes(getContext(), idp.numColumns, 1); + Rect size = AppWidgetResizeFrame.getMinMaxSizes(sizes, null /* outRect */); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom); + if (ATLEAST_S) { + opts.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes); + } return opts; } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 780a1a18bd..41098f9f1c 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -16,9 +16,12 @@ package com.android.launcher3.widget; +import static com.android.launcher3.Utilities.ATLEAST_S; + import android.appwidget.AppWidgetProviderInfo; import android.content.Context; import android.content.res.Configuration; +import android.graphics.PointF; import android.os.Handler; import android.os.SystemClock; import android.util.SparseBooleanArray; @@ -70,8 +73,6 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView private boolean mIsAutoAdvanceRegistered; private Runnable mAutoAdvanceRunnable; - - public LauncherAppWidgetHostView(Context context) { super(context); mLauncher = Launcher.getLauncher(context); @@ -218,6 +219,16 @@ public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView mIsScrollable = checkScrollableRecursively(this); } + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + if (ATLEAST_S) { + float density = getContext().getResources().getDisplayMetrics().density; + setCurrentSize(new PointF(w / density, h / density)); + } + } + @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java index ca47728020..8c3206dea8 100644 --- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java @@ -22,6 +22,7 @@ import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -46,6 +47,8 @@ import com.android.launcher3.model.data.PackageItemInfo; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.util.Themes; +import java.util.List; + public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener, ItemInfoUpdateReceiver { private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5; @@ -108,6 +111,11 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView // No-op } + @Override + public void updateAppWidgetSize(Bundle newOptions, List sizes) { + // No-op + } + @Override protected View getDefaultView() { View defaultView = mInflater.inflate(R.layout.appwidget_not_ready, this, false); diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index c022374614..2438bdf5ab 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -3,6 +3,7 @@ package com.android.launcher3.widget; import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetManager; import android.content.Context; +import android.graphics.PointF; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; @@ -18,6 +19,8 @@ import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.util.Thunk; +import java.util.ArrayList; + public class WidgetHostViewLoader implements DragController.DragListener { private static final String TAG = "WidgetHostViewLoader"; private static final boolean LOGD = false; @@ -152,24 +155,28 @@ public class WidgetHostViewLoader implements DragController.DragListener { } public static Bundle getDefaultOptionsForWidget(Context context, PendingAddWidgetInfo info) { - Rect rect = new Rect(); - AppWidgetResizeFrame.getWidgetSizeRanges(context, info.spanX, info.spanY, rect); + ArrayList sizes = AppWidgetResizeFrame + .getWidgetSizes(context, info.spanX, info.spanY); + Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(context, info.componentName, null); - float density = context.getResources().getDisplayMetrics().density; - int xPaddingDips = (int) ((padding.left + padding.right) / density); - int yPaddingDips = (int) ((padding.top + padding.bottom) / density); + float xPaddingDips = (padding.left + padding.right) / density; + float yPaddingDips = (padding.top + padding.bottom) / density; + + for (PointF size : sizes) { + size.x = Math.max(0.f, size.x - xPaddingDips); + size.y = Math.max(0.f, size.y - yPaddingDips); + } + + Rect rect = AppWidgetResizeFrame.getMinMaxSizes(sizes, null /* outRect */); Bundle options = new Bundle(); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, - rect.left - xPaddingDips); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, - rect.top - yPaddingDips); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, - rect.right - xPaddingDips); - options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, - rect.bottom - yPaddingDips); + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, rect.left); + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, rect.top); + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, rect.right); + options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, rect.bottom); + options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, sizes); return options; } }