Add content description and tooltip to menu item

Bug: 34076597
Test: manual
Change-Id: Ide32463252457721286c929ab2f8f7bae241835d
This commit is contained in:
Vladislav Kaznacheev
2017-01-04 10:15:31 -08:00
parent c9facc0a1f
commit 7039cbc6f3
17 changed files with 229 additions and 30 deletions

View File

@@ -42593,6 +42593,7 @@ package android.view {
method public abstract android.view.ActionProvider getActionProvider();
method public abstract android.view.View getActionView();
method public abstract char getAlphabeticShortcut();
method public default java.lang.CharSequence getContentDescription();
method public abstract int getGroupId();
method public abstract android.graphics.drawable.Drawable getIcon();
method public abstract android.content.Intent getIntent();
@@ -42603,6 +42604,7 @@ package android.view {
method public abstract android.view.SubMenu getSubMenu();
method public abstract java.lang.CharSequence getTitle();
method public abstract java.lang.CharSequence getTitleCondensed();
method public default java.lang.CharSequence getTooltip();
method public abstract boolean hasSubMenu();
method public abstract boolean isActionViewExpanded();
method public abstract boolean isCheckable();
@@ -42615,6 +42617,7 @@ package android.view {
method public abstract android.view.MenuItem setAlphabeticShortcut(char);
method public abstract android.view.MenuItem setCheckable(boolean);
method public abstract android.view.MenuItem setChecked(boolean);
method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
@@ -42628,6 +42631,7 @@ package android.view {
method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
method public abstract android.view.MenuItem setTitle(int);
method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
method public default android.view.MenuItem setTooltip(java.lang.CharSequence);
method public abstract android.view.MenuItem setVisible(boolean);
field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8

View File

@@ -45803,6 +45803,7 @@ package android.view {
method public abstract android.view.ActionProvider getActionProvider();
method public abstract android.view.View getActionView();
method public abstract char getAlphabeticShortcut();
method public default java.lang.CharSequence getContentDescription();
method public abstract int getGroupId();
method public abstract android.graphics.drawable.Drawable getIcon();
method public abstract android.content.Intent getIntent();
@@ -45813,6 +45814,7 @@ package android.view {
method public abstract android.view.SubMenu getSubMenu();
method public abstract java.lang.CharSequence getTitle();
method public abstract java.lang.CharSequence getTitleCondensed();
method public default java.lang.CharSequence getTooltip();
method public abstract boolean hasSubMenu();
method public abstract boolean isActionViewExpanded();
method public abstract boolean isCheckable();
@@ -45825,6 +45827,7 @@ package android.view {
method public abstract android.view.MenuItem setAlphabeticShortcut(char);
method public abstract android.view.MenuItem setCheckable(boolean);
method public abstract android.view.MenuItem setChecked(boolean);
method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
@@ -45838,6 +45841,7 @@ package android.view {
method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
method public abstract android.view.MenuItem setTitle(int);
method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
method public default android.view.MenuItem setTooltip(java.lang.CharSequence);
method public abstract android.view.MenuItem setVisible(boolean);
field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8

View File

@@ -42880,6 +42880,7 @@ package android.view {
method public abstract android.view.ActionProvider getActionProvider();
method public abstract android.view.View getActionView();
method public abstract char getAlphabeticShortcut();
method public default java.lang.CharSequence getContentDescription();
method public abstract int getGroupId();
method public abstract android.graphics.drawable.Drawable getIcon();
method public abstract android.content.Intent getIntent();
@@ -42890,6 +42891,7 @@ package android.view {
method public abstract android.view.SubMenu getSubMenu();
method public abstract java.lang.CharSequence getTitle();
method public abstract java.lang.CharSequence getTitleCondensed();
method public default java.lang.CharSequence getTooltip();
method public abstract boolean hasSubMenu();
method public abstract boolean isActionViewExpanded();
method public abstract boolean isCheckable();
@@ -42902,6 +42904,7 @@ package android.view {
method public abstract android.view.MenuItem setAlphabeticShortcut(char);
method public abstract android.view.MenuItem setCheckable(boolean);
method public abstract android.view.MenuItem setChecked(boolean);
method public default android.view.MenuItem setContentDescription(java.lang.CharSequence);
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
@@ -42915,6 +42918,7 @@ package android.view {
method public abstract android.view.MenuItem setTitle(java.lang.CharSequence);
method public abstract android.view.MenuItem setTitle(int);
method public abstract android.view.MenuItem setTitleCondensed(java.lang.CharSequence);
method public default android.view.MenuItem setTooltip(java.lang.CharSequence);
method public abstract android.view.MenuItem setVisible(boolean);
field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8

View File

@@ -334,6 +334,9 @@ public class MenuInflater {
private ActionProvider itemActionProvider;
private CharSequence itemContentDescription;
private CharSequence itemTooltip;
private static final int defaultGroupId = NO_ID;
private static final int defaultItemId = NO_ID;
private static final int defaultItemCategory = 0;
@@ -424,6 +427,10 @@ public class MenuInflater {
itemActionProvider = null;
}
itemContentDescription =
a.getText(com.android.internal.R.styleable.MenuItem_contentDescription);
itemTooltip = a.getText(com.android.internal.R.styleable.MenuItem_tooltip);
a.recycle();
itemAdded = false;
@@ -486,6 +493,9 @@ public class MenuInflater {
if (itemActionProvider != null) {
item.setActionProvider(itemActionProvider);
}
item.setContentDescription(itemContentDescription);
item.setTooltip(itemTooltip);
}
public MenuItem addItem() {

View File

@@ -599,4 +599,40 @@ public interface MenuItem {
* @return This menu item instance for call chaining
*/
public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
/**
* Change the content description associated with this menu item.
*
* @param contentDescription The new content description.
*/
default MenuItem setContentDescription(CharSequence contentDescription) {
return this;
}
/**
* Retrieve the content description associated with this menu item.
*
* @return The content description.
*/
default CharSequence getContentDescription() {
return null;
}
/**
* Change the tooltip text associated with this menu item.
*
* @param tooltip The new tooltip text.
*/
default MenuItem setTooltip(CharSequence tooltip) {
return this;
}
/**
* Retrieve the tooltip text associated with this menu item.
*
* @return The tooltip text.
*/
default CharSequence getTooltip() {
return null;
}
}

View File

@@ -249,6 +249,19 @@ public final class WindowManagerGlobal {
return views;
}
public View getWindowView(IBinder windowToken) {
synchronized (mLock) {
final int numViews = mViews.size();
for (int i = 0; i < numViews; ++i) {
final View view = mViews.get(i);
if (view.getWindowToken() == windowToken) {
return view;
}
}
}
return null;
}
public View getRootView(String name) {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {

View File

@@ -19,13 +19,17 @@ package com.android.internal.view;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.Slog;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.TextView;
public class TooltipPopup {
private static final String TAG = "TooltipPopup";
private final Context mContext;
private final View mContentView;
@@ -34,6 +38,7 @@ public class TooltipPopup {
private final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
private final Rect mTmpDisplayFrame = new Rect();
private final int[] mTmpAnchorPos = new int[2];
private final int[] mTmpAppPos = new int[2];
public TooltipPopup(Context context) {
mContext = context;
@@ -124,8 +129,21 @@ public class TooltipPopup {
fromTouch ? com.android.internal.R.dimen.tooltip_y_offset_touch
: com.android.internal.R.dimen.tooltip_y_offset_non_touch);
anchorView.getWindowVisibleDisplayFrame(mTmpDisplayFrame);
anchorView.getLocationInWindow(mTmpAnchorPos);
// Find the main app window. The popup window will be positioned relative to it.
final View appView = WindowManagerGlobal.getInstance().getWindowView(
anchorView.getApplicationWindowToken());
if (appView == null) {
Slog.e(TAG, "Cannot find app view");
return;
}
appView.getWindowVisibleDisplayFrame(mTmpDisplayFrame);
appView.getLocationOnScreen(mTmpAppPos);
anchorView.getLocationOnScreen(mTmpAnchorPos);
mTmpAnchorPos[0] -= mTmpAppPos[0];
mTmpAnchorPos[1] -= mTmpAppPos[1];
// mTmpAnchorPos is now relative to the main app window.
outParams.x = mTmpAnchorPos[0] + offsetX - mTmpDisplayFrame.width() / 2;
final int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);

View File

@@ -39,23 +39,26 @@ public class ActionMenuItem implements MenuItem {
private Intent mIntent;
private char mShortcutNumericChar;
private char mShortcutAlphabeticChar;
private Drawable mIconDrawable;
private int mIconResId = NO_ICON;
private Context mContext;
private MenuItem.OnMenuItemClickListener mClickListener;
private CharSequence mContentDescription;
private CharSequence mTooltip;
private static final int NO_ICON = 0;
private int mFlags = ENABLED;
private static final int CHECKABLE = 0x00000001;
private static final int CHECKED = 0x00000002;
private static final int EXCLUSIVE = 0x00000004;
private static final int HIDDEN = 0x00000008;
private static final int ENABLED = 0x00000010;
public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
CharSequence title) {
mContext = context;
@@ -65,7 +68,7 @@ public class ActionMenuItem implements MenuItem {
mOrdering = ordering;
mTitle = title;
}
public char getAlphabeticShortcut() {
return mShortcutAlphabeticChar;
}
@@ -274,4 +277,26 @@ public class ActionMenuItem implements MenuItem {
// No need to save the listener; ActionMenuItem does not support collapsing items.
return this;
}
@Override
public MenuItem setContentDescription(CharSequence contentDescription) {
mContentDescription = contentDescription;
return this;
}
@Override
public CharSequence getContentDescription() {
return mContentDescription;
}
@Override
public MenuItem setTooltip(CharSequence tooltip) {
mTooltip = tooltip;
return this;
}
@Override
public CharSequence getTooltip() {
return mTooltip;
}
}

View File

@@ -119,7 +119,7 @@ public class ActionMenuItemView extends TextView
mItemData = itemData;
setIcon(itemData.getIcon());
setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
setTitle(itemData.getTitleForItemView(this)); // Title is only displayed if there is no icon
setId(itemData.getItemId());
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
@@ -184,8 +184,22 @@ public class ActionMenuItemView extends TextView
setText(visible ? mTitle : null);
// Show the tooltip for items that do not already show text.
setTooltip(visible ? null : mTitle);
final CharSequence contentDescription = mItemData.getContentDescription();
if (TextUtils.isEmpty(contentDescription)) {
// Use the uncondensed title for content description, but only if the title is not
// shown already.
setContentDescription(visible ? null : mItemData.getTitle());
} else {
setContentDescription(contentDescription);
}
final CharSequence tooltip = mItemData.getTooltip();
if (TextUtils.isEmpty(tooltip)) {
// Use the uncondensed title for tooltip, but only if the title is not shown already.
setTooltip(visible ? null : mItemData.getTitle());
} else {
setTooltip(tooltip);
}
}
public void setIcon(Drawable icon) {
@@ -221,7 +235,6 @@ public class ActionMenuItemView extends TextView
public void setTitle(CharSequence title) {
mTitle = title;
setContentDescription(mTitle);
updateTextButtonVisibility();
}

View File

@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.SoundEffectConstants;
@@ -31,7 +32,7 @@ import android.widget.TextView;
import android.text.Layout;
/**
* The item view for each item in the {@link IconMenuView}.
* The item view for each item in the {@link IconMenuView}.
*/
public final class IconMenuItemView extends TextView implements MenuView.ItemView {
@@ -104,13 +105,23 @@ public final class IconMenuItemView extends TextView implements MenuView.ItemVie
setTitle(title);
setIcon(icon);
if (mItemData != null) {
final CharSequence contentDescription = mItemData.getContentDescription();
if (TextUtils.isEmpty(contentDescription)) {
setContentDescription(title);
} else {
setContentDescription(contentDescription);
}
setTooltip(mItemData.getTooltip());
}
}
public void initialize(MenuItemImpl itemData, int menuType) {
mItemData = itemData;
initialize(itemData.getTitleForItemView(this), itemData.getIcon());
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
setEnabled(itemData.isEnabled());
}

View File

@@ -107,13 +107,15 @@ public class ListMenuItemView extends LinearLayout implements MenuView.ItemView
mMenuType = menuType;
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
setTitle(itemData.getTitleForItemView(this));
setCheckable(itemData.isCheckable());
setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
setIcon(itemData.getIcon());
setEnabled(itemData.isEnabled());
setSubMenuArrowVisible(itemData.hasSubMenu());
setContentDescription(itemData.getContentDescription());
setTooltip(itemData.getTooltip());
}
public void setForceShowIcon(boolean forceShow) {

View File

@@ -90,16 +90,19 @@ public final class MenuItemImpl implements MenuItem {
/**
* Current use case is for context menu: Extra information linked to the
* View that added this item to the context menu.
*/
*/
private ContextMenuInfo mMenuInfo;
private CharSequence mContentDescription;
private CharSequence mTooltip;
private static String sLanguage;
private static String sPrependShortcutLabel;
private static String sEnterShortcutLabel;
private static String sDeleteShortcutLabel;
private static String sSpaceShortcutLabel;
/**
* Instantiates this menu item.
*
@@ -670,4 +673,32 @@ public final class MenuItemImpl implements MenuItem {
public boolean isActionViewExpanded() {
return mIsActionViewExpanded;
}
@Override
public MenuItem setContentDescription(CharSequence contentDescription) {
mContentDescription = contentDescription;
mMenu.onItemsChanged(false);
return this;
}
@Override
public CharSequence getContentDescription() {
return mContentDescription;
}
@Override
public MenuItem setTooltip(CharSequence tooltip) {
mTooltip = tooltip;
mMenu.onItemsChanged(false);
return this;
}
@Override
public CharSequence getTooltip() {
return mTooltip;
}
}

View File

@@ -1585,7 +1585,13 @@ public final class FloatingToolbar {
}
if (menuItem != null) {
menuButton.setText(menuItem.getTitle());
menuButton.setContentDescription(menuItem.getTitle());
final CharSequence contentDescription = menuItem.getContentDescription();
if (TextUtils.isEmpty(contentDescription)) {
menuButton.setContentDescription(menuItem.getTitle());
} else {
menuButton.setContentDescription(contentDescription);
}
menuButton.setTooltip(menuItem.getTooltip());
menuButton.setMinimumWidth(minimumWidth);
}
return menuButton;
@@ -1629,19 +1635,31 @@ public final class FloatingToolbar {
* Creates and returns a menu button for the specified menu item.
*/
private static View createMenuItemButton(Context context, MenuItem menuItem) {
final View menuItemButton;
if (isIconOnlyMenuItem(menuItem)) {
View imageMenuItemButton = LayoutInflater.from(context)
menuItemButton = LayoutInflater.from(context)
.inflate(R.layout.floating_popup_menu_image_button, null);
((ImageButton) imageMenuItemButton
((ImageButton) menuItemButton
.findViewById(R.id.floating_toolbar_menu_item_image_button))
.setImageDrawable(menuItem.getIcon());
return imageMenuItemButton;
final CharSequence tooltip = menuItem.getTooltip();
if (TextUtils.isEmpty(tooltip)) {
menuItemButton.setTooltip(menuItem.getTitle());
} else {
menuItemButton.setTooltip(tooltip);
}
} else {
menuItemButton = LayoutInflater.from(context)
.inflate(R.layout.floating_popup_menu_button, null);
((Button) menuItemButton).setText(menuItem.getTitle());
menuItemButton.setTooltip(menuItem.getTooltip());
}
final CharSequence contentDescription = menuItem.getContentDescription();
if (TextUtils.isEmpty(contentDescription)) {
menuItemButton.setContentDescription(menuItem.getTitle());
} else {
menuItemButton.setContentDescription(contentDescription);
}
Button menuItemButton = (Button) LayoutInflater.from(context)
.inflate(R.layout.floating_popup_menu_button, null);
menuItemButton.setText(menuItem.getTitle());
menuItemButton.setContentDescription(menuItem.getTitle());
return menuItemButton;
}

View File

@@ -7009,6 +7009,12 @@
for more info. -->
<attr name="actionProviderClass" format="string" />
<!-- The content description associated with the item. -->
<attr name="contentDescription" format="string" />
<!-- The tooltip text associated with the item. -->
<attr name="tooltip" format="string" />
</declare-styleable>
<!-- Attrbitutes for a ActvityChooserView. -->

View File

@@ -1290,6 +1290,7 @@ please see styles_device_defaults.xml.
<style name="Widget.ActionButton.Overflow">
<item name="src">@drawable/ic_menu_more</item>
<item name="contentDescription">@string/action_menu_overflow_description</item>
<item name="tooltip">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.ActionButton.CloseMode">

View File

@@ -660,6 +660,7 @@ please see styles_device_defaults.xml.
<item name="src">@drawable/ic_menu_moreoverflow_holo_dark</item>
<item name="background">?attr/actionBarItemBackground</item>
<item name="contentDescription">@string/action_menu_overflow_description</item>
<item name="tooltip">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Holo.ActionButton.TextButton" parent="Widget.Holo.ButtonBar.Button" />
@@ -994,6 +995,7 @@ please see styles_device_defaults.xml.
<style name="Widget.Holo.Light.ActionButton.Overflow">
<item name="src">@drawable/ic_menu_moreoverflow_holo_light</item>
<item name="contentDescription">@string/action_menu_overflow_description</item>
<item name="tooltip">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Holo.Light.ActionBar.TabView" parent="Widget.Holo.ActionBar.TabView" />

View File

@@ -944,6 +944,7 @@ please see styles_device_defaults.xml.
<item name="src">@drawable/ic_menu_moreoverflow_material</item>
<item name="background">?attr/actionBarItemBackground</item>
<item name="contentDescription">@string/action_menu_overflow_description</item>
<item name="tooltip">@string/action_menu_overflow_description</item>
<item name="minWidth">@dimen/action_button_min_width_overflow_material</item>
<item name="minHeight">@dimen/action_button_min_height_material</item>
<item name="paddingStart">@dimen/action_bar_overflow_padding_start_material</item>