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;