diff --git a/api/current.txt b/api/current.txt
index 93f7a8f26b88d..a499cee4efcb3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21004,6 +21004,11 @@ package android.view {
method public void onPrepareSubMenu(android.view.SubMenu);
}
+ public abstract interface CollapsibleActionView {
+ method public abstract void onActionViewCollapsed();
+ method public abstract void onActionViewExpanded();
+ }
+
public abstract interface ContextMenu implements android.view.Menu {
method public abstract void clearHeader();
method public abstract android.view.ContextMenu setHeaderIcon(int);
diff --git a/core/java/android/view/CollapsibleActionView.java b/core/java/android/view/CollapsibleActionView.java
new file mode 100644
index 0000000000000..ac1edbb794b35
--- /dev/null
+++ b/core/java/android/view/CollapsibleActionView.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * When a {@link View} implements this interface it will receive callbacks
+ * when expanded or collapsed as an action view alongside the optional,
+ * app-specified callbacks to {@link OnActionExpandListener}.
+ *
+ *
See {@link MenuItem} for more information about action views.
+ * See {@link android.app.ActionBar} for more information about the action bar.
+ */
+public interface CollapsibleActionView {
+ /**
+ * Called when this view is expanded as an action view.
+ * See {@link MenuItem#expandActionView()}.
+ */
+ public void onActionViewExpanded();
+
+ /**
+ * Called when this view is collapsed as an action view.
+ * See {@link MenuItem#collapseActionView()}.
+ */
+ public void onActionViewCollapsed();
+}
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 164d5811c31e1..159b3da440bd9 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -50,6 +50,8 @@ public class MenuBuilder implements Menu {
private static final String LOGTAG = "MenuBuilder";
private static final String PRESENTER_KEY = "android:menu:presenters";
+ private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
+ private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview";
private static final int[] sCategoryToOrder = new int[] {
1, /* No category */
@@ -308,6 +310,67 @@ public class MenuBuilder implements Menu {
dispatchRestoreInstanceState(state);
}
+ public void saveActionViewStates(Bundle outStates) {
+ SparseArray viewStates = null;
+
+ final int itemCount = size();
+ for (int i = 0; i < itemCount; i++) {
+ final MenuItem item = getItem(i);
+ final View v = item.getActionView();
+ if (v != null && v.getId() != View.NO_ID) {
+ if (viewStates == null) {
+ viewStates = new SparseArray();
+ }
+ v.saveHierarchyState(viewStates);
+ if (item.isActionViewExpanded()) {
+ outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
+ }
+ }
+ if (item.hasSubMenu()) {
+ final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ subMenu.saveActionViewStates(outStates);
+ }
+ }
+
+ if (viewStates != null) {
+ outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates);
+ }
+ }
+
+ public void restoreActionViewStates(Bundle states) {
+ if (states == null) {
+ return;
+ }
+
+ SparseArray viewStates = states.getSparseParcelableArray(
+ getActionViewStatesKey());
+
+ final int itemCount = size();
+ for (int i = 0; i < itemCount; i++) {
+ final MenuItem item = getItem(i);
+ final View v = item.getActionView();
+ if (v != null && v.getId() != View.NO_ID) {
+ v.restoreHierarchyState(viewStates);
+ }
+ if (item.hasSubMenu()) {
+ final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+ subMenu.restoreActionViewStates(states);
+ }
+ }
+
+ final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID);
+ if (expandedId > 0) {
+ MenuItem itemToExpand = findItem(expandedId);
+ if (itemToExpand != null) {
+ itemToExpand.expandActionView();
+ }
+ }
+ }
+
+ protected String getActionViewStatesKey() {
+ return ACTION_VIEW_STATES_KEY;
+ }
+
public void setCallback(Callback cb) {
mCallback = cb;
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 541d10120dd60..b0a002d2ce8d6 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -553,6 +553,9 @@ public final class MenuItemImpl implements MenuItem {
public MenuItem setActionView(View view) {
mActionView = view;
mActionProvider = null;
+ if (view != null && view.getId() == View.NO_ID && mId > 0) {
+ view.setId(mId);
+ }
mMenu.onItemActionRequestChanged(this);
return this;
}
diff --git a/core/java/com/android/internal/view/menu/SubMenuBuilder.java b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
index fb1cd5e81ef76..92acf8cda8f5c 100644
--- a/core/java/com/android/internal/view/menu/SubMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/SubMenuBuilder.java
@@ -121,4 +121,13 @@ public class SubMenuBuilder extends MenuBuilder implements SubMenu {
public boolean collapseItemActionView(MenuItemImpl item) {
return mParentMenu.collapseItemActionView(item);
}
+
+ @Override
+ public String getActionViewStatesKey() {
+ final int itemId = mItem != null ? mItem.getItemId() : 0;
+ if (itemId == 0) {
+ return null;
+ }
+ return super.getActionViewStatesKey() + ":" + itemId;
+ }
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index e03858b4af13c..8b74f3d004285 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -42,6 +42,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.view.CollapsibleActionView;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -1304,6 +1305,10 @@ public class ActionBarView extends AbsActionBarView {
if (mCustomNavView != null) mCustomNavView.setVisibility(GONE);
requestLayout();
item.setActionViewExpanded(true);
+
+ if (mExpandedActionView instanceof CollapsibleActionView) {
+ ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
+ }
return true;
}
@@ -1330,11 +1335,16 @@ public class ActionBarView extends AbsActionBarView {
if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
mCustomNavView.setVisibility(VISIBLE);
}
+ View collapsedView = mExpandedActionView;
mExpandedActionView = null;
mExpandedHomeLayout.setIcon(null);
mCurrentExpandedItem = null;
requestLayout();
item.setActionViewExpanded(false);
+
+ if (collapsedView instanceof CollapsibleActionView) {
+ ((CollapsibleActionView) collapsedView).onActionViewCollapsed();
+ }
return true;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b963b131f59fb..e0debf7ca9947 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -388,6 +388,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
st.isHandled = false;
mPreparedPanel = st;
+ if (st.frozenActionViewState != null) {
+ st.menu.restoreActionViewStates(st.frozenActionViewState);
+ st.frozenActionViewState = null;
+ }
+
return true;
}
@@ -652,7 +657,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
public void invalidatePanelMenu(int featureId) {
PanelFeatureState st = getPanelState(featureId, true);
+ Bundle savedActionViewStates = null;
if (st.menu != null) {
+ savedActionViewStates = new Bundle();
+ st.menu.saveActionViewStates(savedActionViewStates);
+ if (savedActionViewStates.size() > 0) {
+ st.frozenActionViewState = savedActionViewStates;
+ }
st.menu.clear();
}
st.refreshMenuContent = true;
@@ -3024,6 +3035,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
*/
Bundle frozenMenuState;
+ /**
+ * Contains the state of associated action views when told to freeze.
+ * These are saved across invalidations.
+ */
+ Bundle frozenActionViewState;
+
PanelFeatureState(int featureId) {
this.featureId = featureId;