am 706a8699: Merge "Make MediaRouter UI more robust around route count changes" into jb-dev

* commit '706a8699008ce416a7fbd9a4215726fdb00ee803':
  Make MediaRouter UI more robust around route count changes
This commit is contained in:
Adam Powell
2012-06-18 10:34:29 -07:00
committed by Android Git Automerger
5 changed files with 106 additions and 23 deletions

View File

@@ -22823,6 +22823,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 {

View File

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

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);
}