Use full screen width for drop target buttons to support higher screen densities from truncating text.
Scale oversized text down if after all computations it will still be truncated at higher densities.
Fix: 239401464
Test: manual. To follow up with screenshot test: b/241386128
Change-Id: Ie088d0631b0d13beb2d9f9d5396a56f7b971dee1
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a9d1127..2e886db 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -226,6 +226,7 @@
<dimen name="drop_target_text_size">16sp</dimen>
<dimen name="drop_target_shadow_elevation">2dp</dimen>
<dimen name="drop_target_bar_margin_horizontal">4dp</dimen>
+ <dimen name="drop_target_button_drawable_size">20dp</dimen>
<dimen name="drop_target_button_drawable_padding">8dp</dimen>
<dimen name="drop_target_button_drawable_horizontal_padding">16dp</dimen>
<dimen name="drop_target_button_drawable_vertical_padding">8dp</dimen>
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 3b24df2..5abe3d3 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -91,7 +91,7 @@
Resources resources = getResources();
mDragDistanceThreshold = resources.getDimensionPixelSize(R.dimen.drag_distanceThreshold);
- mDrawableSize = resources.getDimensionPixelSize(R.dimen.drop_target_text_size);
+ mDrawableSize = resources.getDimensionPixelSize(R.dimen.drop_target_button_drawable_size);
mDrawablePadding = resources.getDimensionPixelSize(
R.dimen.drop_target_button_drawable_padding);
}
@@ -374,11 +374,63 @@
hideTooltip();
}
+ /**
+ * Returns if the text will be truncated within the provided availableWidth.
+ */
public boolean isTextTruncated(int availableWidth) {
- availableWidth -= (getPaddingLeft() + getPaddingRight() + mDrawable.getIntrinsicWidth()
- + getCompoundDrawablePadding());
- CharSequence displayedText = TextUtils.ellipsize(mText, getPaint(), availableWidth,
+ availableWidth -= getPaddingLeft() + getPaddingRight();
+ if (mIconVisible) {
+ availableWidth -= mDrawable.getIntrinsicWidth() + getCompoundDrawablePadding();
+ }
+ if (availableWidth <= 0) {
+ return true;
+ }
+ CharSequence firstLine = TextUtils.ellipsize(mText, getPaint(), availableWidth,
TextUtils.TruncateAt.END);
- return !mText.equals(displayedText);
+ if (!mTextMultiLine) {
+ return !TextUtils.equals(mText, firstLine);
+ }
+ if (TextUtils.equals(mText, firstLine)) {
+ // When multi-line is active, if it can display as one line, then text is not truncated.
+ return false;
+ }
+ CharSequence secondLine =
+ TextUtils.ellipsize(mText.subSequence(firstLine.length(), mText.length()),
+ getPaint(), availableWidth, TextUtils.TruncateAt.END);
+ return !(TextUtils.equals(mText.subSequence(0, firstLine.length()), firstLine)
+ && TextUtils.equals(mText.subSequence(firstLine.length(), secondLine.length()),
+ secondLine));
+ }
+
+ /**
+ * Reduce the size of the text until it fits the measured width or reaches a minimum.
+ *
+ * The minimum size is defined by {@code R.dimen.button_drop_target_min_text_size} and
+ * it diminishes by intervals defined by
+ * {@code R.dimen.button_drop_target_resize_text_increment}
+ * This functionality is very similar to the option
+ * {@link TextView#setAutoSizeTextTypeWithDefaults(int)} but can't be used in this view because
+ * the layout width is {@code WRAP_CONTENT}.
+ *
+ * @return The biggest text size in SP that makes the text fit or if the text can't fit returns
+ * the min available value
+ */
+ public float resizeTextToFit() {
+ float minSize = Utilities.pxToSp(getResources()
+ .getDimensionPixelSize(R.dimen.button_drop_target_min_text_size));
+ float step = Utilities.pxToSp(getResources()
+ .getDimensionPixelSize(R.dimen.button_drop_target_resize_text_increment));
+ float textSize = Utilities.pxToSp(getTextSize());
+
+ int availableWidth = getMeasuredWidth();
+ while (textSize > minSize) {
+ if (isTextTruncated(availableWidth)) {
+ textSize -= step;
+ setTextSize(textSize);
+ } else {
+ return textSize;
+ }
+ }
+ return minSize;
}
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 14a467a..55a8d37 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1030,7 +1030,7 @@
/ getCellLayoutHeight();
scale = Math.min(scale, 1f);
- // Reduce scale if next pages would not be visible after scaling the workspace
+ // Reduce scale if next pages would not be visible after scaling the workspace.
int workspaceWidth = availableWidthPx;
float scaledWorkspaceWidth = workspaceWidth * scale;
float maxAvailableWidth = workspaceWidth - (2 * workspaceSpringLoadedMinNextPageVisiblePx);
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index d64cb26..98ecf3a 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -151,6 +151,8 @@
int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST);
ButtonDropTarget firstButton = mTempTargets[0];
+ firstButton.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ mLauncher.getDeviceProfile().dropTargetTextSizePx);
firstButton.setTextVisible(true);
firstButton.setIconVisible(true);
firstButton.measure(widthSpec, heightSpec);
@@ -160,14 +162,16 @@
int horizontalPadding = dp.dropTargetHorizontalPaddingPx;
ButtonDropTarget firstButton = mTempTargets[0];
+ firstButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp.dropTargetTextSizePx);
firstButton.setTextVisible(true);
firstButton.setIconVisible(true);
firstButton.setTextMultiLine(false);
- // Reset second button padding in case it was previously changed to multi-line text.
+ // Reset first button padding in case it was previously changed to multi-line text.
firstButton.setPadding(horizontalPadding, verticalPadding, horizontalPadding,
verticalPadding);
ButtonDropTarget secondButton = mTempTargets[1];
+ secondButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, dp.dropTargetTextSizePx);
secondButton.setTextVisible(true);
secondButton.setIconVisible(true);
secondButton.setTextMultiLine(false);
@@ -175,20 +179,14 @@
secondButton.setPadding(horizontalPadding, verticalPadding, horizontalPadding,
verticalPadding);
- float scale = dp.getWorkspaceSpringLoadScale(mLauncher);
- int scaledPanelWidth = (int) (dp.getCellLayoutWidth() * scale);
-
int availableWidth;
if (dp.isTwoPanels) {
- // Both buttons for two panel fit to the width of one Cell Layout (less
- // half of the center gap between the buttons).
- int halfButtonGap = dp.dropTargetGapPx / 2;
- availableWidth = scaledPanelWidth - halfButtonGap / 2;
+ // Each button for two panel fits to half the width of the screen excluding the
+ // center gap between the buttons.
+ availableWidth = (dp.availableWidthPx - dp.dropTargetGapPx) / 2;
} else {
- // Both buttons plus the button gap do not display past the edge of the scaled
- // workspace, less a pre-defined gap from the edge of the workspace.
- availableWidth = scaledPanelWidth - dp.dropTargetGapPx
- - 2 * dp.dropTargetButtonWorkspaceEdgeGapPx;
+ // Both buttons plus the button gap do not display past the edge of the screen.
+ availableWidth = dp.availableWidthPx - dp.dropTargetGapPx;
}
int widthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
@@ -219,6 +217,15 @@
horizontalPadding, verticalPadding / 2);
}
}
+
+ // If text is still truncated, shrink to fit in measured width and resize both targets.
+ float minTextSize =
+ Math.min(firstButton.resizeTextToFit(), secondButton.resizeTextToFit());
+ if (firstButton.getTextSize() != minTextSize
+ || secondButton.getTextSize() != minTextSize) {
+ firstButton.setTextSize(minTextSize);
+ secondButton.setTextSize(minTextSize);
+ }
}
setMeasuredDimension(width, height);
}