diff --git a/res/drawable/drop_target_frame.xml b/res/drawable/drop_target_frame.xml index 666a96e940..9f04103510 100644 --- a/res/drawable/drop_target_frame.xml +++ b/res/drawable/drop_target_frame.xml @@ -17,6 +17,6 @@ - + \ No newline at end of file diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml index 662b86ebbe..58aeda4c0d 100644 --- a/res/values-land/dimens.xml +++ b/res/values-land/dimens.xml @@ -23,7 +23,16 @@ 4dp + 36dp 16dp + 45dp + + + 28dp + 16dp + 2dp + 6dp + 6dp diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml new file mode 100644 index 0000000000..e052d614d1 --- /dev/null +++ b/res/values-sw600dp-land/dimens.xml @@ -0,0 +1,25 @@ + + + + + + 44dp + + + 0dp + 16dp + diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml index 4a10e5689a..823fc62372 100644 --- a/res/values-sw600dp/dimens.xml +++ b/res/values-sw600dp/dimens.xml @@ -36,4 +36,12 @@ 0dp + 97dp + + + 34dp + 16dp + 16dp + 16dp + 56dp diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml index 9821526d4d..77d15c708b 100644 --- a/res/values-sw720dp-land/dimens.xml +++ b/res/values-sw720dp-land/dimens.xml @@ -15,9 +15,16 @@ --> - + + 0dp + 32dp + + + 64dp + + 49dp - + 0dp diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml index 7ebc3f886b..e273b09940 100644 --- a/res/values-sw720dp/dimens.xml +++ b/res/values-sw720dp/dimens.xml @@ -18,6 +18,18 @@ 65dp + + 20sp + 72dp + 24dp + 20dp + 32dp + 32dp + 32dp + + + 164dp + 30dp diff --git a/res/values/config.xml b/res/values/config.xml index 76d11617b7..0ed2d858df 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -22,9 +22,6 @@ - - 85 - 50 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index ce5456515b..83d40d59f7 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -34,6 +34,7 @@ 2dp 0dp 0dp + 76dp - 52dp + 56dp 20dp + 36dp + 16dp 13dp @@ -207,6 +210,9 @@ 2dp 4dp 8dp + 16dp + 8dp + 22dp 30dp diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 3489c31306..67d6f4090d 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -108,7 +108,8 @@ public class DeviceProfile { public final int cellLayoutPaddingLeftRightPx; public final int cellLayoutBottomPaddingPx; public final int edgeMarginPx; - public float workspaceSpringLoadShrinkFactor; + public float workspaceSpringLoadShrunkTop; + public float workspaceSpringLoadShrunkBottom; public final int workspaceSpringLoadedBottomSpace; private final int extraSpace; @@ -164,6 +165,7 @@ public class DeviceProfile { public int hotseatBarSizePx; public int hotseatBarTopPaddingPx; public final int hotseatBarBottomPaddingPx; + public int springLoadedHotseatBarTopMarginPx; // Start is the side next to the nav bar, end is the side next to the workspace public final int hotseatBarSidePaddingStartPx; public final int hotseatBarSidePaddingEndPx; @@ -209,8 +211,13 @@ public class DeviceProfile { // Drop Target public int dropTargetBarSizePx; + public int dropTargetBarTopMarginPx; + public int dropTargetBarBottomMarginPx; public int dropTargetDragPaddingPx; public int dropTargetTextSizePx; + public int dropTargetHorizontalPaddingPx; + public int dropTargetVerticalPaddingPx; + public int dropTargetGapPx; // Insets private final Rect mInsets = new Rect(); @@ -347,8 +354,15 @@ public class DeviceProfile { res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding); dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size); + dropTargetBarTopMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_top_margin); + dropTargetBarBottomMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_bottom_margin); dropTargetDragPaddingPx = res.getDimensionPixelSize(R.dimen.drop_target_drag_padding); dropTargetTextSizePx = res.getDimensionPixelSize(R.dimen.drop_target_text_size); + dropTargetHorizontalPaddingPx = res.getDimensionPixelSize( + R.dimen.drop_target_button_drawable_horizontal_padding); + dropTargetVerticalPaddingPx = res.getDimensionPixelSize( + R.dimen.drop_target_button_drawable_vertical_padding); + dropTargetGapPx = res.getDimensionPixelSize(R.dimen.drop_target_button_gap); workspaceSpringLoadedBottomSpace = res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space); @@ -389,6 +403,8 @@ public class DeviceProfile { + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding); qsbWidth = 0; } + springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize( + R.dimen.spring_loaded_hotseat_top_margin); hotseatBarSidePaddingEndPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding); // Add a bit of space between nav bar and hotseat in vertical bar layout. @@ -744,18 +760,6 @@ public class DeviceProfile { } updateHotseatIconSize(iconSizePx); - if (!isVerticalLayout) { - int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx - - workspacePageIndicatorHeight - edgeMarginPx; - float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace; - workspaceSpringLoadShrinkFactor = Math.min( - res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f, - 1 - (minRequiredHeight / expectedWorkspaceHeight)); - } else { - workspaceSpringLoadShrinkFactor = - res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; - } - // Folder icon folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx); folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2; @@ -897,6 +901,41 @@ public class DeviceProfile { return result; } + /** + * Gets the space in px from the bottom of last item in the vertical-bar hotseat to the + * bottom of the screen. + */ + public int getVerticalHotseatLastItemBottomOffset() { + int cellHeight = calculateCellHeight( + heightPx - mHotseatPadding.top - mHotseatPadding.bottom, hotseatBorderSpace, + numShownHotseatIcons); + int hotseatSize = (cellHeight * numShownHotseatIcons) + + (hotseatBorderSpace * (numShownHotseatIcons - 1)); + int extraHotseatEndSpacing = (heightPx - hotseatSize) / 2; + int extraIconEndSpacing = (cellHeight - iconSizePx) / 2; + return extraHotseatEndSpacing + extraIconEndSpacing + mHotseatPadding.bottom; + } + + /** + * Gets the scaled top of the workspace in px for the spring-loaded edit state. + */ + public float getWorkspaceSpringLoadShrunkTop() { + workspaceSpringLoadShrunkTop = mInsets.top + dropTargetBarTopMarginPx + dropTargetBarSizePx + + dropTargetBarBottomMarginPx; + return workspaceSpringLoadShrunkTop; + } + + /** + * Gets the scaled bottom of the workspace in px for the spring-loaded edit state. + */ + public float getWorkspaceSpringLoadShrunkBottom() { + int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx; + workspaceSpringLoadShrunkBottom = + heightPx - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset() + : topOfHotseat); + return workspaceSpringLoadShrunkBottom; + } + public int getWorkspaceWidth() { return getWorkspaceWidth(getTotalWorkspacePadding()); } @@ -1206,6 +1245,12 @@ public class DeviceProfile { hotseatBarSidePaddingStartPx)); writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx", hotseatBarSidePaddingEndPx)); + writer.println(prefix + pxToDpStr("springLoadedHotseatBarTopMarginPx", + springLoadedHotseatBarTopMarginPx)); + writer.println(prefix + pxToDpStr("mHotseatPadding.top", mHotseatPadding.top)); + writer.println(prefix + pxToDpStr("mHotseatPadding.bottom", mHotseatPadding.bottom)); + writer.println(prefix + pxToDpStr("mHotseatPadding.left", mHotseatPadding.left)); + writer.println(prefix + pxToDpStr("mHotseatPadding.right", mHotseatPadding.right)); writer.println(prefix + "\tnumShownHotseatIcons: " + numShownHotseatIcons); writer.println(prefix + pxToDpStr("hotseatBorderSpace", hotseatBorderSpace)); writer.println(prefix + "\tisQsbInline: " + isQsbInline); @@ -1256,6 +1301,16 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("overviewPageSpacing", overviewPageSpacing)); writer.println(prefix + pxToDpStr("overviewRowSpacing", overviewRowSpacing)); writer.println(prefix + pxToDpStr("overviewGridSideMargin", overviewGridSideMargin)); + + writer.println(prefix + pxToDpStr("dropTargetBarTopMarginPx", dropTargetBarTopMarginPx)); + writer.println(prefix + pxToDpStr("dropTargetBarSizePx", dropTargetBarSizePx)); + writer.println( + prefix + pxToDpStr("dropTargetBarBottomMarginPx", dropTargetBarBottomMarginPx)); + + writer.println( + prefix + pxToDpStr("workspaceSpringLoadShrunkTop", workspaceSpringLoadShrunkTop)); + writer.println(prefix + pxToDpStr("workspaceSpringLoadShrunkBottom", + workspaceSpringLoadShrunkBottom)); } private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) { diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java index 9fb14f68cb..73289fb878 100644 --- a/src/com/android/launcher3/DropTargetBar.java +++ b/src/com/android/launcher3/DropTargetBar.java @@ -17,8 +17,6 @@ package com.android.launcher3; import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT; -import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT; -import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT; import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility; import android.animation.TimeInterpolator; @@ -41,6 +39,8 @@ import com.android.launcher3.dragndrop.DragController.DragListener; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.testing.TestProtocol; +import java.util.Arrays; + /* * The top bar containing various drop targets: Delete/App Info/Uninstall. */ @@ -94,30 +94,28 @@ public class DropTargetBar extends FrameLayout lp.rightMargin = insets.right; int tooltipLocation = TOOLTIP_DEFAULT; - if (grid.isVerticalBarLayout()) { - lp.width = grid.dropTargetBarSizePx; - lp.height = grid.availableHeightPx - 2 * grid.edgeMarginPx; - lp.gravity = grid.isSeascape() ? Gravity.RIGHT : Gravity.LEFT; - tooltipLocation = grid.isSeascape() ? TOOLTIP_LEFT : TOOLTIP_RIGHT; + int horizontalMargin; + if (grid.isTablet) { + // XXX: If the icon size changes across orientations, we will have to take + // that into account here too. + horizontalMargin = ((grid.widthPx - 2 * grid.edgeMarginPx + - (grid.inv.numColumns * grid.cellWidthPx)) + / (2 * (grid.inv.numColumns + 1))) + + grid.edgeMarginPx; } else { - int gap; - if (grid.isTablet) { - // XXX: If the icon size changes across orientations, we will have to take - // that into account here too. - gap = ((grid.widthPx - 2 * grid.edgeMarginPx - - (grid.inv.numColumns * grid.cellWidthPx)) - / (2 * (grid.inv.numColumns + 1))) - + grid.edgeMarginPx; - } else { - gap = getContext().getResources() - .getDimensionPixelSize(R.dimen.drop_target_bar_margin_horizontal); - } - lp.width = grid.availableWidthPx - 2 * gap; - - lp.topMargin += grid.edgeMarginPx; - lp.height = grid.dropTargetBarSizePx; - lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; + horizontalMargin = getContext().getResources() + .getDimensionPixelSize(R.dimen.drop_target_bar_margin_horizontal); } + lp.topMargin += grid.dropTargetBarTopMarginPx; + lp.bottomMargin += grid.dropTargetBarBottomMarginPx; + lp.width = grid.availableWidthPx - 2 * horizontalMargin; + if (mIsVertical) { + lp.leftMargin = (grid.widthPx - lp.width) / 2; + lp.rightMargin = (grid.widthPx - lp.width) / 2; + } + lp.height = grid.dropTargetBarSizePx; + lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; + setLayoutParams(lp); for (ButtonDropTarget button : mDropTargets) { button.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.dropTargetTextSizePx); @@ -139,19 +137,7 @@ public class DropTargetBar extends FrameLayout int height = MeasureSpec.getSize(heightMeasureSpec); int visibleCount = getVisibleButtonsCount(); - if (visibleCount == 0) { - // do nothing - } else if (mIsVertical) { - int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); - int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); - - for (ButtonDropTarget button : mDropTargets) { - if (button.getVisibility() != GONE) { - button.setTextVisible(false); - button.measure(widthSpec, heightSpec); - } - } - } else { + if (visibleCount > 0) { int availableWidth = width / visibleCount; boolean textVisible = true; for (ButtonDropTarget buttons : mDropTargets) { @@ -176,31 +162,91 @@ public class DropTargetBar extends FrameLayout protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int visibleCount = getVisibleButtonsCount(); if (visibleCount == 0) { - // do nothing - } else if (mIsVertical) { - int gap = getResources().getDimensionPixelSize(R.dimen.drop_target_vertical_gap); - int start = gap; - int end; + return; + } - for (ButtonDropTarget button : mDropTargets) { - if (button.getVisibility() != GONE) { - end = start + button.getMeasuredHeight(); - button.layout(0, start, button.getMeasuredWidth(), end); - start = end + gap; - } - } - } else { - int frameSize = (right - left) / visibleCount; + Launcher launcher = Launcher.getLauncher(getContext()); + Workspace workspace = launcher.getWorkspace(); + DeviceProfile dp = launcher.getDeviceProfile(); + int buttonHorizontalPadding = dp.dropTargetHorizontalPaddingPx; + int buttonVerticalPadding = dp.dropTargetVerticalPaddingPx; + int barCenter = (right - left) / 2; - int start = frameSize / 2; - int halfWidth; - for (ButtonDropTarget button : mDropTargets) { - if (button.getVisibility() != GONE) { - halfWidth = button.getMeasuredWidth() / 2; - button.layout(start - halfWidth, 0, - start + halfWidth, button.getMeasuredHeight()); - start = start + frameSize; + ButtonDropTarget[] visibleButtons = Arrays.stream(mDropTargets) + .filter(b -> b.getVisibility() != GONE) + .toArray(ButtonDropTarget[]::new); + Arrays.stream(visibleButtons).forEach( + b -> b.setPadding(buttonHorizontalPadding, buttonVerticalPadding, + buttonHorizontalPadding, buttonVerticalPadding)); + + if (visibleCount == 1) { + ButtonDropTarget button = visibleButtons[0]; + button.layout(barCenter - (button.getMeasuredWidth() / 2), 0, + barCenter + (button.getMeasuredWidth() / 2), button.getMeasuredHeight()); + } else if (visibleCount == 2) { + int buttonGap = dp.dropTargetGapPx; + + if (dp.isTwoPanels) { + ButtonDropTarget leftButton = visibleButtons[0]; + leftButton.layout(barCenter - leftButton.getMeasuredWidth() - (buttonGap / 2), 0, + barCenter - (buttonGap / 2), leftButton.getMeasuredHeight()); + + ButtonDropTarget rightButton = visibleButtons[1]; + rightButton.layout(barCenter + (buttonGap / 2), 0, + barCenter + rightButton.getMeasuredWidth() + (buttonGap / 2), + rightButton.getMeasuredHeight()); + } else if (dp.isTablet) { + int numberOfMargins = visibleCount - 1; + int buttonWidths = Arrays.stream(mDropTargets) + .filter(b -> b.getVisibility() != GONE) + .mapToInt(ButtonDropTarget::getMeasuredWidth) + .sum(); + int totalWidth = buttonWidths + (numberOfMargins * buttonGap); + int buttonsStartMargin = barCenter - (totalWidth / 2); + + int start = buttonsStartMargin; + for (ButtonDropTarget button : visibleButtons) { + int margin = (start != buttonsStartMargin) ? buttonGap : 0; + button.layout(start + margin, 0, start + margin + button.getMeasuredWidth(), + button.getMeasuredHeight()); + start += button.getMeasuredWidth() + margin; } + } else if (mIsVertical) { + // Center buttons over workspace, not screen. + int verticalCenter = (workspace.getRight() - workspace.getLeft()) / 2; + ButtonDropTarget leftButton = visibleButtons[0]; + leftButton.layout(verticalCenter - leftButton.getMeasuredWidth() - (buttonGap / 2), + 0, verticalCenter - (buttonGap / 2), leftButton.getMeasuredHeight()); + + ButtonDropTarget rightButton = visibleButtons[1]; + rightButton.layout(verticalCenter + (buttonGap / 2), 0, + verticalCenter + rightButton.getMeasuredWidth() + (buttonGap / 2), + rightButton.getMeasuredHeight()); + } else if (dp.isPhone) { + // Buttons aligned to outer edges of scaled workspace. + float shrunkTop = dp.getWorkspaceSpringLoadShrunkTop(); + float shrunkBottom = dp.getWorkspaceSpringLoadShrunkBottom(); + float scale = + (shrunkBottom - shrunkTop) / launcher.getWorkspace().getNormalChildHeight(); + int workspaceWidth = (int) (launcher.getWorkspace().getNormalChildWidth() * scale); + int start = barCenter - (workspaceWidth / 2); + int end = barCenter + (workspaceWidth / 2); + + ButtonDropTarget leftButton = visibleButtons[0]; + ButtonDropTarget rightButton = visibleButtons[1]; + + // If the text within the buttons is too long, the buttons can overlap + int overlap = start + leftButton.getMeasuredWidth() + rightButton.getMeasuredWidth() + - end; + if (overlap > 0) { + start -= overlap / 2; + end += overlap / 2; + } + + leftButton.layout(start, 0, start + leftButton.getMeasuredWidth(), + leftButton.getMeasuredHeight()); + rightButton.layout(end - rightButton.getMeasuredWidth(), 0, end, + rightButton.getMeasuredHeight()); } } } diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index d52594e409..9be3cc5539 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -18,7 +18,6 @@ package com.android.launcher3.states; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; import android.content.Context; -import android.graphics.Rect; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; @@ -52,28 +51,15 @@ public class SpringLoadedState extends LauncherState { return super.getWorkspaceScaleAndTranslation(launcher); } - if (grid.isVerticalBarLayout()) { - float scale = grid.workspaceSpringLoadShrinkFactor; - return new ScaleAndTranslation(scale, 0, 0); - } - - float scale = grid.workspaceSpringLoadShrinkFactor; - Rect insets = launcher.getDragLayer().getInsets(); - - float scaledHeight = scale * ws.getNormalChildHeight(); - float shrunkTop = insets.top + grid.dropTargetBarSizePx; - float shrunkBottom = ws.getMeasuredHeight() - insets.bottom - - grid.workspacePadding.bottom - - grid.workspaceSpringLoadedBottomSpace; - float totalShrunkSpace = shrunkBottom - shrunkTop; - - float desiredCellTop = shrunkTop + (totalShrunkSpace - scaledHeight) / 2; + float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop(); + float shrunkBottom = grid.getWorkspaceSpringLoadShrunkBottom(); + float scale = (shrunkBottom - shrunkTop) / ws.getNormalChildHeight(); float halfHeight = ws.getHeight() / 2; float myCenter = ws.getTop() + halfHeight; float cellTopFromCenter = halfHeight - ws.getChildAt(0).getTop(); float actualCellTop = myCenter - cellTopFromCenter * scale; - return new ScaleAndTranslation(scale, 0, (desiredCellTop - actualCellTop) / scale); + return new ScaleAndTranslation(scale, 0, (shrunkTop - actualCellTop) / scale); } @Override