/* * Copyright (C) 2012 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.app; import android.content.Context; 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 android.view.ViewGroup; import java.lang.ref.WeakReference; /** * The media route action provider displays a {@link MediaRouteButton media route button} * in the application's {@link ActionBar} to allow the user to select routes and * to control the currently selected route. *

* The application must specify the kinds of routes that the user should be allowed * to select by specifying the route types with the {@link #setRouteTypes} method. *

* Refer to {@link MediaRouteButton} for a description of the button that will * appear in the action bar menu. Note that instead of disabling the button * when no routes are available, the action provider will instead make the * menu item invisible. In this way, the button will only be visible when it * is possible for the user to discover and select a matching route. *

*/ public class MediaRouteActionProvider extends ActionProvider { private static final String TAG = "MediaRouteActionProvider"; private final Context mContext; private final MediaRouter mRouter; private final MediaRouterCallback mCallback; private int mRouteTypes; private MediaRouteButton mButton; private View.OnClickListener mExtendedSettingsListener; public MediaRouteActionProvider(Context context) { super(context); mContext = context; mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE); mCallback = new MediaRouterCallback(this); // Start with live audio by default. // TODO Update this when new route types are added; segment by API level // when different route types were added. setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO); } /** * Sets the types of routes that will be shown in the media route chooser dialog * launched by this button. * * @param types The route types to match. */ public void setRouteTypes(int types) { if (mRouteTypes != types) { // FIXME: We currently have no way of knowing whether the action provider // is still needed by the UI. Unfortunately this means the action provider // may leak callbacks until garbage collection occurs. This may result in // media route providers doing more work than necessary in the short term // while trying to discover routes that are no longer of interest to the // application. To solve this problem, the action provider will need some // indication from the framework that it is being destroyed. if (mRouteTypes != 0) { mRouter.removeCallback(mCallback); } mRouteTypes = types; if (types != 0) { mRouter.addCallback(types, mCallback, MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY); } refreshRoute(); if (mButton != null) { mButton.setRouteTypes(mRouteTypes); } } } public void setExtendedSettingsClickListener(View.OnClickListener listener) { mExtendedSettingsListener = listener; if (mButton != null) { mButton.setExtendedSettingsClickListener(listener); } } @Override @SuppressWarnings("deprecation") public View onCreateActionView() { throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead."); } @Override public View onCreateActionView(MenuItem item) { if (mButton != null) { Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " + "with a menu item. Don't reuse MediaRouteActionProvider instances! " + "Abandoning the old one..."); } mButton = new MediaRouteButton(mContext); mButton.setCheatSheetEnabled(true); mButton.setRouteTypes(mRouteTypes); mButton.setExtendedSettingsClickListener(mExtendedSettingsListener); mButton.setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT)); return mButton; } @Override public boolean onPerformDefaultAction() { if (mButton != null) { return mButton.showDialogInternal(); } return false; } @Override public boolean overridesItemVisibility() { return true; } @Override public boolean isVisible() { return mRouter.isRouteAvailable(mRouteTypes, MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE); } private void refreshRoute() { refreshVisibility(); } private static class MediaRouterCallback extends MediaRouter.SimpleCallback { private final WeakReference mProviderWeak; public MediaRouterCallback(MediaRouteActionProvider provider) { mProviderWeak = new WeakReference(provider); } @Override public void onRouteAdded(MediaRouter router, RouteInfo info) { refreshRoute(router); } @Override public void onRouteRemoved(MediaRouter router, RouteInfo info) { refreshRoute(router); } @Override public void onRouteChanged(MediaRouter router, RouteInfo info) { refreshRoute(router); } private void refreshRoute(MediaRouter router) { MediaRouteActionProvider provider = mProviderWeak.get(); if (provider != null) { provider.refreshRoute(); } else { router.removeCallback(this); } } } }