From e41dd483e63ec1aa241efb5005b11a2760800a9e Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 4 Jun 2021 17:31:02 -0700 Subject: [PATCH 1/6] New folder icon style (uncropped icons). - Switch Circle to PathShape as it allows for more flexibility on choosing what gets cropped. - Remove shadows, and stroke. Bug: 188095988 Test: manual Change-Id: I602b3efcd35c2c11dc3461f49099c2f2a56eae59 --- res/layout/user_folder_icon_normalized.xml | 1 - .../folder/ClippedFolderIconLayoutRule.java | 12 +++---- src/com/android/launcher3/folder/Folder.java | 23 +++++++++++-- .../folder/FolderAnimationManager.java | 19 ++++++++++- .../android/launcher3/folder/FolderIcon.java | 3 -- .../launcher3/folder/FolderPagedView.java | 24 +++++++++++-- .../launcher3/folder/PreviewBackground.java | 10 +++++- .../android/launcher3/graphics/IconShape.java | 34 ++++++++++++++++--- 8 files changed, 102 insertions(+), 24 deletions(-) diff --git a/res/layout/user_folder_icon_normalized.xml b/res/layout/user_folder_icon_normalized.xml index 8b188577a8..15131f11d7 100644 --- a/res/layout/user_folder_icon_normalized.xml +++ b/res/layout/user_folder_icon_normalized.xml @@ -18,7 +18,6 @@ xmlns:launcher="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:background="@drawable/round_rect_folder" android:orientation="vertical" > { +public class FolderPagedView extends PagedView implements ClipPathView { private static final String TAG = "FolderPagedView"; @@ -89,6 +91,8 @@ public class FolderPagedView extends PagedView { private Folder mFolder; + private Path mClipPath; + // If the views are attached to the folder or not. A folder should be bound when its // animating or is open. private boolean mViewsBound = false; @@ -128,8 +132,16 @@ public class FolderPagedView extends PagedView { @Override protected void dispatchDraw(Canvas canvas) { - mFocusIndicatorHelper.draw(canvas); - super.dispatchDraw(canvas); + if (mClipPath != null) { + int count = canvas.save(); + canvas.clipPath(mClipPath); + mFocusIndicatorHelper.draw(canvas); + super.dispatchDraw(canvas); + canvas.restoreToCount(count); + } else { + mFocusIndicatorHelper.draw(canvas); + super.dispatchDraw(canvas); + } } /** @@ -628,4 +640,10 @@ public class FolderPagedView extends PagedView { public int itemsPerPage() { return mOrganizer.getMaxItemsPerPage(); } + + @Override + public void setClipPath(Path clipPath) { + mClipPath = clipPath; + invalidate(); + } } diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java index 4eab63e54f..204decbee4 100644 --- a/src/com/android/launcher3/folder/PreviewBackground.java +++ b/src/com/android/launcher3/folder/PreviewBackground.java @@ -51,6 +51,7 @@ import com.android.launcher3.views.ActivityContext; public class PreviewBackground extends CellLayout.DelegatedCellDrawing { private static final boolean DRAW_SHADOW = false; + private static final boolean DRAW_STROKE = false; private static final int CONSUMPTION_ANIMATION_DURATION = 100; @@ -303,6 +304,10 @@ public class PreviewBackground extends CellLayout.DelegatedCellDrawing { } public void animateBackgroundStroke() { + if (!DRAW_STROKE) { + return; + } + if (mStrokeAlphaAnimator != null) { mStrokeAlphaAnimator.cancel(); } @@ -319,6 +324,9 @@ public class PreviewBackground extends CellLayout.DelegatedCellDrawing { } public void drawBackgroundStroke(Canvas canvas) { + if (!DRAW_STROKE) { + return; + } mPaint.setColor(setColorAlphaBound(mStrokeColor, mStrokeAlpha)); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(mStrokeWidth); @@ -363,7 +371,7 @@ public class PreviewBackground extends CellLayout.DelegatedCellDrawing { } mDrawingDelegate = null; - isClipping = true; + isClipping = false; invalidate(); } diff --git a/src/com/android/launcher3/graphics/IconShape.java b/src/com/android/launcher3/graphics/IconShape.java index 2da679c422..f82b07ebfa 100644 --- a/src/com/android/launcher3/graphics/IconShape.java +++ b/src/com/android/launcher3/graphics/IconShape.java @@ -156,19 +156,43 @@ public abstract class IconShape { } } - public static final class Circle extends SimpleRectShape { + public static final class Circle extends PathShape { - @Override - public void drawShape(Canvas canvas, float offsetX, float offsetY, float radius, Paint p) { - canvas.drawCircle(radius + offsetX, radius + offsetY, radius, p); + private final float[] mTempRadii = new float[8]; + + protected AnimatorUpdateListener newUpdateListener(Rect startRect, Rect endRect, + float endRadius, Path outPath) { + float r1 = getStartRadius(startRect); + + float[] startValues = new float[] { + startRect.left, startRect.top, startRect.right, startRect.bottom, r1, r1}; + float[] endValues = new float[] { + endRect.left, endRect.top, endRect.right, endRect.bottom, endRadius, endRadius}; + + FloatArrayEvaluator evaluator = new FloatArrayEvaluator(new float[6]); + + return (anim) -> { + float progress = (Float) anim.getAnimatedValue(); + float[] values = evaluator.evaluate(progress, startValues, endValues); + outPath.addRoundRect( + values[0], values[1], values[2], values[3], + getRadiiArray(values[4], values[5]), Path.Direction.CW); + }; } + private float[] getRadiiArray(float r1, float r2) { + mTempRadii[0] = mTempRadii [1] = mTempRadii[2] = mTempRadii[3] = + mTempRadii[6] = mTempRadii[7] = r1; + mTempRadii[4] = mTempRadii[5] = r2; + return mTempRadii; + } + + @Override public void addToPath(Path path, float offsetX, float offsetY, float radius) { path.addCircle(radius + offsetX, radius + offsetY, radius, Path.Direction.CW); } - @Override protected float getStartRadius(Rect startRect) { return startRect.width() / 2f; } From 0fe2342445719852ffe09944eab06adde618654f Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Mon, 31 May 2021 13:31:16 +0800 Subject: [PATCH 2/6] Pre-set splash screen as icon-style when launch activity from Launcher. Specify icon style splash screen when launch activity from Launcher. Bug: 188023621 Bug: 189293785 Test: Start application from Launcher/Recents. Change-Id: I13b7cd67576cf8822e86ff90971d6bb1a24d1a91 --- .../src/com/android/launcher3/BaseQuickstepLauncher.java | 2 ++ quickstep/src/com/android/quickstep/RecentsActivity.java | 5 ++++- quickstep/src/com/android/quickstep/TaskShortcutFactory.java | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index c13225abb7..1bf36278ca 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -37,6 +37,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; import android.view.View; +import android.window.SplashScreen; import androidx.annotation.Nullable; @@ -435,6 +436,7 @@ public abstract class BaseQuickstepLauncher extends Launcher ActivityOptionsCompat.setLauncherSourceInfo( activityOptions.options, mLastTouchUpTime); } + activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); addLaunchCookie(item, activityOptions.options); return activityOptions; } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 0e9e3ad029..0e85ec3760 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -40,6 +40,7 @@ import android.os.Handler; import android.os.Looper; import android.view.SurfaceControl.Transaction; import android.view.View; +import android.window.SplashScreen; import androidx.annotation.Nullable; @@ -222,9 +223,11 @@ public final class RecentsActivity extends StatefulActivity { wrapper, RECENTS_LAUNCH_DURATION, RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION - STATUS_BAR_TRANSITION_PRE_DELAY); - return new ActivityOptionsWrapper( + final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper( ActivityOptionsCompat.makeRemoteAnimation(adapterCompat), onEndCallback); + activityOptions.options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); + return activityOptions; } /** diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index 4ec1c15f4d..a078bf331e 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -30,6 +30,7 @@ import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.view.View; +import android.window.SplashScreen; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.DeviceProfile; @@ -165,6 +166,9 @@ public interface TaskShortcutFactory { dismissTaskMenuView(mTarget); ActivityOptions options = mFactory.makeLaunchOptions(mTarget); + if (options != null) { + options.setSplashscreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON); + } if (options != null && ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId, options)) { From 26ab4621ce5b4079c297c65cc94e33a0d98fe8a5 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 7 Jun 2021 14:56:12 -0700 Subject: [PATCH 3/6] Have AlphaUpdateListener update visibility in onAnimationEnd() Previously we were only updating visibility in onAnimationSuccess(), which doesn't handle the canceled case. Test: swipe up from nav bar twice in all apps, ensure all apps is invisible/non-interactable Bug: 190315266 Change-Id: Ic59e6d4b404de4ee2d17c45d6fa59e2aee70c65f --- src/com/android/launcher3/anim/AlphaUpdateListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/anim/AlphaUpdateListener.java b/src/com/android/launcher3/anim/AlphaUpdateListener.java index eabd283699..8dad1b4fa5 100644 --- a/src/com/android/launcher3/anim/AlphaUpdateListener.java +++ b/src/com/android/launcher3/anim/AlphaUpdateListener.java @@ -17,6 +17,7 @@ package com.android.launcher3.anim; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.view.View; @@ -25,7 +26,7 @@ import android.view.ViewGroup; /** * A convenience class to update a view's visibility state after an alpha animation. */ -public class AlphaUpdateListener extends AnimationSuccessListener +public class AlphaUpdateListener extends AnimatorListenerAdapter implements AnimatorUpdateListener { public static final float ALPHA_CUTOFF_THRESHOLD = 0.01f; @@ -41,7 +42,7 @@ public class AlphaUpdateListener extends AnimationSuccessListener } @Override - public void onAnimationSuccess(Animator animator) { + public void onAnimationEnd(Animator animator) { updateVisibility(mView); } From 1fb6718c85e75a818eeb888208466f19677e8c72 Mon Sep 17 00:00:00 2001 From: zakcohen Date: Mon, 7 Jun 2021 14:54:15 -0700 Subject: [PATCH 4/6] DO NOT MERGE Use focused task id for getting task size When getting the selected task size, look at the focused task id, not the running task id. I believe this was a typo from the original change. Bug: 190399315 Test: Local build and flash and run Change-Id: Ice92e0562765f4f0142e27da0c38140df4c11425 --- quickstep/src/com/android/quickstep/views/RecentsView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 74906ddac0..a46bc6b72d 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1358,7 +1358,7 @@ public abstract class RecentsView 1) { taskWidth = boxLength; From fd9bfd3aabe8d1d249188b4e047a4389cdc282f1 Mon Sep 17 00:00:00 2001 From: Stevie Kideckel Date: Mon, 7 Jun 2021 15:46:21 +0000 Subject: [PATCH 5/6] Fix accounting for the position/offset of headers with collapsing views The offset should be taken before views are modified, the position should be taken after. This fixes an off by one issue when expanding a header below another already expanded header. Bug: 183378651 Test: verified locally Change-Id: I4987d57846d7bcde23b76280f800f19350b3521e --- .../widget/picker/WidgetsListAdapter.java | 80 +++++++++++++------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java index 826c244a92..150bd9902f 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java @@ -202,11 +202,16 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC mDiffReporter.process(mVisibleEntries, newVisibleEntries, mRowComparator); } + /** Returns whether {@code entry} matches {@link #mWidgetsContentVisiblePackageUserKey}. */ private boolean isHeaderForVisibleContent(WidgetsListBaseEntry entry) { + return isHeaderForPackageUserKey(entry, mWidgetsContentVisiblePackageUserKey); + } + + /** Returns whether {@code entry} matches {@code key}. */ + private boolean isHeaderForPackageUserKey(WidgetsListBaseEntry entry, PackageUserKey key) { return (entry instanceof WidgetsListHeaderEntry || entry instanceof WidgetsListSearchHeaderEntry) - && new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user) - .equals(mWidgetsContentVisiblePackageUserKey); + && new PackageUserKey(entry.mPkgItem.packageName, entry.mPkgItem.user).equals(key); } /** @@ -270,36 +275,68 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC @Override public void onHeaderClicked(boolean showWidgets, PackageUserKey packageUserKey) { + // Ignore invalid clicks, such as collapsing a package that isn't currently expanded. + if (!showWidgets && !packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) return; + if (showWidgets) { mWidgetsContentVisiblePackageUserKey = packageUserKey; - updateVisibleEntries(); - // Scroll the layout manager to the header position to keep it anchored to the same - // position. - scrollToPositionAndMaintainOffset(getSelectedHeaderPosition()); mLauncher.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_APP_EXPANDED); - } else if (packageUserKey.equals(mWidgetsContentVisiblePackageUserKey)) { - OptionalInt previouslySelectedPosition = getSelectedHeaderPosition(); - + } else { mWidgetsContentVisiblePackageUserKey = null; - updateVisibleEntries(); - - // Scroll to the header that was just collapsed so it maintains its scroll offset. - scrollToPositionAndMaintainOffset(previouslySelectedPosition); } + + // Get the current top of the header with the matching key before adjusting the visible + // entries. + OptionalInt topForPackageUserKey = + getOffsetForPosition(getPositionForPackageUserKey(packageUserKey)); + + updateVisibleEntries(); + + // Get the position for the clicked header after adjusting the visible entries. The + // position may have changed if another header had previously been expanded. + OptionalInt positionForPackageUserKey = getPositionForPackageUserKey(packageUserKey); + scrollToPositionAndMaintainOffset(positionForPackageUserKey, topForPackageUserKey); } - private OptionalInt getSelectedHeaderPosition() { + /** + * Returns the position of {@code key} in {@link #mVisibleEntries}, or empty if it's not + * present. + */ + private OptionalInt getPositionForPackageUserKey(PackageUserKey key) { return IntStream.range(0, mVisibleEntries.size()) - .filter(index -> isHeaderForVisibleContent(mVisibleEntries.get(index))) + .filter(index -> isHeaderForPackageUserKey(mVisibleEntries.get(index), key)) .findFirst(); } /** - * Scrolls to the selected header position. LinearLayoutManager scrolls the minimum distance - * necessary, so this will keep the selected header in place during clicks, without interrupting - * the animation. + * Returns the top of {@code positionOptional} in the recycler view, or empty if its view + * can't be found for any reason, including the position not being currently visible. The + * returned value does not include the top padding of the recycler view. */ - private void scrollToPositionAndMaintainOffset(OptionalInt positionOptional) { + private OptionalInt getOffsetForPosition(OptionalInt positionOptional) { + if (!positionOptional.isPresent() || mRecyclerView == null) return OptionalInt.empty(); + + RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); + if (layoutManager == null) return OptionalInt.empty(); + + View view = layoutManager.findViewByPosition(positionOptional.getAsInt()); + if (view == null) return OptionalInt.empty(); + + return OptionalInt.of(layoutManager.getDecoratedTop(view)); + } + + /** + * Scrolls to the selected header position with the provided offset. LinearLayoutManager + * scrolls the minimum distance necessary, so this will keep the selected header in place during + * clicks, without interrupting the animation. + * + * @param positionOptional The position too scroll to. No scrolling will be done if empty. + * @param offsetOptional The offset from the top to maintain. If empty, then the list will + * scroll to the top of the position. + */ + private void scrollToPositionAndMaintainOffset( + OptionalInt positionOptional, + OptionalInt offsetOptional) { if (!positionOptional.isPresent() || mRecyclerView == null) return; int position = positionOptional.getAsInt(); @@ -317,12 +354,9 @@ public class WidgetsListAdapter extends Adapter implements OnHeaderC // Scroll to the header view's current offset, accounting for the recycler view's padding. // If the header view couldn't be found, then it will appear at the top of the list. - View headerView = layoutManager.findViewByPosition(position); - int targetHeaderViewTop = - headerView == null ? 0 : layoutManager.getDecoratedTop(headerView); layoutManager.scrollToPositionWithOffset( position, - targetHeaderViewTop - mRecyclerView.getPaddingTop()); + offsetOptional.orElse(0) - mRecyclerView.getPaddingTop()); } /** From 1d47d8c705928870badfb510056ec2b16f3a093c Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Tue, 1 Jun 2021 22:58:37 +0100 Subject: [PATCH 6/6] Use grid size as the upper bound for widgets' default size in initSpans Test: In Pixel 4, drag a monthly view Google calendar widget to a new home page from the full widgets picker. The widget outline is correctly shown. Bug: 189060113 Change-Id: I33113b29cc8923098de95f1d5eb14c2b02429de1 --- .../LauncherAppWidgetProviderInfoTest.java | 74 +++++++++++++++++++ .../widget/LauncherAppWidgetProviderInfo.java | 47 +++++++++++- .../android/launcher3/model/WidgetsModel.java | 8 +- 3 files changed, 122 insertions(+), 7 deletions(-) diff --git a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java index d18138f8d2..c7286e5676 100644 --- a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java +++ b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java @@ -40,6 +40,8 @@ import org.robolectric.RuntimeEnvironment; public final class LauncherAppWidgetProviderInfoTest { private static final int CELL_SIZE = 50; + private static final int NUM_OF_COLS = 4; + private static final int NUM_OF_ROWS = 5; private Context mContext; @@ -75,6 +77,33 @@ public final class LauncherAppWidgetProviderInfoTest { assertThat(info.spanY).isEqualTo(2); } + @Test + public void + initSpans_minWidthLargerThanGridColumns_shouldInitializeSpansToAtMostTheGridColumns() { + LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); + info.minWidth = CELL_SIZE * (NUM_OF_COLS + 1); + info.minHeight = 20; + InvariantDeviceProfile idp = createIDP(); + + info.initSpans(mContext, idp); + + assertThat(info.spanX).isEqualTo(NUM_OF_COLS); + assertThat(info.spanY).isEqualTo(1); + } + + @Test + public void initSpans_minHeightLargerThanGridRows_shouldInitializeSpansToAtMostTheGridRows() { + LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); + info.minWidth = 20; + info.minHeight = 50 * (NUM_OF_ROWS + 1); + InvariantDeviceProfile idp = createIDP(); + + info.initSpans(mContext, idp); + + assertThat(info.spanX).isEqualTo(1); + assertThat(info.spanY).isEqualTo(NUM_OF_ROWS); + } + @Test public void initSpans_minResizeWidthUnspecified_shouldInitializeMinSpansToOne() { LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); @@ -153,6 +182,49 @@ public final class LauncherAppWidgetProviderInfoTest { assertThat(info.minSpanY).isEqualTo(3); } + @Test + public void isMinSizeFulfilled_minWidthAndHeightWithinGridSize_shouldReturnTrue() { + LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); + info.minWidth = 80; + info.minHeight = 80; + info.minResizeWidth = 50; + info.minResizeHeight = 50; + InvariantDeviceProfile idp = createIDP(); + + info.initSpans(mContext, idp); + + assertThat(info.isMinSizeFulfilled()).isTrue(); + } + + @Test + public void + isMinSizeFulfilled_minWidthAndMinResizeWidthExceededGridColumns_shouldReturnFalse() { + LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); + info.minWidth = CELL_SIZE * (NUM_OF_COLS + 2); + info.minHeight = 80; + info.minResizeWidth = CELL_SIZE * (NUM_OF_COLS + 1); + info.minResizeHeight = 50; + InvariantDeviceProfile idp = createIDP(); + + info.initSpans(mContext, idp); + + assertThat(info.isMinSizeFulfilled()).isFalse(); + } + + @Test + public void isMinSizeFulfilled_minHeightAndMinResizeHeightExceededGridRows_shouldReturnFalse() { + LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo(); + info.minWidth = 80; + info.minHeight = CELL_SIZE * (NUM_OF_ROWS + 2); + info.minResizeWidth = 50; + info.minResizeHeight = CELL_SIZE * (NUM_OF_ROWS + 1); + InvariantDeviceProfile idp = createIDP(); + + info.initSpans(mContext, idp); + + assertThat(info.isMinSizeFulfilled()).isFalse(); + } + private InvariantDeviceProfile createIDP() { DeviceProfile profile = Mockito.mock(DeviceProfile.class); doAnswer(i -> { @@ -163,6 +235,8 @@ public final class LauncherAppWidgetProviderInfoTest { InvariantDeviceProfile idp = new InvariantDeviceProfile(); idp.supportedProfiles.add(profile); + idp.numColumns = NUM_OF_COLS; + idp.numRows = NUM_OF_ROWS; return idp; } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java index 14108f614c..5a29171361 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java @@ -32,13 +32,44 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-"; + /** + * The desired number of cells that this widget occupies horizontally in + * {@link com.android.launcher3.CellLayout}. + */ public int spanX; + + /** + * The desired number of cells that this widget occupies vertically in + * {@link com.android.launcher3.CellLayout}. + */ public int spanY; + + /** + * The minimum number of cells that this widget can occupy horizontally in + * {@link com.android.launcher3.CellLayout}. + */ public int minSpanX; + + /** + * The minimum number of cells that this widget can occupy vertically in + * {@link com.android.launcher3.CellLayout}. + */ public int minSpanY; + + /** + * The maximum number of cells that this widget can occupy horizontally in + * {@link com.android.launcher3.CellLayout}. + */ public int maxSpanX; + + /** + * The maximum number of cells that this widget can occupy vertically in + * {@link com.android.launcher3.CellLayout}. + */ public int maxSpanY; + private boolean mIsMinSizeFulfilled; + public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context, AppWidgetProviderInfo info) { final LauncherAppWidgetProviderInfo launcherInfo; @@ -133,8 +164,20 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo this.minSpanY = minSpanY; this.maxSpanX = maxSpanX; this.maxSpanY = maxSpanY; - this.spanX = spanX; - this.spanY = spanY; + this.mIsMinSizeFulfilled = Math.min(spanX, minSpanX) <= idp.numColumns + && Math.min(spanY, minSpanY) <= idp.numRows; + // Ensures the default span X and span Y will not exceed the current grid size. + this.spanX = Math.min(spanX, idp.numColumns); + this.spanY = Math.min(spanY, idp.numRows); + } + + /** + * Returns {@code true} if the widget's minimum size requirement can be fulfilled in the device + * grid setting, {@link InvariantDeviceProfile}, that was passed in + * {@link #initSpans(Context, InvariantDeviceProfile)}. + */ + public boolean isMinSizeFulfilled() { + return mIsMinSizeFulfilled; } private int getSpanX(Rect widgetPadding, int widgetWidth, int cellSpacing, float cellWidth) { diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java index be18e546d2..51c5b12b6e 100644 --- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -254,13 +254,11 @@ public class WidgetsModel { } // Ensure that all widgets we show can be added on a workspace of this size - int minSpanX = Math.min(item.widgetInfo.spanX, item.widgetInfo.minSpanX); - int minSpanY = Math.min(item.widgetInfo.spanY, item.widgetInfo.minSpanY); - if (minSpanX > mIdp.numColumns || minSpanY > mIdp.numRows) { + if (!item.widgetInfo.isMinSizeFulfilled()) { if (DEBUG) { Log.d(TAG, String.format( - "Widget %s : (%d X %d) can't fit on this device", - item.componentName, minSpanX, minSpanY)); + "Widget %s : can't fit on this device with a grid size: %dx%d", + item.componentName, mIdp.numColumns, mIdp.numRows)); } return false; }