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();