Merge "Always insetting the widget by a minimum of 6dp" into udc-dev

This commit is contained in:
Treehugger Robot
2023-05-04 17:48:48 +00:00
committed by Android (Google) Code Review
15 changed files with 105 additions and 205 deletions
-6
View File
@@ -32,12 +32,6 @@
<dimen name="dynamic_grid_hotseat_bottom_tall_padding">0dp</dimen> <dimen name="dynamic_grid_hotseat_bottom_tall_padding">0dp</dimen>
<dimen name="spring_loaded_hotseat_top_margin">76dp</dimen> <dimen name="spring_loaded_hotseat_top_margin">76dp</dimen>
<!-- Qsb -->
<!-- Used for adjusting the position of QSB when placed in hotseat. This is a ratio and a higher
number signifies that the QSB is close to the hotseat icons and a lower number signifies that
it is close to the bottom of the screen -->
<item name="qsb_center_factor" format="float" type="dimen">0.325</item>
<dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen> <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
<!-- Scalable Grid --> <!-- Scalable Grid -->
@@ -1,7 +1,5 @@
package com.android.launcher3; package com.android.launcher3;
import static android.appwidget.AppWidgetHostView.getDefaultPaddingForWidget;
import static com.android.launcher3.CellLayout.SPRING_LOADED_PROGRESS; import static com.android.launcher3.CellLayout.SPRING_LOADED_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT; import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH; import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
@@ -77,8 +75,6 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private DragLayer mDragLayer; private DragLayer mDragLayer;
private ImageButton mReconfigureButton; private ImageButton mReconfigureButton;
private Rect mWidgetPadding;
private final int mBackgroundPadding; private final int mBackgroundPadding;
private final int mTouchTargetWidth; private final int mTouchTargetWidth;
@@ -218,9 +214,6 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mMaxHSpan = info.maxSpanX; mMaxHSpan = info.maxSpanX;
mMaxVSpan = info.maxSpanY; mMaxVSpan = info.maxSpanY;
mWidgetPadding = getDefaultPaddingForWidget(getContext(),
widgetView.getAppWidgetInfo().provider, null);
// Only show resize handles for the directions in which resizing is possible. // Only show resize handles for the directions in which resizing is possible.
InvariantDeviceProfile idp = LauncherAppState.getIDP(cellLayout.getContext()); InvariantDeviceProfile idp = LauncherAppState.getIDP(cellLayout.getContext());
mVerticalResizeActive = (info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0 mVerticalResizeActive = (info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0
@@ -517,16 +510,12 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
*/ */
private void getSnappedRectRelativeToDragLayer(Rect out) { private void getSnappedRectRelativeToDragLayer(Rect out) {
float scale = mWidgetView.getScaleToFit(); float scale = mWidgetView.getScaleToFit();
mDragLayer.getViewRectRelativeToSelf(mWidgetView, out); mDragLayer.getViewRectRelativeToSelf(mWidgetView, out);
int width = 2 * mBackgroundPadding int width = 2 * mBackgroundPadding + Math.round(scale * out.width());
+ (int) (scale * (out.width() - mWidgetPadding.left - mWidgetPadding.right)); int height = 2 * mBackgroundPadding + Math.round(scale * out.height());
int height = 2 * mBackgroundPadding int x = out.left - mBackgroundPadding;
+ (int) (scale * (out.height() - mWidgetPadding.top - mWidgetPadding.bottom)); int y = out.top - mBackgroundPadding;
int x = (int) (out.left - mBackgroundPadding + scale * mWidgetPadding.left);
int y = (int) (out.top - mBackgroundPadding + scale * mWidgetPadding.top);
out.left = x; out.left = x;
out.top = y; out.top = y;
+17 -22
View File
@@ -67,14 +67,12 @@ public class DeviceProfile {
private static final int DEFAULT_DOT_SIZE = 100; private static final int DEFAULT_DOT_SIZE = 100;
private static final float ALL_APPS_TABLET_MAX_ROWS = 5.5f; private static final float ALL_APPS_TABLET_MAX_ROWS = 5.5f;
private static final float MIN_FOLDER_TEXT_SIZE_SP = 16f; private static final float MIN_FOLDER_TEXT_SIZE_SP = 16f;
private static final float MIN_WIDGET_PADDING_DP = 6f;
public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f); public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE; public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {}; public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {};
// Ratio of empty space, qsb should take up to appear visually centered.
private final float mQsbCenterFactor;
public final InvariantDeviceProfile inv; public final InvariantDeviceProfile inv;
private final Info mInfo; private final Info mInfo;
private final DisplayMetrics mMetrics; private final DisplayMetrics mMetrics;
@@ -252,6 +250,10 @@ public class DeviceProfile {
// Insets // Insets
private final Rect mInsets = new Rect(); private final Rect mInsets = new Rect();
public final Rect workspacePadding = new Rect(); public final Rect workspacePadding = new Rect();
// Additional padding added to the widget inside its cellSpace. It is applied outside
// the widgetView, such that the actual view size is same as the widget size.
public final Rect widgetPadding = new Rect();
// When true, nav bar is on the left side of the screen. // When true, nav bar is on the left side of the screen.
private boolean mIsSeascape; private boolean mIsSeascape;
@@ -314,9 +316,6 @@ public class DeviceProfile {
availableHeightPx = windowBounds.availableSize.y; availableHeightPx = windowBounds.availableSize.y;
aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx); aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
mQsbCenterFactor = res.getFloat(R.dimen.qsb_center_factor);
if (isTwoPanels) { if (isTwoPanels) {
if (isLandscape) { if (isLandscape) {
mTypeIndex = INDEX_TWO_PANEL_LANDSCAPE; mTypeIndex = INDEX_TWO_PANEL_LANDSCAPE;
@@ -730,22 +729,6 @@ public class DeviceProfile {
return mInfo; return mInfo;
} }
/**
* We inset the widget padding added by the system and instead rely on the border spacing
* between cells to create reliable consistency between widgets
*/
public boolean shouldInsetWidgets() {
Rect widgetPadding = inv.defaultWidgetPadding;
// Check all sides to ensure that the widget won't overlap into another cell, or into
// status bar.
return workspaceTopPadding > widgetPadding.top
&& cellLayoutBorderSpacePx.x > widgetPadding.left
&& cellLayoutBorderSpacePx.y > widgetPadding.top
&& cellLayoutBorderSpacePx.x > widgetPadding.right
&& cellLayoutBorderSpacePx.y > widgetPadding.bottom;
}
public Builder toBuilder(Context context) { public Builder toBuilder(Context context) {
WindowBounds bounds = new WindowBounds( WindowBounds bounds = new WindowBounds(
widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint); widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint);
@@ -999,6 +982,18 @@ public class DeviceProfile {
// Folder icon // Folder icon
folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx); folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx);
folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2; folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2;
// Update widget padding:
float minSpacing = pxFromDp(MIN_WIDGET_PADDING_DP, mMetrics);
if (cellLayoutBorderSpacePx.x < minSpacing
|| cellLayoutBorderSpacePx.y < minSpacing) {
widgetPadding.left = widgetPadding.right =
Math.round(Math.max(0, minSpacing - cellLayoutBorderSpacePx.x));
widgetPadding.top = widgetPadding.bottom =
Math.round(Math.max(0, minSpacing - cellLayoutBorderSpacePx.y));
} else {
widgetPadding.setEmpty();
}
} }
/** /**
@@ -26,8 +26,6 @@ import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUN
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
@@ -35,7 +33,6 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.Rect;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
@@ -192,7 +189,6 @@ public class InvariantDeviceProfile {
public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST; public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST;
public Point defaultWallpaperSize; public Point defaultWallpaperSize;
public Rect defaultWidgetPadding;
private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>(); private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
@@ -443,9 +439,6 @@ public class InvariantDeviceProfile {
deviceProfile.numShownHotseatIcons = numMinShownHotseatIconsForTablet; deviceProfile.numShownHotseatIcons = numMinShownHotseatIconsForTablet;
deviceProfile.recalculateHotseatWidthAndBorderSpace(); deviceProfile.recalculateHotseatWidthAndBorderSpace();
}); });
ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
} }
public void addOnChangeListener(OnIDPChangeListener listener) { public void addOnChangeListener(OnIDPChangeListener listener) {
@@ -46,8 +46,6 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
// return an (x, y) value from helper functions. Do NOT use them to maintain other state. // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
private final int[] mTmpCellXY = new int[2]; private final int[] mTmpCellXY = new int[2];
private final Rect mTempRect = new Rect();
@ContainerType @ContainerType
private final int mContainerType; private final int mContainerType;
private final WallpaperManager mWallpaperManager; private final WallpaperManager mWallpaperManager;
@@ -124,13 +122,12 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams(); CellLayoutLayoutParams lp = (CellLayoutLayoutParams) child.getLayoutParams();
if (child instanceof NavigableAppWidgetHostView) { if (child instanceof NavigableAppWidgetHostView) {
DeviceProfile profile = mActivity.getDeviceProfile(); DeviceProfile profile = mActivity.getDeviceProfile();
((NavigableAppWidgetHostView) child).getWidgetInset(profile, mTempRect);
final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag()); final PointF appWidgetScale = profile.getAppWidgetScale((ItemInfo) child.getTag());
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
appWidgetScale.x, appWidgetScale.y, mBorderSpace, mTempRect); appWidgetScale.x, appWidgetScale.y, mBorderSpace, profile.widgetPadding);
} else { } else {
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
mBorderSpace, null); mBorderSpace);
} }
} }
@@ -149,13 +146,12 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
final DeviceProfile dp = mActivity.getDeviceProfile(); final DeviceProfile dp = mActivity.getDeviceProfile();
if (child instanceof NavigableAppWidgetHostView) { if (child instanceof NavigableAppWidgetHostView) {
((NavigableAppWidgetHostView) child).getWidgetInset(dp, mTempRect);
final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag()); final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag());
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
appWidgetScale.x, appWidgetScale.y, mBorderSpace, mTempRect); appWidgetScale.x, appWidgetScale.y, mBorderSpace, dp.widgetPadding);
} else { } else {
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY, lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
mBorderSpace, null); mBorderSpace);
// Center the icon/folder // Center the icon/folder
int cHeight = getCellContentHeight(); int cHeight = getCellContentHeight();
int cellPaddingY = dp.isScalableGrid && mContainerType == WORKSPACE int cellPaddingY = dp.isScalableGrid && mContainerType == WORKSPACE
+2 -3
View File
@@ -2912,9 +2912,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
Rect r = estimateItemPosition(layout, targetCell[0], targetCell[1], spanX, spanY); Rect r = estimateItemPosition(layout, targetCell[0], targetCell[1], spanX, spanY);
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) {
DeviceProfile profile = mLauncher.getDeviceProfile(); DeviceProfile profile = mLauncher.getDeviceProfile();
if (profile.shouldInsetWidgets() && finalView instanceof NavigableAppWidgetHostView) { if (finalView instanceof NavigableAppWidgetHostView) {
Rect widgetPadding = new Rect(); Rect widgetPadding = profile.widgetPadding;
((NavigableAppWidgetHostView) finalView).getWidgetInset(profile, widgetPadding);
r.left -= widgetPadding.left; r.left -= widgetPadding.left;
r.right += widgetPadding.right; r.right += widgetPadding.right;
r.top -= widgetPadding.top; r.top -= widgetPadding.top;
@@ -113,13 +113,13 @@ public class CellLayoutLayoutParams extends ViewGroup.MarginLayoutParams {
* full/invariant device profile sizes. * full/invariant device profile sizes.
*/ */
public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount, public void setup(int cellWidth, int cellHeight, boolean invertHorizontally, int colCount,
int rowCount, Point borderSpace, @Nullable Rect inset) { int rowCount, Point borderSpace) {
setup(cellWidth, cellHeight, invertHorizontally, colCount, rowCount, 1.0f, 1.0f, setup(cellWidth, cellHeight, invertHorizontally, colCount, rowCount, 1.0f, 1.0f,
borderSpace, inset); borderSpace, null);
} }
/** /**
* Use this method, as opposed to {@link #setup(int, int, boolean, int, int, Point, Rect)}, * Use this method, as opposed to {@link #setup(int, int, boolean, int, int, Point)},
* if the view needs to be scaled. * if the view needs to be scaled.
* *
* ie. In multi-window mode, we setup widgets so that they are measured and laid out * ie. In multi-window mode, we setup widgets so that they are measured and laid out
@@ -150,10 +150,10 @@ public class CellLayoutLayoutParams extends ViewGroup.MarginLayoutParams {
y = topMargin + (myCellY * cellHeight) + (myCellY * borderSpace.y); y = topMargin + (myCellY * cellHeight) + (myCellY * borderSpace.y);
if (inset != null) { if (inset != null) {
x -= inset.left; x += inset.left;
y -= inset.top; y += inset.top;
width += inset.left + inset.right; width -= inset.left + inset.right;
height += inset.top + inset.bottom; height -= inset.top + inset.bottom;
} }
} }
} }
@@ -451,26 +451,8 @@ public class LauncherPreviewRenderer extends ContextWrapper
final Size origSize = WidgetSizes.getWidgetSizePx(mDpOrig, final Size origSize = WidgetSizes.getWidgetSizePx(mDpOrig,
launcherWidgetSize.getWidth(), launcherWidgetSize.getHeight()); launcherWidgetSize.getWidth(), launcherWidgetSize.getHeight());
final Size newSize = WidgetSizes.getWidgetSizePx(mDp, info.spanX, info.spanY); final Size newSize = WidgetSizes.getWidgetSizePx(mDp, info.spanX, info.spanY);
final Rect previewInset = new Rect(); return new PointF((float) newSize.getWidth() / origSize.getWidth(),
final Rect origInset = new Rect(); (float) newSize.getHeight() / origSize.getHeight());
// When the setup() is called for the LayoutParams, insets are added to the width
// and height of the view. This is not accounted for in WidgetSizes and is handled
// here.
if (mDp.shouldInsetWidgets()) {
previewInset.set(mDp.inv.defaultWidgetPadding);
} else {
previewInset.setEmpty();
}
if (mDpOrig.shouldInsetWidgets()) {
origInset.set(mDpOrig.inv.defaultWidgetPadding);
} else {
origInset.setEmpty();
}
return new PointF((float) newSize.getWidth() / (origSize.getWidth()
+ origInset.left + origInset.right),
(float) newSize.getHeight() / (origSize.getHeight()
+ origInset.top + origInset.bottom));
} }
private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) { private void inflateAndAddPredictedIcon(WorkspaceItemInfo info) {
@@ -146,8 +146,7 @@ public class DatabaseWidgetPreviewLoader {
previewWidth = drawable.getIntrinsicWidth(); previewWidth = drawable.getIntrinsicWidth();
previewHeight = drawable.getIntrinsicHeight(); previewHeight = drawable.getIntrinsicHeight();
} else { } else {
Size widgetSize = WidgetSizes.getWidgetPaddedSizePx(mContext, info.provider, dp, spanX, Size widgetSize = WidgetSizes.getWidgetSizePx(dp, spanX, spanY);
spanY);
previewWidth = widgetSize.getWidth(); previewWidth = widgetSize.getWidth();
previewHeight = widgetSize.getHeight(); previewHeight = widgetSize.getHeight();
} }
@@ -2,7 +2,6 @@ package com.android.launcher3.widget;
import static com.android.launcher3.Utilities.ATLEAST_S; import static com.android.launcher3.Utilities.ATLEAST_S;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetProviderInfo; import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -105,44 +104,35 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
int spanX = 0; int spanX = 0;
int spanY = 0; int spanY = 0;
Rect widgetPadding = new Rect();
Rect localPadding = new Rect();
AppWidgetHostView.getDefaultPaddingForWidget(context, provider, widgetPadding);
Point cellSize = new Point(); Point cellSize = new Point();
for (DeviceProfile dp : idp.supportedProfiles) { for (DeviceProfile dp : idp.supportedProfiles) {
dp.getCellSize(cellSize); dp.getCellSize(cellSize);
// We want to account for the extra amount of padding that we are adding to the widget Rect widgetPadding = dp.widgetPadding;
// to ensure that it gets the full amount of space that it has requested.
// If grids supports insetting widgets, we do not account for widget padding.
if (dp.shouldInsetWidgets()) {
localPadding.setEmpty();
} else {
localPadding.set(widgetPadding);
}
minSpanX = Math.max(minSpanX, minSpanX = Math.max(minSpanX,
getSpanX(localPadding, minResizeWidth, dp.cellLayoutBorderSpacePx.x, getSpanX(widgetPadding, minResizeWidth, dp.cellLayoutBorderSpacePx.x,
cellSize.x)); cellSize.x));
minSpanY = Math.max(minSpanY, minSpanY = Math.max(minSpanY,
getSpanY(localPadding, minResizeHeight, dp.cellLayoutBorderSpacePx.y, getSpanY(widgetPadding, minResizeHeight, dp.cellLayoutBorderSpacePx.y,
cellSize.y)); cellSize.y));
if (ATLEAST_S) { if (ATLEAST_S) {
if (maxResizeWidth > 0) { if (maxResizeWidth > 0) {
maxSpanX = Math.min(maxSpanX, getSpanX(localPadding, maxResizeWidth, maxSpanX = Math.min(maxSpanX, getSpanX(widgetPadding, maxResizeWidth,
dp.cellLayoutBorderSpacePx.x, cellSize.x)); dp.cellLayoutBorderSpacePx.x, cellSize.x));
} }
if (maxResizeHeight > 0) { if (maxResizeHeight > 0) {
maxSpanY = Math.min(maxSpanY, getSpanY(localPadding, maxResizeHeight, maxSpanY = Math.min(maxSpanY, getSpanY(widgetPadding, maxResizeHeight,
dp.cellLayoutBorderSpacePx.y, cellSize.y)); dp.cellLayoutBorderSpacePx.y, cellSize.y));
} }
} }
spanX = Math.max(spanX, spanX = Math.max(spanX,
getSpanX(localPadding, minWidth, dp.cellLayoutBorderSpacePx.x, getSpanX(widgetPadding, minWidth, dp.cellLayoutBorderSpacePx.x,
cellSize.x)); cellSize.x));
spanY = Math.max(spanY, spanY = Math.max(spanY,
getSpanY(localPadding, minHeight, dp.cellLayoutBorderSpacePx.y, getSpanY(widgetPadding, minHeight, dp.cellLayoutBorderSpacePx.y,
cellSize.y)); cellSize.y));
} }
@@ -184,15 +174,22 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo
} }
private int getSpanX(Rect widgetPadding, int widgetWidth, int cellSpacing, float cellWidth) { private int getSpanX(Rect widgetPadding, int widgetWidth, int cellSpacing, float cellWidth) {
return Math.max(1, (int) Math.ceil( return getSpan(widgetPadding.left + widgetPadding.right,
(widgetWidth + widgetPadding.left + widgetPadding.right + cellSpacing) / (cellWidth widgetWidth, cellSpacing, cellWidth);
+ cellSpacing)));
} }
private int getSpanY(Rect widgetPadding, int widgetHeight, int cellSpacing, float cellHeight) { private int getSpanY(Rect widgetPadding, int widgetHeight, int cellSpacing, float cellHeight) {
return getSpan(widgetPadding.top + widgetPadding.bottom, widgetHeight,
cellSpacing, cellHeight);
}
/**
* Solving the equation:
* n * cellSize + (n - 1) * cellSpacing - widgetPadding = widgetSize
*/
private int getSpan(int widgetPadding, int widgetSize, int cellSpacing, float cellSize) {
return Math.max(1, (int) Math.ceil( return Math.max(1, (int) Math.ceil(
(widgetHeight + widgetPadding.top + widgetPadding.bottom + cellSpacing) / ( (widgetSize + widgetPadding + cellSpacing) / (cellSize + cellSpacing)));
cellHeight + cellSpacing)));
} }
public String getLabel(PackageManager packageManager) { public String getLabel(PackageManager packageManager) {
@@ -25,7 +25,6 @@ import android.view.View;
import android.view.ViewDebug; import android.view.ViewDebug;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Reorderable; import com.android.launcher3.Reorderable;
import com.android.launcher3.dragndrop.DraggableView; import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.util.MultiTranslateDelegate; import com.android.launcher3.util.MultiTranslateDelegate;
@@ -48,13 +47,13 @@ public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
private float mScaleForReorderBounce = 1f; private float mScaleForReorderBounce = 1f;
private final Rect mTempRect = new Rect();
@ViewDebug.ExportedProperty(category = "launcher") @ViewDebug.ExportedProperty(category = "launcher")
private boolean mChildrenFocused; private boolean mChildrenFocused;
protected final ActivityContext mActivity; protected final ActivityContext mActivity;
private boolean mDisableSetPadding = false;
public NavigableAppWidgetHostView(Context context) { public NavigableAppWidgetHostView(Context context) {
super(context); super(context);
mActivity = ActivityContext.lookupContext(context); mActivity = ActivityContext.lookupContext(context);
@@ -146,6 +145,22 @@ public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
dispatchChildFocus(false); dispatchChildFocus(false);
} }
@Override
public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
// Prevent default padding being set on the view based on provider info. Launcher manages
// its own widget spacing
mDisableSetPadding = true;
super.setAppWidget(appWidgetId, info);
mDisableSetPadding = false;
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
if (!mDisableSetPadding) {
super.setPadding(left, top, right, bottom);
}
}
@Override @Override
public boolean dispatchUnhandledMove(View focused, int direction) { public boolean dispatchUnhandledMove(View focused, int direction) {
return mChildrenFocused; return mChildrenFocused;
@@ -195,26 +210,6 @@ public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
public void getWorkspaceVisualDragBounds(Rect bounds) { public void getWorkspaceVisualDragBounds(Rect bounds) {
int width = (int) (getMeasuredWidth() * mScaleToFit); int width = (int) (getMeasuredWidth() * mScaleToFit);
int height = (int) (getMeasuredHeight() * mScaleToFit); int height = (int) (getMeasuredHeight() * mScaleToFit);
bounds.set(0, 0, width, height);
getWidgetInset(mActivity.getDeviceProfile(), mTempRect);
bounds.set(mTempRect.left, mTempRect.top, width - mTempRect.right,
height - mTempRect.bottom);
}
/**
* Widgets have padding added by the system. We may choose to inset this padding if the grid
* supports it.
*/
public void getWidgetInset(DeviceProfile grid, Rect out) {
if (!grid.shouldInsetWidgets()) {
out.setEmpty();
return;
}
AppWidgetProviderInfo info = getAppWidgetInfo();
if (info == null) {
out.set(grid.inv.defaultWidgetPadding);
} else {
AppWidgetHostView.getDefaultPaddingForWidget(getContext(), info.provider, out);
}
} }
} }
@@ -16,6 +16,8 @@
package com.android.launcher3.widget; package com.android.launcher3.widget;
import static com.android.launcher3.widget.util.WidgetSizes.getWidgetSizePx;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint; import android.graphics.Paint;
@@ -43,7 +45,6 @@ import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.icons.RoundDrawableWrapper; import com.android.launcher3.icons.RoundDrawableWrapper;
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener; import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
import com.android.launcher3.widget.util.WidgetSizes;
/** /**
* Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts * Extension of {@link DragPreviewProvider} with logic specific to pending widgets/shortcuts
@@ -121,13 +122,8 @@ public class PendingItemDragHelper extends DragPreviewProvider {
mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1, mAppWidgetHostViewPreview.setAppWidget(/* appWidgetId= */ -1,
((PendingAddWidgetInfo) mAddInfo).info); ((PendingAddWidgetInfo) mAddInfo).info);
DeviceProfile deviceProfile = launcher.getDeviceProfile(); DeviceProfile deviceProfile = launcher.getDeviceProfile();
Rect padding = new Rect();
mAppWidgetHostViewPreview.getWidgetInset(deviceProfile, padding);
mAppWidgetHostViewPreview.setPadding(padding.left, padding.top, padding.right,
padding.bottom);
mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview); mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ mRemoteViewsPreview);
Size widgetSizes = WidgetSizes.getWidgetPaddedSizePx(launcher, Size widgetSizes = getWidgetSizePx(deviceProfile, mAddInfo.spanX, mAddInfo.spanY);
mAddInfo.componentName, deviceProfile, mAddInfo.spanX, mAddInfo.spanY);
mAppWidgetHostViewPreview.measure( mAppWidgetHostViewPreview.measure(
MeasureSpec.makeMeasureSpec(widgetSizes.getWidth(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(widgetSizes.getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(widgetSizes.getHeight(), MeasureSpec.EXACTLY)); MeasureSpec.makeMeasureSpec(widgetSizes.getHeight(), MeasureSpec.EXACTLY));
@@ -15,8 +15,6 @@
*/ */
package com.android.launcher3.widget.util; package com.android.launcher3.widget.util;
import static android.appwidget.AppWidgetHostView.getDefaultPaddingForWidget;
import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
import android.content.ComponentName; import android.content.ComponentName;
@@ -28,8 +26,6 @@ import android.util.Log;
import android.util.Size; import android.util.Size;
import android.util.SizeF; import android.util.SizeF;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R; import com.android.launcher3.R;
@@ -43,24 +39,13 @@ public final class WidgetSizes {
/** /**
* Returns the list of all possible sizes, in dp, for a widget of given spans on this device. * Returns the list of all possible sizes, in dp, for a widget of given spans on this device.
*
* <p>The returned sizes already take into account the system padding, and whether it is applied
* or not in that specific configuration.
*/ */
public static ArrayList<SizeF> getWidgetPaddedSizes(Context context, ComponentName provider, public static ArrayList<SizeF> getWidgetSizesDp(Context context, int spanX, int spanY) {
int spanX, int spanY) {
Rect padding = getDefaultPaddingForWidget(context, provider, /* padding= */ null);
ArrayList<SizeF> sizes = new ArrayList<>(2); ArrayList<SizeF> sizes = new ArrayList<>(2);
final float density = context.getResources().getDisplayMetrics().density; final float density = context.getResources().getDisplayMetrics().density;
final Point cellSize = new Point();
for (DeviceProfile profile : LauncherAppState.getIDP(context).supportedProfiles) { for (DeviceProfile profile : LauncherAppState.getIDP(context).supportedProfiles) {
Size widgetSizePx = getWidgetSizePx(profile, spanX, spanY, cellSize); Size widgetSizePx = getWidgetSizePx(profile, spanX, spanY);
if (!profile.shouldInsetWidgets()) {
widgetSizePx = new Size(widgetSizePx.getWidth() - padding.left - padding.right,
widgetSizePx.getHeight() - padding.top - padding.bottom);
}
sizes.add(new SizeF(widgetSizePx.getWidth() / density, sizes.add(new SizeF(widgetSizePx.getWidth() / density,
widgetSizePx.getHeight() / density)); widgetSizePx.getHeight() / density));
} }
@@ -69,21 +54,15 @@ public final class WidgetSizes {
/** Returns the size, in pixels, a widget of given spans & {@code profile}. */ /** Returns the size, in pixels, a widget of given spans & {@code profile}. */
public static Size getWidgetSizePx(DeviceProfile profile, int spanX, int spanY) { public static Size getWidgetSizePx(DeviceProfile profile, int spanX, int spanY) {
return getWidgetSizePx(profile, spanX, spanY, /* recycledCellSize= */ null); final int hBorderSpacing = (spanX - 1) * profile.cellLayoutBorderSpacePx.x;
} final int vBorderSpacing = (spanY - 1) * profile.cellLayoutBorderSpacePx.y;
/** Point cellSize = profile.getCellSize();
* Returns the size, in pixels and removing padding, a widget of given spans & {@code profile}. Rect padding = profile.widgetPadding;
*/
public static Size getWidgetPaddedSizePx(Context context, ComponentName component, return new Size(
DeviceProfile profile, int spanX, int spanY) { (spanX * cellSize.x) + hBorderSpacing - padding.left - padding.right,
Size size = getWidgetSizePx(profile, spanX, spanY); (spanY * cellSize.y) + vBorderSpacing - padding.top - padding.bottom);
if (profile.shouldInsetWidgets()) {
return size;
}
Rect padding = getDefaultPaddingForWidget(context, component, /* padding= */ null);
return new Size(size.getWidth() - padding.left - padding.right,
size.getHeight() - padding.top - padding.bottom);
} }
/** /**
@@ -92,8 +71,7 @@ public final class WidgetSizes {
* <p>This size is used by the widget picker. It should NEVER be shared with app widgets. * <p>This size is used by the widget picker. It should NEVER be shared with app widgets.
* *
* <p>For sizes shared with app widgets, please refer to * <p>For sizes shared with app widgets, please refer to
* {@link #getWidgetPaddedSizes(Context, ComponentName, int, int)} & * {@link #getWidgetSizesDp(Context, int, int)} &
* {@link #getWidgetPaddedSizePx(Context, ComponentName, DeviceProfile, int, int)}.
*/ */
public static Size getWidgetItemSizePx(Context context, DeviceProfile profile, public static Size getWidgetItemSizePx(Context context, DeviceProfile profile,
WidgetItem widgetItem) { WidgetItem widgetItem) {
@@ -102,27 +80,7 @@ public final class WidgetSizes {
.getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding); .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
return new Size(dimension, dimension); return new Size(dimension, dimension);
} }
Size widgetItemSize = getWidgetSizePx(profile, widgetItem.spanX, return getWidgetSizePx(profile, widgetItem.spanX, widgetItem.spanY);
widgetItem.spanY, /* recycledCellSize= */ null);
if (profile.shouldInsetWidgets()) {
Rect inset = new Rect();
AppWidgetHostView.getDefaultPaddingForWidget(context, widgetItem.componentName, inset);
return new Size(widgetItemSize.getWidth() + inset.left + inset.right,
widgetItemSize.getHeight() + inset.top + inset.bottom);
}
return widgetItemSize;
}
private static Size getWidgetSizePx(DeviceProfile profile, int spanX, int spanY,
@Nullable Point recycledCellSize) {
final int hBorderSpacing = (spanX - 1) * profile.cellLayoutBorderSpacePx.x;
final int vBorderSpacing = (spanY - 1) * profile.cellLayoutBorderSpacePx.y;
if (recycledCellSize == null) {
recycledCellSize = new Point();
}
profile.getCellSize(recycledCellSize);
return new Size(((spanX * recycledCellSize.x) + hBorderSpacing),
((spanY * recycledCellSize.y) + vBorderSpacing));
} }
/** /**
@@ -154,7 +112,7 @@ public final class WidgetSizes {
*/ */
public static Bundle getWidgetSizeOptions(Context context, ComponentName provider, int spanX, public static Bundle getWidgetSizeOptions(Context context, ComponentName provider, int spanX,
int spanY) { int spanY) {
ArrayList<SizeF> paddedSizes = getWidgetPaddedSizes(context, provider, spanX, spanY); ArrayList<SizeF> paddedSizes = getWidgetSizesDp(context, spanX, spanY);
Rect rect = getMinMaxSizes(paddedSizes); Rect rect = getMinMaxSizes(paddedSizes);
Bundle options = new Bundle(); Bundle options = new Bundle();
@@ -32,6 +32,7 @@ import androidx.test.filters.SmallTest;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -161,7 +162,6 @@ public final class LauncherAppWidgetProviderInfoTest {
int maxPadding = Math.max(Math.max(padding.left, padding.right), int maxPadding = Math.max(Math.max(padding.left, padding.right),
Math.max(padding.top, padding.bottom)); Math.max(padding.top, padding.bottom));
dp.cellLayoutBorderSpacePx.x = dp.cellLayoutBorderSpacePx.y = maxPadding + 1; dp.cellLayoutBorderSpacePx.x = dp.cellLayoutBorderSpacePx.y = maxPadding + 1;
Mockito.when(dp.shouldInsetWidgets()).thenReturn(true);
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = CELL_SIZE * 3; info.minWidth = CELL_SIZE * 3;
@@ -184,7 +184,6 @@ public final class LauncherAppWidgetProviderInfoTest {
int maxPadding = Math.max(Math.max(padding.left, padding.right), int maxPadding = Math.max(Math.max(padding.left, padding.right),
Math.max(padding.top, padding.bottom)); Math.max(padding.top, padding.bottom));
dp.cellLayoutBorderSpacePx.x = dp.cellLayoutBorderSpacePx.y = maxPadding - 1; dp.cellLayoutBorderSpacePx.x = dp.cellLayoutBorderSpacePx.y = maxPadding - 1;
Mockito.when(dp.shouldInsetWidgets()).thenReturn(false);
LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
info.minWidth = CELL_SIZE * 3; info.minWidth = CELL_SIZE * 3;
info.minHeight = CELL_SIZE * 3; info.minHeight = CELL_SIZE * 3;
@@ -257,14 +256,16 @@ public final class LauncherAppWidgetProviderInfoTest {
} }
private InvariantDeviceProfile createIDP() { private InvariantDeviceProfile createIDP() {
DeviceProfile profile = Mockito.mock(DeviceProfile.class); DeviceProfile dp = LauncherAppState.getIDP(mContext)
.getDeviceProfile(mContext).copy(mContext);
DeviceProfile profile = Mockito.spy(dp);
doAnswer(i -> { doAnswer(i -> {
((Point) i.getArgument(0)).set(CELL_SIZE, CELL_SIZE); ((Point) i.getArgument(0)).set(CELL_SIZE, CELL_SIZE);
return null; return null;
}).when(profile).getCellSize(any(Point.class)); }).when(profile).getCellSize(any(Point.class));
Mockito.when(profile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE)); Mockito.when(profile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
profile.cellLayoutBorderSpacePx = new Point(SPACE_SIZE, SPACE_SIZE); profile.cellLayoutBorderSpacePx = new Point(SPACE_SIZE, SPACE_SIZE);
Mockito.when(profile.shouldInsetWidgets()).thenReturn(true); profile.widgetPadding.setEmpty();
InvariantDeviceProfile idp = new InvariantDeviceProfile(); InvariantDeviceProfile idp = new InvariantDeviceProfile();
List<DeviceProfile> supportedProfiles = new ArrayList<>(idp.supportedProfiles); List<DeviceProfile> supportedProfiles = new ArrayList<>(idp.supportedProfiles);
@@ -38,6 +38,7 @@ import androidx.test.filters.SmallTest;
import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.icons.ComponentWithLabel; import com.android.launcher3.icons.ComponentWithLabel;
import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.WidgetItem;
@@ -50,6 +51,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayList; import java.util.ArrayList;
@@ -68,7 +70,6 @@ public final class WidgetsTableUtilsTest {
@Mock @Mock
private IconCache mIconCache; private IconCache mIconCache;
@Mock
private DeviceProfile mTestDeviceProfile; private DeviceProfile mTestDeviceProfile;
private Context mContext; private Context mContext;
@@ -198,13 +199,18 @@ public final class WidgetsTableUtilsTest {
} }
private void initDP() { private void initDP() {
DeviceProfile dp = LauncherAppState.getIDP(mContext)
.getDeviceProfile(mContext).copy(mContext);
mTestDeviceProfile = Mockito.spy(dp);
doAnswer(i -> { doAnswer(i -> {
((Point) i.getArgument(0)).set(CELL_SIZE, CELL_SIZE); ((Point) i.getArgument(0)).set(CELL_SIZE, CELL_SIZE);
return null; return null;
}).when(mTestDeviceProfile).getCellSize(any(Point.class)); }).when(mTestDeviceProfile).getCellSize(any(Point.class));
when(mTestDeviceProfile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE)); when(mTestDeviceProfile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
mTestDeviceProfile.cellLayoutBorderSpacePx = new Point(SPACE_SIZE, SPACE_SIZE); mTestDeviceProfile.cellLayoutBorderSpacePx = new Point(SPACE_SIZE, SPACE_SIZE);
when(mTestDeviceProfile.shouldInsetWidgets()).thenReturn(false); mTestDeviceProfile.widgetPadding.setEmpty();
mTestDeviceProfile.allAppsIconSizePx = 0;
} }
private void initTestWidgets() { private void initTestWidgets() {