diff options
10 files changed, 300 insertions, 29 deletions
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java index b86eb132163b..9c06d693c15c 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java @@ -20,7 +20,8 @@ import com.android.internal.view.menu.ActionMenuView.ActionMenuChildView; import android.content.Context; import android.content.res.Resources; -import android.util.Log; +import android.os.Parcel; +import android.os.Parcelable; import android.util.SparseBooleanArray; import android.view.MenuItem; import android.view.SoundEffectConstants; @@ -60,6 +61,9 @@ public class ActionMenuPresenter extends BaseMenuPresenter { private OpenOverflowRunnable mPostedOpenRunnable; + final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback(); + int mOpenSubMenuId; + public ActionMenuPresenter() { super(com.android.internal.R.layout.action_menu_layout, com.android.internal.R.layout.action_menu_item_layout); @@ -196,8 +200,12 @@ public class ActionMenuPresenter extends BaseMenuPresenter { topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu(); } View anchor = findViewForItem(topSubMenu.getItem()); - if (anchor == null) return false; + if (anchor == null) { + if (mOverflowButton == null) return false; + anchor = mOverflowButton; + } + mOpenSubMenuId = subMenu.getItem().getItemId(); mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu); mActionButtonPopup.setAnchorView(anchor); mActionButtonPopup.show(); @@ -426,6 +434,57 @@ public class ActionMenuPresenter extends BaseMenuPresenter { super.onCloseMenu(menu, allMenusAreClosing); } + @Override + public Parcelable onSaveInstanceState() { + SavedState state = new SavedState(); + state.openSubMenuId = mOpenSubMenuId; + return state; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState saved = (SavedState) state; + if (saved.openSubMenuId > 0) { + MenuItem item = mMenu.findItem(saved.openSubMenuId); + if (item != null) { + SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + onSubMenuSelected(subMenu); + } + } + } + + private static class SavedState implements Parcelable { + public int openSubMenuId; + + SavedState() { + } + + SavedState(Parcel in) { + openSubMenuId = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(openSubMenuId); + } + + public static final Parcelable.Creator<SavedState> CREATOR + = new Parcelable.Creator<SavedState>() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + private class OverflowMenuButton extends ImageButton implements ActionMenuChildView { public OverflowMenuButton(Context context) { super(context, null, com.android.internal.R.attr.actionOverflowButtonStyle); @@ -460,6 +519,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter { public OverflowPopup(Context context, MenuBuilder menu, View anchorView, boolean overflowOnly) { super(context, menu, anchorView, overflowOnly); + setCallback(mPopupPresenterCallback); } @Override @@ -482,6 +542,8 @@ public class ActionMenuPresenter extends BaseMenuPresenter { // Give a reasonable anchor to nested submenus. setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton); } + + setCallback(mPopupPresenterCallback); } @Override @@ -489,6 +551,20 @@ public class ActionMenuPresenter extends BaseMenuPresenter { super.onDismiss(); mSubMenu.close(); mActionButtonPopup = null; + mOpenSubMenuId = 0; + } + } + + private class PopupPresenterCallback implements MenuPresenter.Callback { + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); + return false; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { } } diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java index ddbb08c01e68..ed9d34a25a90 100644 --- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java @@ -39,6 +39,8 @@ public abstract class BaseMenuPresenter implements MenuPresenter { protected MenuView mMenuView; + private int mId; + /** * Construct a new BaseMenuPresenter. * @@ -200,4 +202,12 @@ public abstract class BaseMenuPresenter implements MenuPresenter { public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { return false; } + + public int getId() { + return mId; + } + + public void setId(int id) { + mId = id; + } } diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java index f71790479f7f..56128d4659bd 100644 --- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java @@ -23,6 +23,7 @@ import android.os.Parcelable; import android.util.SparseArray; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -35,7 +36,12 @@ public class IconMenuPresenter extends BaseMenuPresenter { private IconMenuItemView mMoreView; private int mMaxItems = -1; + int mOpenSubMenuId; + SubMenuPresenterCallback mSubMenuPresenterCallback = new SubMenuPresenterCallback(); + MenuDialogHelper mOpenSubMenu; + private static final String VIEWS_TAG = "android:menu:icon"; + private static final String OPEN_SUBMENU_KEY = "android:menu:icon:submenu"; public IconMenuPresenter() { super(com.android.internal.R.layout.icon_menu_layout, @@ -86,7 +92,11 @@ public class IconMenuPresenter extends BaseMenuPresenter { if (!subMenu.hasVisibleItems()) return false; // The window manager will give us a token. - new MenuDialogHelper(subMenu).show(null); + MenuDialogHelper helper = new MenuDialogHelper(subMenu); + helper.setPresenterCallback(mSubMenuPresenterCallback); + helper.show(null); + mOpenSubMenu = helper; + mOpenSubMenuId = subMenu.getItem().getItemId(); super.onSubMenuSelected(subMenu); return true; } @@ -137,5 +147,47 @@ public class IconMenuPresenter extends BaseMenuPresenter { if (viewStates != null) { ((View) mMenuView).restoreHierarchyState(viewStates); } + int subMenuId = inState.getInt(OPEN_SUBMENU_KEY, 0); + if (subMenuId > 0 && mMenu != null) { + MenuItem item = mMenu.findItem(subMenuId); + if (item != null) { + onSubMenuSelected((SubMenuBuilder) item.getSubMenu()); + } + } + } + + @Override + public Parcelable onSaveInstanceState() { + if (mMenuView == null) { + return null; + } + + Bundle state = new Bundle(); + saveHierarchyState(state); + if (mOpenSubMenuId > 0) { + state.putInt(OPEN_SUBMENU_KEY, mOpenSubMenuId); + } + return state; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + restoreHierarchyState((Bundle) state); + } + + class SubMenuPresenterCallback implements MenuPresenter.Callback { + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + mOpenSubMenuId = 0; + mOpenSubMenu.dismiss(); + mOpenSubMenu = null; + } + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); + return false; + } + } } diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java index 27e4191ae790..146c7ac8a3e0 100644 --- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java @@ -47,6 +47,8 @@ public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClick private Callback mCallback; private MenuAdapter mAdapter; + private int mId; + public static final String VIEWS_TAG = "android:menu:list"; /** @@ -182,6 +184,31 @@ public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClick } } + public void setId(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + + @Override + public Parcelable onSaveInstanceState() { + if (mMenuView == null) { + return null; + } + + Bundle state = new Bundle(); + saveHierarchyState(state); + return state; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + restoreHierarchyState((Bundle) state); + } + private class MenuAdapter extends BaseAdapter { public int getCount() { ArrayList<MenuItemImpl> items = mMenu.getNonActionItems(); diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index fdfa9546a040..a4edbc5166e0 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -25,8 +25,8 @@ import android.content.pm.ResolveInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.Parcelable; -import android.util.Log; import android.util.SparseArray; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyCharacterMap; @@ -38,7 +38,6 @@ import android.view.View; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -49,6 +48,8 @@ import java.util.concurrent.CopyOnWriteArrayList; public class MenuBuilder implements Menu { private static final String LOGTAG = "MenuBuilder"; + private static final String PRESENTER_KEY = "android:menu:presenters"; + private static final int[] sCategoryToOrder = new int[] { 1, /* No category */ 4, /* CONTAINER */ @@ -254,6 +255,58 @@ public class MenuBuilder implements Menu { return result; } + private void dispatchSaveInstanceState(Bundle outState) { + if (mPresenters.isEmpty()) return; + + SparseArray<Parcelable> presenterStates = new SparseArray<Parcelable>(); + + for (WeakReference<MenuPresenter> ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + final int id = presenter.getId(); + if (id > 0) { + final Parcelable state = presenter.onSaveInstanceState(); + if (state != null) { + presenterStates.put(id, state); + } + } + } + } + + outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates); + } + + private void dispatchRestoreInstanceState(Bundle state) { + SparseArray<Parcelable> presenterStates = state.getSparseParcelableArray(PRESENTER_KEY); + + if (presenterStates == null || mPresenters.isEmpty()) return; + + for (WeakReference<MenuPresenter> ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + final int id = presenter.getId(); + if (id > 0) { + Parcelable parcel = presenterStates.get(id); + if (parcel != null) { + presenter.onRestoreInstanceState(parcel); + } + } + } + } + } + + public void savePresenterStates(Bundle outState) { + dispatchSaveInstanceState(outState); + } + + public void restorePresenterStates(Bundle state) { + dispatchRestoreInstanceState(state); + } + public void setCallback(Callback cb) { mCallback = cb; } diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index cffbb4ea7696..4ecc8287d4f0 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -18,6 +18,7 @@ package com.android.internal.view.menu; import android.content.Context; import android.content.res.Resources; +import android.os.Parcelable; import android.util.DisplayMetrics; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -296,4 +297,18 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On return convertView; } } + + @Override + public int getId() { + return 0; + } + + @Override + public Parcelable onSaveInstanceState() { + return null; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + } } diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java index bd664489aff7..d913a39b242d 100644 --- a/core/java/com/android/internal/view/menu/MenuPresenter.java +++ b/core/java/com/android/internal/view/menu/MenuPresenter.java @@ -17,6 +17,7 @@ package com.android.internal.view.menu; import android.content.Context; +import android.os.Parcelable; import android.view.Menu; import android.view.ViewGroup; @@ -125,4 +126,24 @@ public interface MenuPresenter { * @return true if this presenter collapsed the action view, false otherwise. */ public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item); + + /** + * Returns an ID for determining how to save/restore instance state. + * @return a valid ID value. + */ + public int getId(); + + /** + * Returns a Parcelable describing the current state of the presenter. + * It will be passed to the {@link #onRestoreInstanceState(Parcelable)} + * method of the presenter sharing the same ID later. + * @return The saved instance state + */ + public Parcelable onSaveInstanceState(); + + /** + * Supplies the previously saved instance state to be restored. + * @param state The previously saved instance state + */ + public void onRestoreInstanceState(Parcelable state); } diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 09bc1fc3cf7f..595753a2b930 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -337,6 +337,7 @@ public class ActionBarView extends AbsActionBarView { if (mActionMenuPresenter == null) { mActionMenuPresenter = new ActionMenuPresenter(); mActionMenuPresenter.setCallback(cb); + mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter); mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter(); } @@ -1301,5 +1302,19 @@ public class ActionBarView extends AbsActionBarView { item.setActionViewExpanded(false); return true; } + + @Override + public int getId() { + return 0; + } + + @Override + public Parcelable onSaveInstanceState() { + return null; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + } } } diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml index d05685c6cecd..547a192fde45 100644 --- a/core/res/res/values/ids.xml +++ b/core/res/res/values/ids.xml @@ -74,4 +74,9 @@ <item type="id" name="rowTypeId" /> <item type="id" name="up" /> <item type="id" name="action_menu_divider" /> + <item type="id" name="icon_menu_presenter" /> + <item type="id" name="list_menu_presenter" /> + <item type="id" name="action_menu_presenter" /> + <item type="id" name="overflow_menu_presenter" /> + <item type="id" name="popup_submenu_presenter" /> </resources> diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 7f6327dd88dd..dff0556e1e82 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -1555,9 +1555,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // We restore the panel if it was last open; we skip it if it // now is open, to avoid a race condition if the user immediately // opens it when we are resuming. - if ((st != null) && !st.isOpen && st.wasLastOpen) { - st.isInExpandedMode = st.wasLastExpanded; - openPanel(st, null); + if (st != null) { + st.applyFrozenState(); + if (!st.isOpen && st.wasLastOpen) { + st.isInExpandedMode = st.wasLastExpanded; + openPanel(st, null); + } } } } @@ -2235,6 +2238,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } mActionModePopup = null; } + + PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false); + if (st != null && st.menu != null) { + st.menu.close(); + } } @Override @@ -3046,46 +3054,33 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { getIconMenuView(cb); // Need this initialized to know where our offset goes - boolean init = false; if (expandedMenuPresenter == null) { expandedMenuPresenter = new ListMenuPresenter( com.android.internal.R.layout.list_menu_item_layout, com.android.internal.R.style.Theme_ExpandedMenu); expandedMenuPresenter.setCallback(cb); + expandedMenuPresenter.setId(com.android.internal.R.id.list_menu_presenter); menu.addMenuPresenter(expandedMenuPresenter); - init = true; } expandedMenuPresenter.setItemIndexOffset(iconMenuPresenter.getNumActualItemsShown()); MenuView result = expandedMenuPresenter.getMenuView(decorView); - if (init && frozenMenuState != null) { - expandedMenuPresenter.restoreHierarchyState(frozenMenuState); - // Once we initialize the expanded menu we're done with the frozen state - // since we will have also restored any icon menu state. - frozenMenuState = null; - } - return result; } MenuView getIconMenuView(MenuPresenter.Callback cb) { if (menu == null) return null; - boolean init = false; if (iconMenuPresenter == null) { iconMenuPresenter = new IconMenuPresenter(); iconMenuPresenter.setCallback(cb); + iconMenuPresenter.setId(com.android.internal.R.id.icon_menu_presenter); menu.addMenuPresenter(iconMenuPresenter); - init = true; } MenuView result = iconMenuPresenter.getMenuView(decorView); - if (init && frozenMenuState != null) { - iconMenuPresenter.restoreHierarchyState(frozenMenuState); - } - return result; } @@ -3097,12 +3092,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (menu != null) { savedState.menuState = new Bundle(); - if (iconMenuPresenter != null) { - iconMenuPresenter.saveHierarchyState(savedState.menuState); - } - if (expandedMenuPresenter != null) { - expandedMenuPresenter.saveHierarchyState(savedState.menuState); - } + menu.savePresenterStates(savedState.menuState); } return savedState; @@ -3127,6 +3117,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { decorView = null; } + void applyFrozenState() { + if (menu != null && frozenMenuState != null) { + menu.restorePresenterStates(frozenMenuState); + frozenMenuState = null; + } + } + private static class SavedState implements Parcelable { int featureId; boolean isOpen; |