Support ActionProvider functionality from API 16
Add the API 16 ActionProvider methods regarding visibility changes to
appcompat.
Fix a previously introduced bug inflating ActionProviders.
Change-Id: Ieff63683af4515eaacd0a25fddd168a7e71006cd
diff --git a/v4/java/android/support/v4/view/ActionProvider.java b/v4/java/android/support/v4/view/ActionProvider.java
index a1a9e74..0668e0e 100644
--- a/v4/java/android/support/v4/view/ActionProvider.java
+++ b/v4/java/android/support/v4/view/ActionProvider.java
@@ -17,6 +17,8 @@
package android.support.v4.view;
import android.content.Context;
+import android.util.Log;
+import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
@@ -58,9 +60,11 @@
* @see android.support.v4.view.MenuItemCompat#getActionProvider(android.view.MenuItem)
*/
public abstract class ActionProvider {
+ private static final String TAG = "ActionProvider(support)";
private final Context mContext;
private SubUiVisibilityListener mSubUiVisibilityListener;
+ private VisibilityListener mVisibilityListener;
/**
* Creates a new instance.
@@ -86,6 +90,60 @@
public abstract View onCreateActionView();
/**
+ * Factory method called by the Android framework to create new action views.
+ * This method returns a new action view for the given MenuItem.
+ *
+ * <p>If your ActionProvider implementation overrides the deprecated no-argument overload
+ * {@link #onCreateActionView()}, overriding this method for devices running API 16 or later
+ * is recommended but optional. The default implementation calls {@link #onCreateActionView()}
+ * for compatibility with applications written for older platform versions.</p>
+ *
+ * @param forItem MenuItem to create the action view for
+ * @return the new action view
+ */
+ public View onCreateActionView(MenuItem forItem) {
+ return onCreateActionView();
+ }
+
+ /**
+ * The result of this method determines whether or not {@link #isVisible()} will be used
+ * by the {@link MenuItem} this ActionProvider is bound to help determine its visibility.
+ *
+ * @return true if this ActionProvider overrides the visibility of the MenuItem
+ * it is bound to, false otherwise. The default implementation returns false.
+ * @see #isVisible()
+ */
+ public boolean overridesItemVisibility() {
+ return false;
+ }
+
+ /**
+ * If {@link #overridesItemVisibility()} returns true, the return value of this method
+ * will help determine the visibility of the {@link MenuItem} this ActionProvider is bound to.
+ *
+ * <p>If the MenuItem's visibility is explicitly set to false by the application,
+ * the MenuItem will not be shown, even if this method returns true.</p>
+ *
+ * @return true if the MenuItem this ActionProvider is bound to is visible, false if
+ * it is invisible. The default implementation returns true.
+ */
+ public boolean isVisible() {
+ return true;
+ }
+
+ /**
+ * If this ActionProvider is associated with an item in a menu,
+ * refresh the visibility of the item based on {@link #overridesItemVisibility()} and
+ * {@link #isVisible()}. If {@link #overridesItemVisibility()} returns false, this call
+ * will have no effect.
+ */
+ public void refreshVisibility() {
+ if (mVisibilityListener != null && overridesItemVisibility()) {
+ mVisibilityListener.onActionProviderVisibilityChanged(isVisible());
+ }
+ }
+
+ /**
* Performs an optional default action.
*
* <p>For the case of an action provider placed in a menu
@@ -165,10 +223,35 @@
}
/**
+ * Set a listener to be notified when this ActionProvider's overridden visibility changes.
+ * This should only be used by MenuItem implementations.
+ *
+ * @param listener listener to set
+ */
+ public void setVisibilityListener(VisibilityListener listener) {
+ if (mVisibilityListener != null && listener != null) {
+ Log.w(TAG, "setVisibilityListener: Setting a new ActionProvider.VisibilityListener " +
+ "when one is already set. Are you reusing this " + getClass().getSimpleName() +
+ " instance while it is still in use somewhere else?");
+ }
+ mVisibilityListener = listener;
+ }
+
+ /**
* @hide Internal use only
*/
public interface SubUiVisibilityListener {
public void onSubUiVisibilityChanged(boolean isVisible);
}
+
+ /**
+ * Listens to changes in visibility as reported by {@link ActionProvider#refreshVisibility()}.
+ *
+ * @see ActionProvider#overridesItemVisibility()
+ * @see ActionProvider#isVisible()
+ */
+ public interface VisibilityListener {
+ public void onActionProviderVisibilityChanged(boolean isVisible);
+ }
}
diff --git a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java b/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
index afedc69..1ba0d9f 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/SupportMenuInflater.java
@@ -444,8 +444,8 @@
+ " Action view already specified.");
}
}
- if (impl != null && itemActionProvider != null) {
- impl.setSupportActionProvider(itemActionProvider);
+ if (itemActionProvider != null) {
+ MenuItemCompat.setActionProvider(item, itemActionProvider);
}
}
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
index 06fbeee..35e6bfc 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemImpl.java
@@ -585,7 +585,7 @@
if (mActionView != null) {
return mActionView;
} else if (mActionProvider != null) {
- mActionView = mActionProvider.onCreateActionView();
+ mActionView = mActionProvider.onCreateActionView(this);
return mActionView;
} else {
return null;
@@ -609,9 +609,24 @@
}
public SupportMenuItem setSupportActionProvider(ActionProvider actionProvider) {
+ if (mActionProvider == actionProvider) {
+ return this;
+ }
+
mActionView = null;
+ if (mActionProvider != null) {
+ mActionProvider.setVisibilityListener(null);
+ }
mActionProvider = actionProvider;
mMenu.onItemsChanged(true); // Measurement can be changed
+ if (actionProvider != null) {
+ actionProvider.setVisibilityListener(new ActionProvider.VisibilityListener() {
+ @Override
+ public void onActionProviderVisibilityChanged(boolean isVisible) {
+ setVisible(isVisible);
+ }
+ });
+ }
return this;
}
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperHC.java b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperHC.java
index ce9fae8..699af0e 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperHC.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperHC.java
@@ -312,16 +312,19 @@
@Override
@SuppressWarnings("deprecation")
public View onCreateActionView() {
- return mInner.onCreateActionView();
+ return mInner.onCreateActionView(mWrappedObject);
}
- @Override
+ public boolean overridesItemVisibility() {
+ return mInner.overridesItemVisibility();
+ }
+
public boolean isVisible() {
- return true;
+ return mInner.isVisible();
}
- @Override
public void refreshVisibility() {
+ mInner.refreshVisibility();
}
@Override
diff --git a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
index cf14513..8da2bc3 100644
--- a/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
+++ b/v7/appcompat/src/android/support/v7/internal/view/menu/MenuItemWrapperICS.java
@@ -99,9 +99,9 @@
}
}
- private class ActionProviderWrapper extends android.view.ActionProvider {
+ class ActionProviderWrapper extends android.view.ActionProvider {
- private final ActionProvider mWrappedObject;
+ final ActionProvider mWrappedObject;
public ActionProviderWrapper(ActionProvider object) {
super(null);
@@ -110,9 +110,22 @@
@Override
public View onCreateActionView() {
- return mWrappedObject.onCreateActionView();
+ return mWrappedObject.onCreateActionView(MenuItemWrapperICS.this.mWrappedObject);
}
+ public boolean overridesItemVisibility() {
+ return mWrappedObject.overridesItemVisibility();
+ }
+
+ public boolean isVisible() {
+ return mWrappedObject.isVisible();
+ }
+
+ public void refreshVisibility() {
+ mWrappedObject.refreshVisibility();
+ }
+
+
@Override
public boolean onPerformDefaultAction() {
return mWrappedObject.onPerformDefaultAction();