Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 706a8699 authored by Adam Powell's avatar Adam Powell Committed by Android (Google) Code Review
Browse files

Merge "Make MediaRouter UI more robust around route count changes" into jb-dev

parents d7a04de1 39d5c617
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -22822,6 +22822,12 @@ package android.view {
    method public boolean onPerformDefaultAction();
    method public void onPrepareSubMenu(android.view.SubMenu);
    method public boolean overridesItemVisibility();
    method public void refreshVisibility();
    method public void setVisibilityListener(android.view.ActionProvider.VisibilityListener);
  }
  public static abstract interface ActionProvider.VisibilityListener {
    method public abstract void onActionProviderVisibilityChanged(boolean);
  }
  public final class Choreographer {
+42 −1
Original line number Diff line number Diff line
@@ -21,11 +21,14 @@ import com.android.internal.app.MediaRouteChooserDialogFragment;
import android.content.Context;
import android.content.ContextWrapper;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.util.Log;
import android.view.ActionProvider;
import android.view.MenuItem;
import android.view.View;

import java.lang.ref.WeakReference;

public class MediaRouteActionProvider extends ActionProvider {
    private static final String TAG = "MediaRouteActionProvider";

@@ -35,11 +38,13 @@ public class MediaRouteActionProvider extends ActionProvider {
    private MediaRouteButton mView;
    private int mRouteTypes;
    private View.OnClickListener mExtendedSettingsListener;
    private RouterCallback mCallback;

    public MediaRouteActionProvider(Context context) {
        super(context);
        mContext = context;
        mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
        mCallback = new RouterCallback(this);

        // Start with live audio by default.
        // TODO Update this when new route types are added; segment by API level
@@ -48,7 +53,14 @@ public class MediaRouteActionProvider extends ActionProvider {
    }

    public void setRouteTypes(int types) {
        if (mRouteTypes == types) return;
        if (mRouteTypes != 0) {
            mRouter.removeCallback(mCallback);
        }
        mRouteTypes = types;
        if (types != 0) {
            mRouter.addCallback(types, mCallback);
        }
        if (mView != null) {
            mView.setRouteTypes(mRouteTypes);
        }
@@ -68,7 +80,6 @@ public class MediaRouteActionProvider extends ActionProvider {
        }
        mMenuItem = item;
        mView = new MediaRouteButton(mContext);
        mMenuItem.setVisible(mRouter.getRouteCount() > 1);
        mView.setRouteTypes(mRouteTypes);
        mView.setExtendedSettingsClickListener(mExtendedSettingsListener);
        return mView;
@@ -123,4 +134,34 @@ public class MediaRouteActionProvider extends ActionProvider {
    public boolean isVisible() {
        return mRouter.getRouteCount() > 1;
    }

    private static class RouterCallback extends MediaRouter.SimpleCallback {
        private WeakReference<MediaRouteActionProvider> mAp;

        RouterCallback(MediaRouteActionProvider ap) {
            mAp = new WeakReference<MediaRouteActionProvider>(ap);
        }

        @Override
        public void onRouteAdded(MediaRouter router, RouteInfo info) {
            final MediaRouteActionProvider ap = mAp.get();
            if (ap == null) {
                router.removeCallback(this);
                return;
            }

            ap.refreshVisibility();
        }

        @Override
        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
            final MediaRouteActionProvider ap = mAp.get();
            if (ap == null) {
                router.removeCallback(this);
                return;
            }

            ap.refreshVisibility();
        }
    }
}
+40 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.view;

import android.content.Context;
import android.util.Log;

/**
 * An ActionProvider defines rich menu interaction in a single component.
@@ -55,7 +56,9 @@ import android.content.Context;
 * @see MenuItem#getActionProvider()
 */
public abstract class ActionProvider {
    private static final String TAG = "ActionProvider";
    private SubUiVisibilityListener mSubUiVisibilityListener;
    private VisibilityListener mVisibilityListener;

    /**
     * Creates a new instance. ActionProvider classes should always implement a
@@ -121,6 +124,18 @@ public abstract class ActionProvider {
        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>
@@ -206,10 +221,35 @@ public abstract class ActionProvider {
        mSubUiVisibilityListener = listener;
    }

    /**
     * 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) {
            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);
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -589,9 +589,17 @@ public final class MenuItemImpl implements MenuItem {
    }

    public MenuItem setActionProvider(ActionProvider actionProvider) {
        if (mActionProvider != null) {
            mActionProvider.setVisibilityListener(null);
        }
        mActionView = null;
        mActionProvider = actionProvider;
        mMenu.onItemsChanged(true); // Measurement can be changed
        mActionProvider.setVisibilityListener(new ActionProvider.VisibilityListener() {
            @Override public void onActionProviderVisibilityChanged(boolean isVisible) {
                mMenu.onItemVisibleChanged(MenuItemImpl.this);
            }
        });
        return this;
    }

+10 −22
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * MediaRouter allows applications to control the routing of media channels
@@ -48,7 +49,8 @@ public class MediaRouter {
        final Resources mResources;
        final IAudioService mAudioService;
        final Handler mHandler;
        final ArrayList<CallbackInfo> mCallbacks = new ArrayList<CallbackInfo>();
        final CopyOnWriteArrayList<CallbackInfo> mCallbacks =
                new CopyOnWriteArrayList<CallbackInfo>();

        final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
        final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>();
@@ -497,9 +499,7 @@ public class MediaRouter {
    }

    static void dispatchRouteSelected(int type, RouteInfo info) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & type) != 0) {
                cbi.cb.onRouteSelected(cbi.router, type, info);
            }
@@ -507,9 +507,7 @@ public class MediaRouter {
    }

    static void dispatchRouteUnselected(int type, RouteInfo info) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & type) != 0) {
                cbi.cb.onRouteUnselected(cbi.router, type, info);
            }
@@ -517,9 +515,7 @@ public class MediaRouter {
    }

    static void dispatchRouteChanged(RouteInfo info) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
                cbi.cb.onRouteChanged(cbi.router, info);
            }
@@ -527,9 +523,7 @@ public class MediaRouter {
    }

    static void dispatchRouteAdded(RouteInfo info) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
                cbi.cb.onRouteAdded(cbi.router, info);
            }
@@ -537,9 +531,7 @@ public class MediaRouter {
    }

    static void dispatchRouteRemoved(RouteInfo info) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
                cbi.cb.onRouteRemoved(cbi.router, info);
            }
@@ -547,9 +539,7 @@ public class MediaRouter {
    }

    static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & group.mSupportedTypes) != 0) {
                cbi.cb.onRouteGrouped(cbi.router, info, group, index);
            }
@@ -557,9 +547,7 @@ public class MediaRouter {
    }

    static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo cbi = sStatic.mCallbacks.get(i);
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & group.mSupportedTypes) != 0) {
                cbi.cb.onRouteUngrouped(cbi.router, info, group);
            }