From 8515ee846bd76aee86ec5ddfcc4dd1e626dd999c Mon Sep 17 00:00:00 2001
From: Adam Powell
Date: Tue, 30 Nov 2010 14:09:55 -0800
Subject: [PATCH] Fix bug 3240444 - add OnMenuVisibilityListener for action
bar.
Fix bug 3180015 - leaking window handles on configuration change for
action bar dropdown menus
Rename ActionBar.NavigationCallback to something more consistent with
the rest of the API.
Change-Id: Ic1fb4c07484c57a72649b30e27d220b18cda6cdf
---
api/current.xml | 57 +++++++++++--
core/java/android/app/ActionBar.java | 48 +++++++++--
core/java/android/app/Activity.java | 9 +-
core/java/android/app/Dialog.java | 6 ++
.../android/internal/app/ActionBarImpl.java | 32 ++++++-
.../internal/view/StandaloneActionMode.java | 2 +-
.../internal/view/menu/ActionMenuView.java | 76 +++++++++++++----
.../internal/view/menu/MenuPopupHelper.java | 16 ++--
.../internal/widget/ActionBarContextView.java | 6 ++
.../internal/widget/ActionBarView.java | 19 ++++-
docs/html/guide/topics/ui/actionbar.jd | 22 ++---
.../internal/policy/impl/PhoneWindow.java | 84 ++++++++++++++++++-
12 files changed, 313 insertions(+), 64 deletions(-)
diff --git a/api/current.xml b/api/current.xml
index e7d5ff43f224e..9fc6e3ede8577 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -20749,6 +20749,19 @@
visibility="public"
>
+
+
+
+
+
+
+
+
-
+
-
+
@@ -21163,7 +21189,7 @@
>
-
+
-
+
+
+
+
+
+
-
+
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 7a6ad0f395bd5..2f695202d5f31 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -168,13 +168,13 @@ public abstract class ActionBar {
* @param adapter An adapter that will provide views both to display
* the current navigation selection and populate views
* within the dropdown navigation menu.
- * @param callback A NavigationCallback that will receive events when the user
+ * @param callback A OnNavigationListener that will receive events when the user
* selects a navigation item.
* @deprecated See setListNavigationCallbacks.
*/
@Deprecated
public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
- NavigationCallback callback);
+ OnNavigationListener callback);
/**
* Set the adapter and navigation callback for list navigation mode.
@@ -182,17 +182,17 @@ public abstract class ActionBar {
* The supplied adapter will provide views for the expanded list as well as
* the currently selected item. (These may be displayed differently.)
*
- * The supplied NavigationCallback will alert the application when the user
+ * The supplied OnNavigationListener will alert the application when the user
* changes the current list selection.
*
* @param adapter An adapter that will provide views both to display
* the current navigation selection and populate views
* within the dropdown navigation menu.
- * @param callback A NavigationCallback that will receive events when the user
+ * @param callback An OnNavigationListener that will receive events when the user
* selects a navigation item.
*/
public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
- NavigationCallback callback);
+ OnNavigationListener callback);
/**
* Set the action bar into dropdown navigation mode and supply an adapter that will
@@ -201,7 +201,7 @@ public abstract class ActionBar {
* @param adapter An adapter that will provide views both to display the current
* navigation selection and populate views within the dropdown
* navigation menu.
- * @param callback A NavigationCallback that will receive events when the user
+ * @param callback A OnNavigationListener that will receive events when the user
* selects a navigation item.
* @param defaultSelectedPosition Position within the provided adapter that should be
* selected from the outset.
@@ -209,7 +209,7 @@ public abstract class ActionBar {
*/
@Deprecated
public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
- NavigationCallback callback, int defaultSelectedPosition);
+ OnNavigationListener callback, int defaultSelectedPosition);
/**
* Set the selected navigation item in list or tabbed navigation modes.
@@ -532,9 +532,24 @@ public abstract class ActionBar {
public abstract boolean isShowing();
/**
- * Callback interface for ActionBar navigation events.
+ * Add a listener that will respond to menu visibility change events.
+ *
+ * @param listener The new listener to add
*/
- public interface NavigationCallback {
+ public abstract void addOnMenuVisibilityListener(OnMenuVisibilityListener listener);
+
+ /**
+ * Remove a menu visibility listener. This listener will no longer receive menu
+ * visibility change events.
+ *
+ * @param listener A listener to remove that was previously added
+ */
+ public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
+
+ /**
+ * Listener interface for ActionBar navigation events.
+ */
+ public interface OnNavigationListener {
/**
* This method is called whenever a navigation item in your action bar
* is selected.
@@ -546,6 +561,21 @@ public abstract class ActionBar {
public boolean onNavigationItemSelected(int itemPosition, long itemId);
}
+ /**
+ * Listener for receiving events when action bar menus are shown or hidden.
+ */
+ public interface OnMenuVisibilityListener {
+ /**
+ * Called when an action bar menu is shown or hidden. Applications may want to use
+ * this to tune auto-hiding behavior for the action bar or pause/resume video playback,
+ * gameplay, or other activity within the main content area.
+ *
+ * @param isVisible True if an action bar menu is now visible, false if no action bar
+ * menus are visible.
+ */
+ public void onMenuVisibilityChanged(boolean isVisible);
+ }
+
/**
* A tab in the action bar.
*
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d69a179ce0f5b..6b619fb5567df 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2362,6 +2362,9 @@ public class Activity extends ContextThemeWrapper
* @return The default implementation returns true.
*/
public boolean onMenuOpened(int featureId, Menu menu) {
+ if (featureId == Window.FEATURE_ACTION_BAR) {
+ mActionBar.dispatchMenuVisibilityChanged(true);
+ }
return true;
}
@@ -2392,7 +2395,7 @@ public class Activity extends ContextThemeWrapper
return true;
}
return mFragments.dispatchContextItemSelected(item);
-
+
default:
return false;
}
@@ -2417,6 +2420,10 @@ public class Activity extends ContextThemeWrapper
case Window.FEATURE_CONTEXT_MENU:
onContextMenuClosed(menu);
break;
+
+ case Window.FEATURE_ACTION_BAR:
+ mActionBar.dispatchMenuVisibilityChanged(false);
+ break;
}
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 64a4d7a71c502..f90fc59a33b36 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -735,6 +735,9 @@ public class Dialog implements DialogInterface, Window.Callback,
* @see Activity#onMenuOpened(int, Menu)
*/
public boolean onMenuOpened(int featureId, Menu menu) {
+ if (featureId == Window.FEATURE_ACTION_BAR) {
+ mActionBar.dispatchMenuVisibilityChanged(true);
+ }
return true;
}
@@ -749,6 +752,9 @@ public class Dialog implements DialogInterface, Window.Callback,
* @see Activity#onPanelClosed(int, Menu)
*/
public void onPanelClosed(int featureId, Menu menu) {
+ if (featureId == Window.FEATURE_ACTION_BAR) {
+ mActionBar.dispatchMenuVisibilityChanged(false);
+ }
}
/**
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 20402a3363069..447a062e47136 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -70,6 +70,10 @@ public class ActionBarImpl extends ActionBar {
private ActionMode mActionMode;
+ private boolean mLastMenuVisibility;
+ private ArrayList mMenuVisibilityListeners =
+ new ArrayList();
+
private static final int CONTEXT_DISPLAY_NORMAL = 0;
private static final int CONTEXT_DISPLAY_SPLIT = 1;
@@ -120,6 +124,26 @@ public class ActionBarImpl extends ActionBar {
CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
}
+ public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+ mMenuVisibilityListeners.add(listener);
+ }
+
+ public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+ mMenuVisibilityListeners.remove(listener);
+ }
+
+ public void dispatchMenuVisibilityChanged(boolean isVisible) {
+ if (isVisible == mLastMenuVisibility) {
+ return;
+ }
+ mLastMenuVisibility = isVisible;
+
+ final int count = mMenuVisibilityListeners.size();
+ for (int i = 0; i < count; i++) {
+ mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
+ }
+ }
+
@Override
public void setTitle(int resId) {
setTitle(mContext.getString(resId));
@@ -138,11 +162,11 @@ public class ActionBarImpl extends ActionBar {
mActionView.setCallback(null);
}
- public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback) {
+ public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback) {
setDropdownNavigationMode(adapter, callback, -1);
}
- public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback,
+ public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback,
int defaultSelectedPosition) {
cleanupTabs();
setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
@@ -516,7 +540,7 @@ public class ActionBarImpl extends ActionBar {
public void onMenuModeChange(MenuBuilder menu) {
invalidate();
- mUpperContextView.showOverflowMenu();
+ mUpperContextView.openOverflowMenu();
}
}
@@ -627,7 +651,7 @@ public class ActionBarImpl extends ActionBar {
}
@Override
- public void setListNavigationCallbacks(SpinnerAdapter adapter, NavigationCallback callback) {
+ public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
mActionView.setDropdownAdapter(adapter);
mActionView.setCallback(callback);
}
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index b54daba3b96d5..2d067da15af40 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -135,6 +135,6 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call
public void onMenuModeChange(MenuBuilder menu) {
invalidate();
- mContextView.showOverflowMenu();
+ mContextView.openOverflowMenu();
}
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 621defe5fb25d..84067d004f230 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -59,6 +59,22 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
};
+ private class OpenOverflowRunnable implements Runnable {
+ private MenuPopupHelper mPopup;
+
+ public OpenOverflowRunnable(MenuPopupHelper popup) {
+ mPopup = popup;
+ }
+
+ public void run() {
+ mOverflowPopup = mPopup;
+ mPopup.show();
+ mPostedOpenRunnable = null;
+ }
+ }
+
+ private OpenOverflowRunnable mPostedOpenRunnable;
+
public ActionMenuView(Context context) {
this(context, null);
}
@@ -100,6 +116,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
final int screen = newConfig.screenLayout;
mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_XLARGE;
@@ -115,6 +132,14 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
}
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mOverflowPopup != null && mOverflowPopup.isShowing()) {
+ mOverflowPopup.dismiss();
+ }
+ }
+
private int getMaxActionButtons() {
return getResources().getInteger(com.android.internal.R.integer.max_action_buttons);
}
@@ -193,30 +218,34 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
public boolean showOverflowMenu() {
- if (mOverflowButton != null) {
- final MenuPopupHelper popup =
- new MenuPopupHelper(getContext(), mMenu, mOverflowButton, true);
- // Post this for later; we might still need a layout for the anchor to be right.
- post(new Runnable() {
- public void run() {
- popup.show();
- }
- });
- mOverflowPopup = popup;
+ if (mOverflowButton != null && !isOverflowMenuShowing()) {
+ mMenu.getCallback().onMenuModeChange(mMenu);
return true;
}
return false;
}
+ public void openOverflowMenu() {
+ OverflowPopup popup = new OverflowPopup(getContext(), mMenu, mOverflowButton, true);
+ mPostedOpenRunnable = new OpenOverflowRunnable(popup);
+ // Post this for later; we might still need a layout for the anchor to be right.
+ post(mPostedOpenRunnable);
+ }
+
public boolean isOverflowMenuShowing() {
- MenuPopupHelper popup = mOverflowPopup;
- if (popup != null) {
- return popup.isShowing();
- }
- return false;
+ return mOverflowPopup != null && mOverflowPopup.isShowing();
+ }
+
+ public boolean isOverflowMenuOpen() {
+ return mOverflowPopup != null;
}
public boolean hideOverflowMenu() {
+ if (mPostedOpenRunnable != null) {
+ removeCallbacks(mPostedOpenRunnable);
+ return true;
+ }
+
MenuPopupHelper popup = mOverflowPopup;
if (popup != null) {
popup.dismiss();
@@ -274,9 +303,22 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
return true;
}
- // Change to overflow mode
- mMenu.getCallback().onMenuModeChange(mMenu);
+ showOverflowMenu();
return true;
}
}
+
+ private class OverflowPopup extends MenuPopupHelper {
+ public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
+ boolean overflowOnly) {
+ super(context, menu, anchorView, overflowOnly);
+ }
+
+ @Override
+ public void onDismiss() {
+ super.onDismiss();
+ mMenu.getCallback().onCloseMenu(mMenu, true);
+ mOverflowPopup = null;
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 1406e4e1d5c94..2cb78a58c49bd 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -35,7 +35,7 @@ import java.lang.ref.WeakReference;
* @hide
*/
public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
- ViewTreeObserver.OnGlobalLayoutListener {
+ ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener {
private static final String TAG = "MenuPopupHelper";
private Context mContext;
@@ -46,12 +46,6 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
private boolean mOverflowOnly;
private ViewTreeObserver mTreeObserver;
- private PopupWindow.OnDismissListener mDismissListener = new PopupWindow.OnDismissListener() {
- public void onDismiss() {
- mPopup = null;
- }
- };
-
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false);
}
@@ -77,7 +71,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
public void show() {
mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
mPopup.setOnItemClickListener(this);
- mPopup.setOnDismissListener(mDismissListener);
+ mPopup.setOnDismissListener(this);
final MenuAdapter adapter = mOverflowOnly ?
mMenu.getOverflowMenuAdapter(MenuBuilder.TYPE_POPUP) :
@@ -110,8 +104,12 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
if (isShowing()) {
mPopup.dismiss();
}
+ }
+
+ public void onDismiss() {
+ mPopup = null;
if (mTreeObserver != null) {
- mTreeObserver.removeGlobalOnLayoutListener(this);
+ mTreeObserver.removeGlobalOnLayoutListener(MenuPopupHelper.this);
mTreeObserver = null;
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index e93c414fd774d..cbf12bf81962f 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -180,6 +180,12 @@ public class ActionBarContextView extends ViewGroup {
return false;
}
+ public void openOverflowMenu() {
+ if (mMenuView != null) {
+ mMenuView.openOverflowMenu();
+ }
+ }
+
public boolean hideOverflowMenu() {
if (mMenuView != null) {
return mMenuView.hideOverflowMenu();
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index f931217edc45b..07a65fcb94ffa 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -22,7 +22,7 @@ import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;
import android.app.ActionBar;
-import android.app.ActionBar.NavigationCallback;
+import android.app.ActionBar.OnNavigationListener;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -114,7 +114,7 @@ public class ActionBarView extends ViewGroup {
private ActionMenuItem mLogoNavItem;
private SpinnerAdapter mSpinnerAdapter;
- private NavigationCallback mCallback;
+ private OnNavigationListener mCallback;
private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@@ -243,7 +243,7 @@ public class ActionBarView extends ViewGroup {
return null;
}
- public void setCallback(NavigationCallback callback) {
+ public void setCallback(OnNavigationListener callback) {
mCallback = callback;
}
@@ -269,6 +269,12 @@ public class ActionBarView extends ViewGroup {
return false;
}
+ public void openOverflowMenu() {
+ if (mMenuView != null) {
+ mMenuView.openOverflowMenu();
+ }
+ }
+
public void postShowOverflowMenu() {
post(new Runnable() {
public void run() {
@@ -291,6 +297,13 @@ public class ActionBarView extends ViewGroup {
return false;
}
+ public boolean isOverflowMenuOpen() {
+ if (mMenuView != null) {
+ return mMenuView.isOverflowMenuOpen();
+ }
+ return false;
+ }
+
public boolean isOverflowReserved() {
return mMenuView != null && mMenuView.isOverflowReserved();
}
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index c3d3482fcc6f7..44d75c19dee54 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -455,7 +455,7 @@ Action Bar.
- Create a {@link android.widget.SpinnerAdapter} that provides the
list of selectable items for the list and the layout to use when drawing each item in the list.
- - Implement {@link android.app.ActionBar.NavigationCallback} to define the behavior when the
+
- Implement {@link android.app.ActionBar.OnNavigationListener} to define the behavior when the
user selects an item from the list.
- Turn on navigation mode for the Action Bar with {@link
android.app.ActionBar#setNavigationMode setNavigationMode()}. For example:
@@ -472,17 +472,17 @@ android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}.
actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);
This method takes your {@link android.widget.SpinnerAdapter} and {@link
-android.app.ActionBar.NavigationCallback}. More about these next.
+android.app.ActionBar.OnNavigationListener}. More about these next.
That's the basic setup. The {@link android.widget.SpinnerAdapter} and {@link
-android.app.ActionBar.NavigationCallback} is where most of the work is done. There are many ways
+android.app.ActionBar.OnNavigationListener} is where most of the work is done. There are many ways
you can implement these to define the functionality for your drop-down navigation. Implementing
various types of {@link android.widget.SpinnerAdapter} is beyond the scope of this
document—you should refer to the class refrence for more information about implementing it or
extending an existing implementation. However, below is a simple example for a {@link
-android.widget.SpinnerAdapter} and {@link android.app.ActionBar.NavigationCallback} to get you
+android.widget.SpinnerAdapter} and {@link android.app.ActionBar.OnNavigationListener} to get you
started.
@@ -520,24 +520,24 @@ defined as a resource looks like this:
-Example: simple NavigationCallback
+Example: simple OnNavigationListener
-Your implementation of {@link android.app.ActionBar.NavigationCallback} is where you handle
+
Your implementation of {@link android.app.ActionBar.OnNavigationListener} is where you handle
fragment changes or other modifications to your activity when the user selects an item from the
drop-down list. There's only one callback method to implement: {@link
-android.app.ActionBar.NavigationCallback#onNavigationItemSelected onNavigationItemSelected()}.
+android.app.ActionBar.OnNavigationListener#onNavigationItemSelected onNavigationItemSelected()}.
The {@link
-android.app.ActionBar.NavigationCallback#onNavigationItemSelected onNavigationItemSelected()}
+android.app.ActionBar.OnNavigationListener#onNavigationItemSelected onNavigationItemSelected()}
method receives the position of the item in the list and an item ID provided by the {@link
android.widget.SpinnerAdapter}.
Here's an example that instantiates an anonymous implementation of {@link
-android.app.ActionBar.NavigationCallback}, which inserts a {@link android.app.Fragment} into the
+android.app.ActionBar.OnNavigationListener}, which inserts a {@link android.app.Fragment} into the
layout container identified by {@code R.id.fragment_container}:
-mNavigationCallback = new NavigationCallback() {
+mOnNavigationListener = new OnNavigationListener() {
// Get the same strings provided for the drop-down's ArrayAdapter
String[] strings = getResources().getStringArray(R.array.action_list);
@@ -556,7 +556,7 @@ mNavigationCallback = new NavigationCallback() {
};
-This instance of {@link android.app.ActionBar.NavigationCallback} can be given to {@link
+
This instance of {@link android.app.ActionBar.OnNavigationListener} can be given to {@link
android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}, in step 4 from
above.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index cd8a0657bc9ce..138dff76235cd 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -160,6 +160,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
+ private ActionButtonSubmenu mActionButtonPopup;
+ private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
@@ -542,6 +544,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (doCallback) {
callOnPanelClosed(st.featureId, st, null);
}
+ } else if (st.featureId == FEATURE_OPTIONS_PANEL && doCallback &&
+ mActionBar != null) {
+ checkCloseActionMenu(st.menu);
}
st.isPrepared = false;
st.isHandled = false;
@@ -563,6 +568,27 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ private void checkCloseActionMenu(Menu menu) {
+ if (mClosingActionMenu) {
+ return;
+ }
+
+ boolean closed = false;
+ mClosingActionMenu = true;
+ if (mActionBar.isOverflowMenuOpen() && mActionBar.hideOverflowMenu()) {
+ closed = true;
+ }
+ if (mActionButtonPopup != null) {
+ mActionButtonPopup.dismiss();
+ closed = true;
+ }
+ Callback cb = getCallback();
+ if (cb != null && closed) {
+ cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
+ }
+ mClosingActionMenu = false;
+ }
+
@Override
public final void togglePanel(int featureId, KeyEvent event) {
PanelFeatureState st = getPanelState(featureId, true);
@@ -842,7 +868,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// The window manager will give us a valid window token
new MenuDialogHelper(subMenu).show(null);
} else {
- new MenuPopupHelper(getContext(), subMenu).show();
+ mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
+ mActionButtonPopup.show();
+ Callback cb = getCallback();
+ if (cb != null) {
+ cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+ }
}
return true;
@@ -854,16 +885,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private void reopenMenu(boolean toggleMenuMode) {
if (mActionBar != null) {
+ final Callback cb = getCallback();
if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
- final Callback cb = getCallback();
if (cb != null) {
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
- mActionBar.showOverflowMenu();
+ cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
+ mActionBar.openOverflowMenu();
}
}
} else {
mActionBar.hideOverflowMenu();
+ if (cb != null) {
+ final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+ cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
+ }
}
return;
}
@@ -2042,8 +2078,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
}
+
+ if (mActionButtonPopup != null) {
+ if (mActionButtonPopup.isShowing()) {
+ mActionButtonPopup.dismiss();
+ }
+ mActionButtonPopup = null;
+ }
}
-
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ if (mActionButtonPopup != null) {
+ mActionButtonPopup.dismiss();
+ post(mActionButtonPopup);
+ }
+ }
+
@Override
public void onCloseSystemDialogs(String reason) {
if (mFeatureId >= 0) {
@@ -2921,4 +2972,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
void sendCloseSystemWindows(String reason) {
PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
}
+
+ private class ActionButtonSubmenu extends MenuPopupHelper implements Runnable {
+ private SubMenuBuilder mSubMenu;
+
+ public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
+ super(context, subMenu);
+ mSubMenu = subMenu;
+ }
+
+ @Override
+ public void onDismiss() {
+ super.onDismiss();
+ mSubMenu.getCallback().onCloseSubMenu(mSubMenu);
+ mActionButtonPopup = null;
+ }
+
+ @Override
+ public void run() {
+ show();
+ Callback cb = getCallback();
+ if (cb != null) {
+ cb.onMenuOpened(FEATURE_ACTION_BAR, mSubMenu);
+ }
+ }
+ }
}