Bug 785994: Submenu for custom menu. [r=mfinkle]

--HG--
extra : rebase_source : 473a746b802fdc9ff10c4bdc7a95e4a13700f23a
This commit is contained in:
Sriram Ramasubramanian 2012-09-19 10:35:35 -07:00
parent 87922539e0
commit de35e11712
13 changed files with 278 additions and 53 deletions

View File

@ -716,7 +716,11 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void closeOptionsMenu() {
if (!mBrowserToolbar.closeOptionsMenu())
boolean closed = mBrowserToolbar.closeOptionsMenu();
if (closed)
onOptionsMenuClosed(mMenu);
else
super.closeOptionsMenu();
}

View File

@ -304,6 +304,12 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
if (mHasSoftMenuButton) {
mMenuPopup = new MenuPopup(mActivity);
mMenuPopup.setPanelView(panel);
mMenuPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
public void onDismiss() {
mActivity.onOptionsMenuClosed(null);
}
});
}
}
}
@ -696,7 +702,7 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
}
// MenuPopup holds the MenuPanel in Honeycomb/ICS devices with no hardware key
public class MenuPopup extends PopupWindow {
public static class MenuPopup extends PopupWindow {
private RelativeLayout mPanel;
public MenuPopup(Context context) {

View File

@ -142,6 +142,7 @@ abstract public class GeckoApp
public SurfaceView cameraView;
public static GeckoApp mAppContext;
public boolean mDOMFullScreen = false;
protected MenuPresenter mMenuPresenter;
protected MenuPanel mMenuPanel;
protected Menu mMenu;
private static GeckoThread sGeckoThread;
@ -466,10 +467,14 @@ abstract public class GeckoApp
return super.getMenuInflater();
}
public View getMenuPanel() {
public MenuPanel getMenuPanel() {
return mMenuPanel;
}
public MenuPresenter getMenuPresenter() {
return mMenuPresenter;
}
// MenuPanel holds the scrollable Menu
public static class MenuPanel extends LinearLayout {
public MenuPanel(Context context, AttributeSet attrs) {
@ -497,11 +502,41 @@ abstract public class GeckoApp
}
}
// MenuPresenter takes care of proper animation and inflation.
public class MenuPresenter {
GeckoApp mActivity;
public MenuPresenter(GeckoApp activity) {
mActivity = activity;
}
public void show(GeckoMenu menu) {
mActivity.closeOptionsMenu();
MenuPanel panel = mActivity.getMenuPanel();
panel.removeAllViews();
panel.addView(menu);
mActivity.openOptionsMenu();
}
public void hide() {
mActivity.closeOptionsMenu();
}
public void onOptionsMenuClosed() {
MenuPanel panel = mActivity.getMenuPanel();
panel.removeAllViews();
panel.addView((GeckoMenu) mMenu);
}
}
@Override
public View onCreatePanelView(int featureId) {
if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) {
if (mMenuPanel == null) {
mMenuPanel = new MenuPanel(mAppContext, null);
mMenuPresenter = new MenuPresenter(this);
} else {
// Prepare the panel everytime before showing the menu.
onPreparePanel(featureId, mMenuPanel, mMenu);
@ -573,6 +608,12 @@ abstract public class GeckoApp
return super.onOptionsItemSelected(item);
}
}
@Override
public void onOptionsMenuClosed(Menu menu) {
if (Build.VERSION.SDK_INT >= 11)
mMenuPresenter.onOptionsMenuClosed();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

View File

@ -41,7 +41,7 @@ public class GeckoMenu extends ListView
public int getActionItemsCount();
}
private static final int NO_ID = 0;
protected static final int NO_ID = 0;
// List of all menu items.
private List<GeckoMenuItem> mItems;
@ -60,7 +60,6 @@ public class GeckoMenu extends ListView
public GeckoMenu(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
@ -145,22 +144,38 @@ public class GeckoMenu extends ListView
@Override
public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
return null;
MenuItem menuItem = add(groupId, itemId, order, title);
GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
subMenu.setMenuItem(menuItem);
((GeckoMenuItem) menuItem).setSubMenu(subMenu);
return subMenu;
}
@Override
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
return null;
MenuItem menuItem = add(groupId, itemId, order, titleRes);
GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
subMenu.setMenuItem(menuItem);
((GeckoMenuItem) menuItem).setSubMenu(subMenu);
return subMenu;
}
@Override
public SubMenu addSubMenu(CharSequence title) {
return null;
MenuItem menuItem = add(title);
GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
subMenu.setMenuItem(menuItem);
((GeckoMenuItem) menuItem).setSubMenu(subMenu);
return subMenu;
}
@Override
public SubMenu addSubMenu(int titleRes) {
return null;
MenuItem menuItem = add(titleRes);
GeckoSubMenu subMenu = new GeckoSubMenu(mContext, null);
subMenu.setMenuItem(menuItem);
((GeckoMenuItem) menuItem).setSubMenu(subMenu);
return subMenu;
}
@Override
@ -174,8 +189,14 @@ public class GeckoMenu extends ListView
@Override
public MenuItem findItem(int id) {
for (GeckoMenuItem menuItem : mItems) {
if (menuItem.getItemId() == id)
if (menuItem.getItemId() == id) {
return menuItem;
} else if (menuItem.hasSubMenu()) {
SubMenu subMenu = menuItem.getSubMenu();
MenuItem item = subMenu.findItem(id);
if (item != null)
return item;
}
}
return null;
}
@ -298,10 +319,18 @@ public class GeckoMenu extends ListView
@Override
public boolean onMenuItemClick(MenuItem item) {
Activity activity = (Activity) mContext;
boolean result = activity.onOptionsItemSelected(item);
activity.closeOptionsMenu();
return result;
GeckoApp activity = (GeckoApp) mContext;
if (!item.hasSubMenu()) {
boolean result = activity.onOptionsItemSelected(item);
activity.closeOptionsMenu();
return result;
} else {
// Dismiss this menu.
GeckoApp.MenuPresenter presenter = activity.getMenuPresenter();
presenter.show((GeckoSubMenu) item.getSubMenu());
return true;
}
}
public void setActionItemBarPresenter(ActionItemBarPresenter presenter) {

View File

@ -16,17 +16,21 @@ import android.view.InflateException;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import java.io.IOException;
public class GeckoMenuInflater extends MenuInflater {
private static final String LOGTAG = "GeckoMenuInflater";
private static final String TAG_MENU = "menu";
private static final String TAG_ITEM = "item";
private static final int NO_ID = 0;
private Context mContext;
private boolean isSubMenu;
// Private class to hold the parsed menu item.
private class ParsedItem {
public int id;
@ -43,13 +47,13 @@ public class GeckoMenuInflater extends MenuInflater {
public GeckoMenuInflater(Context context) {
super(context);
mContext = context;
isSubMenu = false;
}
public void inflate(int menuRes, Menu menu) {
// This is a very minimal parser for the custom menu.
// This assumes that there is only one menu tag in the resource file.
// This does not support sub-menus.
// This does not check for a well-formed XML.
XmlResourceParser parser = null;
try {
@ -57,6 +61,8 @@ public class GeckoMenuInflater extends MenuInflater {
AttributeSet attrs = Xml.asAttributeSet(parser);
ParsedItem item = null;
SubMenu subMenu = null;
MenuItem menuItem = null;
String tag;
int eventType = parser.getEventType();
@ -70,14 +76,35 @@ public class GeckoMenuInflater extends MenuInflater {
// Parse the menu item.
item = new ParsedItem();
parseItem(item, attrs);
}
} else if (tag.equals(TAG_MENU)) {
if (item != null) {
// Start parsing the sub menu.
isSubMenu = true;
subMenu = menu.addSubMenu(NO_ID, item.id, item.order, item.title);
menuItem = subMenu.getItem();
// Set the menu item in main menu.
setValues(item, menuItem);
}
}
break;
case XmlPullParser.END_TAG:
if (parser.getName().equals(TAG_ITEM)) {
// Add the item.
MenuItem menuItem = menu.add(NO_ID, item.id, item.order, item.title);
setValues(item, menuItem);
if (isSubMenu && subMenu == null) {
isSubMenu = false;
} else {
// Add the item.
if (subMenu == null)
menuItem = menu.add(NO_ID, item.id, item.order, item.title);
else
menuItem = subMenu.add(NO_ID, item.id, item.order, item.title);
setValues(item, menuItem);
}
} else if (tag.equals(TAG_MENU)) {
// End of sub menu.
subMenu = null;
}
break;
}

View File

@ -51,6 +51,7 @@ public class GeckoMenuItem implements MenuItem, View.OnClickListener {
private boolean mEnabled;
private Drawable mIcon;
private int mIconRes;
private GeckoSubMenu mSubMenu;
private MenuItem.OnMenuItemClickListener mMenuItemClickListener;
private OnVisibilityChangedListener mVisibilityChangedListener;
private OnShowAsActionChangedListener mShowAsActionChangedListener;
@ -141,7 +142,7 @@ public class GeckoMenuItem implements MenuItem, View.OnClickListener {
@Override
public SubMenu getSubMenu() {
return null;
return mSubMenu;
}
@Override
@ -156,7 +157,7 @@ public class GeckoMenuItem implements MenuItem, View.OnClickListener {
@Override
public boolean hasSubMenu() {
return false;
return (mSubMenu != null);
}
@Override
@ -308,6 +309,11 @@ public class GeckoMenuItem implements MenuItem, View.OnClickListener {
return this;
}
public MenuItem setSubMenu(GeckoSubMenu subMenu) {
mSubMenu = subMenu;
return this;
}
@Override
public MenuItem setTitle(CharSequence title) {
mTitle = title;

View File

@ -0,0 +1,85 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import java.util.ArrayList;
import java.util.List;
public class GeckoSubMenu extends GeckoMenu
implements SubMenu {
private static final String LOGTAG = "GeckoSubMenu";
private Context mContext;
// MenuItem associated with this submenu.
private MenuItem mMenuItem;
public GeckoSubMenu(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
@Override
public void clearHeader() {
}
public SubMenu setMenuItem(MenuItem item) {
mMenuItem = item;
return this;
}
@Override
public MenuItem getItem() {
return mMenuItem;
}
@Override
public SubMenu setHeaderIcon(Drawable icon) {
return this;
}
@Override
public SubMenu setHeaderIcon(int iconRes) {
return this;
}
@Override
public SubMenu setHeaderTitle(CharSequence title) {
return this;
}
@Override
public SubMenu setHeaderTitle(int titleRes) {
return this;
}
@Override
public SubMenu setHeaderView(View view) {
return this;
}
@Override
public SubMenu setIcon(Drawable icon) {
return this;
}
@Override
public SubMenu setIcon(int iconRes) {
return this;
}
}

View File

@ -81,6 +81,7 @@ FENNEC_JAVA_FILES = \
GeckoMenuInflater.java \
GeckoMenuItem.java \
GeckoMessageReceiver.java \
GeckoSubMenu.java \
GeckoPreferences.java \
GeckoProfile.java \
GeckoThread.java \

View File

@ -124,6 +124,7 @@ size. -->
<!ENTITY save_as_pdf "Save as PDF">
<!ENTITY find_in_page "Find in Page">
<!ENTITY desktop_mode "Request Desktop Site">
<!ENTITY tools "Tools">
<!-- Localization note (find_text, find_prev, find_next, find_close) : These strings are used
as alternate text for accessibility. They are not visible in the UI. -->

View File

@ -28,10 +28,6 @@
gecko:icon="@drawable/ic_menu_reading_list_add"
gecko:title="@string/reading_list" />
<item gecko:id="@+id/save_as_pdf"
gecko:icon="@drawable/ic_menu_save_as_pdf"
gecko:title="@string/save_as_pdf" />
<item gecko:id="@+id/find_in_page"
gecko:icon="@drawable/ic_menu_find_in_page"
gecko:title="@string/find_in_page" />
@ -41,14 +37,26 @@
gecko:title="@string/desktop_mode"
gecko:checkable="true" />
<item gecko:id="@+id/addons"
gecko:title="@string/addons"/>
<item gecko:title="@string/tools">
<item gecko:id="@+id/downloads"
gecko:title="@string/downloads"/>
<menu>
<item gecko:id="@+id/apps"
gecko:title="@string/apps"/>
<item gecko:id="@+id/save_as_pdf"
gecko:icon="@drawable/ic_menu_save_as_pdf"
gecko:title="@string/save_as_pdf" />
<item gecko:id="@+id/addons"
gecko:title="@string/addons"/>
<item gecko:id="@+id/downloads"
gecko:title="@string/downloads"/>
<item gecko:id="@+id/apps"
gecko:title="@string/apps"/>
</menu>
</item>
<item gecko:id="@+id/char_encoding"
gecko:visible="false"

View File

@ -29,10 +29,6 @@
gecko:icon="@drawable/ic_menu_reading_list_add"
gecko:title="@string/reading_list" />
<item gecko:id="@+id/save_as_pdf"
gecko:icon="@drawable/ic_menu_save_as_pdf"
gecko:title="@string/save_as_pdf" />
<item gecko:id="@+id/find_in_page"
gecko:icon="@drawable/ic_menu_find_in_page"
gecko:title="@string/find_in_page" />
@ -42,14 +38,26 @@
gecko:title="@string/desktop_mode"
gecko:checkable="true" />
<item gecko:id="@+id/addons"
gecko:title="@string/addons"/>
<item gecko:title="@string/tools">
<item gecko:id="@+id/downloads"
gecko:title="@string/downloads"/>
<menu>
<item gecko:id="@+id/apps"
gecko:title="@string/apps"/>
<item gecko:id="@+id/save_as_pdf"
gecko:icon="@drawable/ic_menu_save_as_pdf"
gecko:title="@string/save_as_pdf" />
<item gecko:id="@+id/addons"
gecko:title="@string/addons"/>
<item gecko:id="@+id/downloads"
gecko:title="@string/downloads"/>
<item gecko:id="@+id/apps"
gecko:title="@string/apps"/>
</menu>
</item>
<item gecko:id="@+id/char_encoding"
gecko:visible="false"

View File

@ -29,10 +29,6 @@
gecko:icon="@drawable/ic_menu_reading_list_add"
gecko:title="@string/reading_list" />
<item gecko:id="@+id/save_as_pdf"
gecko:icon="@drawable/ic_menu_save_as_pdf"
gecko:title="@string/save_as_pdf" />
<item gecko:id="@+id/find_in_page"
gecko:icon="@drawable/ic_menu_find_in_page"
gecko:title="@string/find_in_page" />
@ -42,14 +38,26 @@
gecko:title="@string/desktop_mode"
gecko:checkable="true" />
<item gecko:id="@+id/addons"
gecko:title="@string/addons"/>
<item gecko:title="@string/tools">
<item gecko:id="@+id/downloads"
gecko:title="@string/downloads"/>
<menu>
<item gecko:id="@+id/apps"
gecko:title="@string/apps"/>
<item gecko:id="@+id/save_as_pdf"
gecko:icon="@drawable/ic_menu_save_as_pdf"
gecko:title="@string/save_as_pdf" />
<item gecko:id="@+id/addons"
gecko:title="@string/addons"/>
<item gecko:id="@+id/downloads"
gecko:title="@string/downloads"/>
<item gecko:id="@+id/apps"
gecko:title="@string/apps"/>
</menu>
</item>
<item gecko:id="@+id/char_encoding"
gecko:visible="false"

View File

@ -60,6 +60,7 @@
<string name="save_as_pdf">&save_as_pdf;</string>
<string name="find_in_page">&find_in_page;</string>
<string name="desktop_mode">&desktop_mode;</string>
<string name="tools">&tools;</string>
<string name="find_text">&find_text;</string>
<string name="find_prev">&find_prev;</string>