Bug 1480031 - Truncate floating menu labels if they overflow screen width; r=VladBaicu

There's currently a bug in Android's framework that manifests by placing the
floating menu off-screen if a menu label overflows the menu's width.
https://issuetracker.google.com/issues/137169336
To overcome this we'll manually check and truncate any menu label that could
cause issues based on the floating menu style declared upstream.

Differential Revision: https://phabricator.services.mozilla.com/D37684

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Petru Lingurar 2019-07-12 11:30:48 +00:00
parent dc61c90a77
commit 6177d83601
3 changed files with 70 additions and 2 deletions

View File

@ -150,6 +150,10 @@
<dimen name="menu_item_row_height">64dip</dimen>
<dimen name="menu_item_row_width">240dp</dimen>
<dimen name="menu_popup_width">256dp</dimen>
<!-- https://android.googlesource.com/platform/frameworks/base/+/eb101a7/core/res/res/values/dimens.xml#384 -->
<dimen name="floating_toolbar_horizontal_margin">16dp</dimen>
<dimen name="floating_toolbar_menu_button_side_padding">18dp</dimen>
<dimen name="floating_toolbar_text_size">14sp</dimen>
<dimen name="nav_button_border_width">1dp</dimen>
<dimen name="prompt_service_group_padding_size">32dp</dimen>
<dimen name="prompt_service_icon_size">36dp</dimen>

View File

@ -5,15 +5,22 @@
package org.mozilla.gecko.text;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.TextPaint;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.WindowUtils;
import org.mozilla.geckoview.GeckoViewBridge;
import java.util.List;
@ -43,7 +50,8 @@ public class FloatingActionModeCallback extends ActionMode.Callback2 {
for (int i = 0; i < actions.size(); i++) {
final TextAction action = actions.get(i);
menu.add(Menu.NONE, i, action.getFloatingOrder(), action.getLabel());
final String actionLabel = getOneLinerMenuText(action.getLabel());
menu.add(Menu.NONE, i, action.getFloatingOrder(), actionLabel);
}
return true;
@ -70,4 +78,38 @@ public class FloatingActionModeCallback extends ActionMode.Callback2 {
outRect.set(contentRect);
}
}
// There's currently a bug in Android's framework that manifests by placing the floating menu
// off-screen if a menu label overflows the menu's width.
// https://issuetracker.google.com/issues/137169336
// To overcome this we'll manually check and truncate any menu label that could cause issues.
private static @NonNull String getOneLinerMenuText(@NonNull final String text) {
final int textLength = text.length();
// Avoid heavy unneeded calculations if the text is small
if (textLength < 30) {
return text;
}
// Simulate as best as possible the floating menu button style used in Android framework
// https://android.googlesource.com/platform/frameworks/base/+/eb101a7/core/java/com/android/internal/widget/FloatingToolbar.java
final Context context = GeckoAppShell.getApplicationContext();
final Resources resources = context.getResources();
final TextPaint textPaint = new TextPaint();
textPaint.setTextSize(resources.getDimensionPixelSize(R.dimen.floating_toolbar_text_size));
textPaint.setTypeface(Typeface.create("sans-serif-medium", Typeface.NORMAL));
final int screenWidth = WindowUtils.getScreenWidth(context);
final int menuWidth = screenWidth
- (2 * resources.getDimensionPixelSize(R.dimen.floating_toolbar_horizontal_margin))
- (2 * resources.getDimensionPixelSize(R.dimen.floating_toolbar_menu_button_side_padding));
// If the text cannot fit on one line ellipsize it manually
final int charactersThatFit = textPaint.breakText(text, 0, textLength, true, menuWidth, null);
final boolean shouldEllipsize = textLength > charactersThatFit;
if (shouldEllipsize) {
return text.substring(0, charactersThatFit - 3) + "...";
} else {
return text;
}
}
}

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.util;
import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
@ -52,7 +53,28 @@ public class WindowUtils {
}
return Math.max(tempWidth, tempHeight);
}
}
public static int getScreenWidth(@NonNull final Context context) {
final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (Build.VERSION.SDK_INT >= 17) {
final DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
return realMetrics.widthPixels;
} else {
int tempWidth;
try {
final Method getRawW = Display.class.getMethod("getRawWidth");
tempWidth = (Integer) getRawW.invoke(display);
} catch (Exception e) {
// This is the best we can do.
tempWidth = display.getWidth();
Log.w(LOGTAG, "Couldn't use reflection to get the real display metrics.");
}
return tempWidth;
}
}
}