feat(widget-stacks): add support for resizing widget stacks

This commit is contained in:
MrSluffy
2025-12-30 09:44:37 +08:00
parent 720d2383d9
commit decb69e855
4 changed files with 384 additions and 48 deletions

View File

@@ -114,8 +114,8 @@
<bool name="config_default_dock_search_bar_force_website">false</bool>
<bool name="config_default_rounded_widgets">true</bool>
<bool name="config_default_allow_widget_overlap">false</bool>
<bool name="config_default_force_widget_resize">false</bool>
<bool name="config_default_widget_unlimited_size">false</bool>
<bool name="config_default_force_widget_resize">true</bool>
<bool name="config_default_widget_unlimited_size">true</bool>
<bool name="config_default_show_status_bar">true</bool>
<bool name="config_default_remember_position">false</bool>
<bool name="config_default_dynamic_hide_status_bar_clock">false</bool>

View File

@@ -27,11 +27,14 @@ import android.widget.FrameLayout
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import app.lawnchair.smartspace.PageIndicator
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Launcher
import com.android.launcher3.R
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.util.MultiTranslateDelegate
import com.android.launcher3.widget.LauncherAppWidgetHostView
import com.android.launcher3.widget.LauncherWidgetHolder
import com.android.launcher3.widget.NavigableAppWidgetHostView
import com.android.launcher3.widget.PendingAppWidgetHostView
import com.android.launcher3.widget.WidgetInflater
import com.android.launcher3.widget.WidgetManagerHelper
@@ -392,6 +395,12 @@ class WidgetStackContentView @JvmOverloads constructor(
} else {
stopAutoRotate()
}
// Apply scaling to all widgets after stack info is updated
// This ensures widgets scale correctly when stack is resized
handler.post {
applyWidgetScaling()
}
}
/**
@@ -573,6 +582,13 @@ class WidgetStackContentView @JvmOverloads constructor(
pendingView.isClickable = false
pendingView.isFocusable = false
// Apply scaling after view is created
if (pendingView is NavigableAppWidgetHostView) {
pendingView.post {
applyScalingToWidget(pendingView)
}
}
// Update position after successful restore
stackInfo?.let { info ->
val needsPositionUpdate = widgetInfo.screenId != info.screenId ||
@@ -646,6 +662,14 @@ class WidgetStackContentView @JvmOverloads constructor(
)
hostView?.isClickable = false
hostView?.isFocusable = false
// Apply scaling after view is created
if (hostView is NavigableAppWidgetHostView) {
hostView.post {
applyScalingToWidget(hostView)
}
}
return hostView
}
@@ -721,6 +745,15 @@ class WidgetStackContentView @JvmOverloads constructor(
)
pendingView.isClickable = false
pendingView.isFocusable = false
// Apply scaling after view is created
if (pendingView is NavigableAppWidgetHostView) {
// Post to apply scaling after layout
pendingView.post {
applyScalingToWidget(pendingView)
}
}
return pendingView as? LauncherAppWidgetHostView
}
@@ -773,6 +806,14 @@ class WidgetStackContentView @JvmOverloads constructor(
hostView?.isClickable = false
hostView?.isFocusable = false
// Apply scaling after view is created
if (hostView is NavigableAppWidgetHostView) {
// Post to apply scaling after layout
hostView.post {
applyScalingToWidget(hostView)
}
}
return hostView
}
@@ -836,6 +877,57 @@ class WidgetStackContentView @JvmOverloads constructor(
}
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
// Apply scaling to all widget views after layout
applyWidgetScaling()
}
/**
* Applies scaling to all widget views to fit within the stack bounds.
* Similar to ShortcutAndWidgetContainer.layoutChild() logic.
*/
private fun applyWidgetScaling() {
synchronized(widgetViews) {
widgetViews.forEach { widgetView ->
if (widgetView is NavigableAppWidgetHostView) {
applyScalingToWidget(widgetView)
}
}
}
}
/**
* Applies scaling to a single widget view to fit within the stack bounds.
* Similar to ShortcutAndWidgetContainer.layoutChild() logic.
*/
private fun applyScalingToWidget(widgetView: NavigableAppWidgetHostView) {
val launcherInstance = launcher ?: return
val profile = launcherInstance.deviceProfile
val widgetInfo = widgetView.tag as? com.android.launcher3.model.data.ItemInfo
if (widgetInfo != null) {
// Get the app widget scale from device profile
val appWidgetScale = profile.getAppWidgetScale(widgetInfo)
val scaleX = appWidgetScale.x
val scaleY = appWidgetScale.y
// Apply scale to fit (use minimum to maintain aspect ratio)
widgetView.setScaleToFit(Math.min(scaleX, scaleY))
// Apply translation for centering (similar to ShortcutAndWidgetContainer)
// Use measured dimensions if layout dimensions aren't available yet
val width = if (widgetView.width > 0) widgetView.width else widgetView.measuredWidth
val height = if (widgetView.height > 0) widgetView.height else widgetView.measuredHeight
if (width > 0 && height > 0) {
widgetView.getTranslateDelegate().setTranslation(
MultiTranslateDelegate.INDEX_WIDGET_CENTERING,
-(width - (width * scaleX)) / 2.0f,
-(height - (height * scaleY)) / 2.0f,
)
}
}
}
/**
* Refreshes widgets that were pending but are now ready
* This ensures widgets transition from "Loading..." to actual content
@@ -918,6 +1010,14 @@ class WidgetStackContentView @JvmOverloads constructor(
} else {
widgetViews.add(view)
}
// Apply scaling to newly loaded widget
if (view is NavigableAppWidgetHostView) {
view.post {
applyScalingToWidget(view)
}
}
needsRefresh = true
android.util.Log.d("WidgetStackContentView", "Loaded missing widget $widgetId at position $positionInStack for stack ${currentStackInfo.stackId}")
} else {
@@ -1007,6 +1107,13 @@ class WidgetStackContentView @JvmOverloads constructor(
realView?.isFocusable = false
if (realView != null) {
// Apply scaling after view is created
if (realView is NavigableAppWidgetHostView) {
realView.post {
applyScalingToWidget(realView)
}
}
// Replace pending view with real widget view
synchronized(widgetViews) {
val actualIndex = widgetViews.indexOfFirst { it.appWidgetId == widgetInfo.appWidgetId }
@@ -1081,6 +1188,13 @@ class WidgetStackContentView @JvmOverloads constructor(
realView?.isFocusable = false
if (realView != null) {
// Apply scaling after view is created
if (realView is NavigableAppWidgetHostView) {
realView.post {
applyScalingToWidget(realView)
}
}
synchronized(widgetViews) {
val actualIndex = widgetViews.indexOfFirst { it.appWidgetId == widgetInfo.appWidgetId }
if (actualIndex != -1 && actualIndex < widgetViews.size) {
@@ -1368,6 +1482,11 @@ class WidgetStackContentView @JvmOverloads constructor(
// Widgets must be attached to receive live updates from AppWidgetManager
container.addView(view)
// Apply scaling to widget after it's added to container
if (view is NavigableAppWidgetHostView) {
applyScalingToWidget(view)
}
// Ensure widget is properly set up for updates
if (view is LauncherAppWidgetHostView) {
val widgetId = view.appWidgetId
@@ -1377,6 +1496,11 @@ class WidgetStackContentView @JvmOverloads constructor(
// Widget is now attached and will receive updates automatically
android.util.Log.d("WidgetStackContentView", "Widget $widgetId attached at position $position - will receive live updates")
// Apply scaling again after layout (in case dimensions changed)
if (view is NavigableAppWidgetHostView) {
applyScalingToWidget(view)
}
// Request an immediate update to ensure widget is fresh
try {
val appWidgetManager = AppWidgetManager.getInstance(context)

View File

@@ -43,6 +43,7 @@ import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.util.PendingRequestArgs;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -57,6 +58,8 @@ import java.util.List;
import app.lawnchair.preferences2.PreferenceManager2;
import app.lawnchair.theme.color.tokens.ColorTokens;
import app.lawnchair.theme.drawable.DrawableTokens;
import app.lawnchair.widget.WidgetStackInfo;
import app.lawnchair.widget.WidgetStackView;
public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
private static final int SNAP_DURATION_MS = 150;
@@ -85,6 +88,7 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
private final List<Rect> mSystemGestureExclusionRects = new ArrayList<>(HANDLE_COUNT);
private LauncherAppWidgetHostView mWidgetView;
private WidgetStackView mWidgetStackView;
private CellLayout mCellLayout;
private DragLayer mDragLayer;
private ImageButton mReconfigureButton;
@@ -250,6 +254,32 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
frame.post(() -> frame.snapToWidget(false));
}
public static void showForWidgetStack(WidgetStackView widgetStack, CellLayout cellLayout) {
PreferenceManager2 pref2 = PreferenceManager2.getInstance(widgetStack.getContext());
boolean force = PreferenceExtensionsKt.firstBlocking(pref2.getForceWidgetResize());
boolean unlimited = PreferenceExtensionsKt.firstBlocking(pref2.getWidgetUnlimitedSize());
// If widget stack is not added to view hierarchy, we cannot show resize frame at
// correct location
if (widgetStack.getParent() == null) {
return;
}
Launcher launcher = Launcher.getLauncher(cellLayout.getContext());
AbstractFloatingView.closeAllOpenViews(launcher);
DragLayer dl = launcher.getDragLayer();
AppWidgetResizeFrame frame = (AppWidgetResizeFrame) launcher.getLayoutInflater()
.inflate(R.layout.app_widget_resize_frame, dl, false);
ImageView imageView = frame.findViewById(R.id.widget_resize_frame);
imageView.setImageDrawable(DrawableTokens.WidgetResizeFrame.resolve(launcher));
frame.setupForWidgetStack(widgetStack, cellLayout, dl, force, unlimited);
((DragLayer.LayoutParams) frame.getLayoutParams()).customPosition = true;
dl.addView(frame);
frame.mIsOpen = true;
frame.post(() -> frame.snapToWidget(false));
}
private void setCornerRadiusFromWidget() {
if (mWidgetView != null && mWidgetView.hasEnforcedCornerRadius()) {
float enforcedCornerRadius = mWidgetView.getEnforcedCornerRadius();
@@ -375,6 +405,82 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mWidgetView.addOnLayoutChangeListener(mWidgetViewLayoutListener);
}
private void setupForWidgetStack(WidgetStackView widgetStackView, CellLayout cellLayout,
DragLayer dragLayer, boolean force, boolean unlimited) {
mCellLayout = cellLayout;
mWidgetStackView = widgetStackView;
mWidgetView = null; // Clear widget view when using stack
mDragLayer = dragLayer;
InvariantDeviceProfile idp = LauncherAppState.getIDP(cellLayout.getContext());
app.lawnchair.widget.WidgetStackInfo stackInfo = widgetStackView.getStackInfo();
if (stackInfo == null) {
return;
}
// For widget stacks, we allow resizing in both directions by default
// Use the minimum and maximum spans from the device profile
int resizeMode = AppWidgetProviderInfo.RESIZE_BOTH;
if (unlimited) {
mMinHSpan = 1;
mMinVSpan = 1;
mMaxHSpan = idp.numColumns;
mMaxVSpan = idp.numRows;
} else {
// Use current stack size as base, allow resizing from 1x1 to full screen
mMinHSpan = 1;
mMinVSpan = 1;
mMaxHSpan = idp.numColumns;
mMaxVSpan = idp.numRows;
}
// Show all resize handles for widget stacks
mVerticalResizeActive = mMinVSpan < idp.numRows && mMaxVSpan > 1 && mMinVSpan < mMaxVSpan;
if (!mVerticalResizeActive) {
mDragHandles[INDEX_TOP].setVisibility(GONE);
mDragHandles[INDEX_BOTTOM].setVisibility(GONE);
}
mHorizontalResizeActive = mMinHSpan < idp.numColumns && mMaxHSpan > 1 && mMinHSpan < mMaxHSpan;
if (!mHorizontalResizeActive) {
mDragHandles[INDEX_LEFT].setVisibility(GONE);
mDragHandles[INDEX_RIGHT].setVisibility(GONE);
}
// Hide reconfigure button for widget stacks (not applicable)
mReconfigureButton = (ImageButton) findViewById(R.id.widget_reconfigure_button);
mReconfigureButton.setVisibility(GONE);
CellLayoutLayoutParams lp = (CellLayoutLayoutParams) mWidgetStackView.getLayoutParams();
ItemInfo widgetInfo = (ItemInfo) mWidgetStackView.getTag();
if (widgetInfo != null) {
CellPos presenterPos = mLauncher.getCellPosMapper().mapModelToPresenter(widgetInfo);
lp.setCellX(presenterPos.cellX);
lp.setTmpCellX(presenterPos.cellX);
lp.setCellY(presenterPos.cellY);
lp.setTmpCellY(presenterPos.cellY);
lp.cellHSpan = widgetInfo.spanX;
lp.cellVSpan = widgetInfo.spanY;
lp.isLockedToGrid = true;
}
// When we create the resize frame, we first mark all cells as unoccupied. The
// appropriate
// cells (same if not resized, or different) will be marked as occupied when the
// resize
// frame is dismissed.
mCellLayout.markCellsAsUnoccupiedForView(mWidgetStackView);
if (widgetInfo != null) {
mLauncher.getStatsLogManager()
.logger()
.withInstanceId(logInstanceId)
.withItemInfo(widgetInfo)
.log(LAUNCHER_WIDGET_RESIZE_STARTED);
}
setOnKeyListener(this);
}
public boolean beginResizeIfPointInRegion(int x, int y) {
mLeftBorderActive = x < mTouchTargetWidth;
mRightBorderActive = x > getWidth() - mTouchTargetWidth;
@@ -491,7 +597,12 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
* Based on the current deltas, we determine if and how to resize the widget.
*/
private void resizeWidgetIfNeeded(boolean onDismiss) {
ViewGroup.LayoutParams wlp = mWidgetView.getLayoutParams();
View targetView = mWidgetView != null ? mWidgetView : (View) mWidgetStackView;
if (targetView == null) {
return;
}
ViewGroup.LayoutParams wlp = targetView.getLayoutParams();
if (!(wlp instanceof CellLayoutLayoutParams)) {
return;
}
@@ -550,30 +661,101 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
mLastDirectionVector[1] = mDirectionVector[1];
}
// We don't want to evaluate resize if a widget was pending config activity and
// was already
// occupying a space on the screen. This otherwise will cause reorder algorithm
// evaluate a
// different location for the widget and cause a jump.
if (!(mWidgetView instanceof PendingAppWidgetHostView) && mCellLayout.createAreaForResize(
cellX, cellY, spanX, spanY, mWidgetView, mDirectionVector, onDismiss)) {
if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY)) {
mStateAnnouncer.announce(
mLauncher.getString(R.string.widget_resized, spanX, spanY));
// Handle widget stack resize
if (mWidgetStackView != null) {
if (mCellLayout.createAreaForResize(
cellX, cellY, spanX, spanY, mWidgetStackView, mDirectionVector, onDismiss)) {
if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY)) {
mStateAnnouncer.announce(
mLauncher.getString(R.string.widget_resized, spanX, spanY));
}
lp.setTmpCellX(cellX);
lp.setTmpCellY(cellY);
lp.cellHSpan = spanX;
lp.cellVSpan = spanY;
mRunningVInc += vSpanDelta;
mRunningHInc += hSpanDelta;
// Update stack info with new size
WidgetStackInfo stackInfo = mWidgetStackView.getStackInfo();
if (stackInfo != null) {
ItemInfo itemInfo = (ItemInfo) mWidgetStackView.getTag();
if (itemInfo != null) {
int container = itemInfo.container;
int screenId = mLauncher.getCellPosMapper().mapModelToPresenter(itemInfo).screenId;
WidgetStackInfo updatedStackInfo = stackInfo.copy(
stackInfo.getStackId(),
stackInfo.getWidgetIds(),
stackInfo.getCurrentIndex(),
stackInfo.getAutoRotate(),
container,
screenId,
cellX,
cellY,
spanX,
spanY
);
// Update all widgets in the stack to the new size
final com.android.launcher3.model.BgDataModel bgDataModel = mLauncher.getModel().getBgDataModel();
synchronized (bgDataModel) {
for (Integer widgetIdObj : stackInfo.getWidgetIds()) {
int widgetId = widgetIdObj;
for (ItemInfo item : bgDataModel.itemsIdMap) {
if (item instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo wInfo = (LauncherAppWidgetInfo) item;
if (wInfo.appWidgetId == widgetId) {
mLauncher.getModelWriter().modifyItemInDatabase(
wInfo, container, screenId,
cellX, cellY, spanX, spanY
);
break;
}
}
}
}
}
// Save updated stack info to database
mLauncher.getModelWriter().saveWidgetStack(updatedStackInfo);
// Update the view with new stack info
mWidgetStackView.setStackInfo(updatedStackInfo);
// Update item info
itemInfo.spanX = spanX;
itemInfo.spanY = spanY;
}
}
}
} else if (mWidgetView != null) {
// We don't want to evaluate resize if a widget was pending config activity and
// was already
// occupying a space on the screen. This otherwise will cause reorder algorithm
// evaluate a
// different location for the widget and cause a jump.
if (!(mWidgetView instanceof PendingAppWidgetHostView) && mCellLayout.createAreaForResize(
cellX, cellY, spanX, spanY, mWidgetView, mDirectionVector, onDismiss)) {
if (mStateAnnouncer != null && (lp.cellHSpan != spanX || lp.cellVSpan != spanY)) {
mStateAnnouncer.announce(
mLauncher.getString(R.string.widget_resized, spanX, spanY));
}
lp.setTmpCellX(cellX);
lp.setTmpCellY(cellY);
lp.cellHSpan = spanX;
lp.cellVSpan = spanY;
mRunningVInc += vSpanDelta;
mRunningHInc += hSpanDelta;
lp.setTmpCellX(cellX);
lp.setTmpCellY(cellY);
lp.cellHSpan = spanX;
lp.cellVSpan = spanY;
mRunningVInc += vSpanDelta;
mRunningHInc += hSpanDelta;
if (!onDismiss) {
WidgetSizes.updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
if (!onDismiss) {
WidgetSizes.updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
}
}
}
mWidgetView.requestLayout();
targetView.requestLayout();
}
@Override
@@ -583,11 +765,17 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
// We are done with resizing the widget. Save the widget size & position to
// LauncherModel
resizeWidgetIfNeeded(true);
mLauncher.getStatsLogManager()
.logger()
.withInstanceId(logInstanceId)
.withItemInfo((ItemInfo) mWidgetView.getTag())
.log(LAUNCHER_WIDGET_RESIZE_COMPLETED);
View targetView = mWidgetView != null ? mWidgetView : (View) mWidgetStackView;
if (targetView != null) {
ItemInfo itemInfo = (ItemInfo) targetView.getTag();
if (itemInfo != null) {
mLauncher.getStatsLogManager()
.logger()
.withInstanceId(logInstanceId)
.withItemInfo(itemInfo)
.log(LAUNCHER_WIDGET_RESIZE_COMPLETED);
}
}
}
private void onTouchUp() {
@@ -609,11 +797,17 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
* relative to the {@link DragLayer}.
*/
private void getSnappedRectRelativeToDragLayer(@NonNull Rect out) {
float scale = mWidgetView.getScaleToFit();
if (FeatureFlags.ENABLE_WIDGET_TRANSITION_FOR_RESIZING.get()) {
View targetView = mWidgetView != null ? mWidgetView : (View) mWidgetStackView;
if (targetView == null) {
out.setEmpty();
return;
}
float scale = mWidgetView != null ? mWidgetView.getScaleToFit() : 1.0f;
if (FeatureFlags.ENABLE_WIDGET_TRANSITION_FOR_RESIZING.get() && mWidgetView != null) {
getViewRectRelativeToDragLayer(out);
} else {
mDragLayer.getViewRectRelativeToSelf(mWidgetView, out);
mDragLayer.getViewRectRelativeToSelf(targetView, out);
}
int width = 2 * mBackgroundPadding + Math.round(scale * out.width());
@@ -658,8 +852,12 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
// The widget is guaranteed to be attached to the cell layout at this point,
// thus setting
// the transition here
View targetView = mWidgetView != null ? mWidgetView : (View) mWidgetStackView;
if (targetView == null) {
return;
}
if (FeatureFlags.ENABLE_WIDGET_TRANSITION_FOR_RESIZING.get()
&& mWidgetView.getLayoutTransition() == null) {
&& mWidgetView != null && mWidgetView.getLayoutTransition() == null) {
final LayoutTransition transition = new LayoutTransition();
transition.setDuration(RESIZE_TRANSITION_DURATION_MS);
transition.enableTransitionType(LayoutTransition.CHANGING);
@@ -813,12 +1011,14 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
@Override
protected void handleClose(boolean animate) {
if (FeatureFlags.ENABLE_WIDGET_TRANSITION_FOR_RESIZING.get()) {
mWidgetView.clearCellChildViewPreLayoutListener();
mWidgetView.setLayoutTransition(null);
if (mWidgetView != null) {
if (FeatureFlags.ENABLE_WIDGET_TRANSITION_FOR_RESIZING.get()) {
mWidgetView.clearCellChildViewPreLayoutListener();
mWidgetView.setLayoutTransition(null);
}
mWidgetView.removeOnLayoutChangeListener(mWidgetViewLayoutListener);
}
mDragLayer.removeView(this);
mWidgetView.removeOnLayoutChangeListener(mWidgetViewLayoutListener);
}
private void updateInvalidResizeEffect(CellLayout cellLayout, CellLayout pairedCellLayout,

View File

@@ -56,7 +56,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -2816,12 +2815,12 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
lp.isLockedToGrid = true;
if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
cell instanceof LauncherAppWidgetHostView) {
(cell instanceof LauncherAppWidgetHostView || cell instanceof WidgetStackView)) {
// We post this call so that the widget has a chance to be placed
// in its final location
onCompleteRunnable = getWidgetResizeFrameRunnable(options,
(LauncherAppWidgetHostView) cell, dropTargetLayout, forceWidgetResize);
cell, dropTargetLayout, forceWidgetResize);
}
// If this is a widget stack, update the stack info position
@@ -2906,7 +2905,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
if (pageIsVisible) {
onCompleteRunnable = getWidgetResizeFrameRunnable(options,
(LauncherAppWidgetHostView) cell, cellLayout, forceWidgetResize);
cell, cellLayout, forceWidgetResize);
}
}
}
@@ -2971,15 +2970,28 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
@Nullable
private Runnable getWidgetResizeFrameRunnable(DragOptions options,
LauncherAppWidgetHostView hostView, CellLayout cellLayout, boolean force) {
AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
boolean shouldResize = (pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) || force;
if (pInfo != null && shouldResize && !options.isAccessibleDrag) {
return () -> {
if (!isPageInTransition()) {
AppWidgetResizeFrame.showForWidget(hostView, cellLayout);
}
};
View widgetView, CellLayout cellLayout, boolean force) {
if (widgetView instanceof LauncherAppWidgetHostView) {
LauncherAppWidgetHostView hostView = (LauncherAppWidgetHostView) widgetView;
AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
boolean shouldResize = (pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE) || force;
if (pInfo != null && shouldResize && !options.isAccessibleDrag) {
return () -> {
if (!isPageInTransition()) {
AppWidgetResizeFrame.showForWidget(hostView, cellLayout);
}
};
}
} else if (widgetView instanceof WidgetStackView) {
WidgetStackView stackView = (WidgetStackView) widgetView;
// Widget stacks are always resizable
if (!options.isAccessibleDrag) {
return () -> {
if (!isPageInTransition()) {
AppWidgetResizeFrame.showForWidgetStack(stackView, cellLayout);
}
};
}
}
return null;
}