2 * Copyright (C) 2012 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 import android.content.Context;
20 import android.media.MediaRouter;
21 import android.media.MediaRouter.RouteInfo;
22 import android.util.Log;
23 import android.view.ActionProvider;
24 import android.view.MenuItem;
25 import android.view.View;
26 import android.view.ViewGroup;
28 import java.lang.ref.WeakReference;
31 * The media route action provider displays a {@link MediaRouteButton media route button}
32 * in the application's {@link ActionBar} to allow the user to select routes and
33 * to control the currently selected route.
35 * The application must specify the kinds of routes that the user should be allowed
36 * to select by specifying the route types with the {@link #setRouteTypes} method.
38 * Refer to {@link MediaRouteButton} for a description of the button that will
39 * appear in the action bar menu. Note that instead of disabling the button
40 * when no routes are available, the action provider will instead make the
41 * menu item invisible. In this way, the button will only be visible when it
42 * is possible for the user to discover and select a matching route.
45 public class MediaRouteActionProvider extends ActionProvider {
46 private static final String TAG = "MediaRouteActionProvider";
48 private final Context mContext;
49 private final MediaRouter mRouter;
50 private final MediaRouterCallback mCallback;
52 private int mRouteTypes;
53 private MediaRouteButton mButton;
54 private View.OnClickListener mExtendedSettingsListener;
56 public MediaRouteActionProvider(Context context) {
60 mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
61 mCallback = new MediaRouterCallback(this);
63 // Start with live audio by default.
64 // TODO Update this when new route types are added; segment by API level
65 // when different route types were added.
66 setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
70 * Sets the types of routes that will be shown in the media route chooser dialog
71 * launched by this button.
73 * @param types The route types to match.
75 public void setRouteTypes(int types) {
76 if (mRouteTypes != types) {
77 // FIXME: We currently have no way of knowing whether the action provider
78 // is still needed by the UI. Unfortunately this means the action provider
79 // may leak callbacks until garbage collection occurs. This may result in
80 // media route providers doing more work than necessary in the short term
81 // while trying to discover routes that are no longer of interest to the
82 // application. To solve this problem, the action provider will need some
83 // indication from the framework that it is being destroyed.
84 if (mRouteTypes != 0) {
85 mRouter.removeCallback(mCallback);
89 mRouter.addCallback(types, mCallback,
90 MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
94 if (mButton != null) {
95 mButton.setRouteTypes(mRouteTypes);
100 public void setExtendedSettingsClickListener(View.OnClickListener listener) {
101 mExtendedSettingsListener = listener;
102 if (mButton != null) {
103 mButton.setExtendedSettingsClickListener(listener);
108 @SuppressWarnings("deprecation")
109 public View onCreateActionView() {
110 throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
114 public View onCreateActionView(MenuItem item) {
115 if (mButton != null) {
116 Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
117 "with a menu item. Don't reuse MediaRouteActionProvider instances! " +
118 "Abandoning the old one...");
121 mButton = new MediaRouteButton(mContext);
122 mButton.setCheatSheetEnabled(true);
123 mButton.setRouteTypes(mRouteTypes);
124 mButton.setExtendedSettingsClickListener(mExtendedSettingsListener);
125 mButton.setLayoutParams(new ViewGroup.LayoutParams(
126 ViewGroup.LayoutParams.WRAP_CONTENT,
127 ViewGroup.LayoutParams.MATCH_PARENT));
132 public boolean onPerformDefaultAction() {
133 if (mButton != null) {
134 return mButton.showDialogInternal();
140 public boolean overridesItemVisibility() {
145 public boolean isVisible() {
146 return mRouter.isRouteAvailable(mRouteTypes,
147 MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
150 private void refreshRoute() {
154 private static class MediaRouterCallback extends MediaRouter.SimpleCallback {
155 private final WeakReference<MediaRouteActionProvider> mProviderWeak;
157 public MediaRouterCallback(MediaRouteActionProvider provider) {
158 mProviderWeak = new WeakReference<MediaRouteActionProvider>(provider);
162 public void onRouteAdded(MediaRouter router, RouteInfo info) {
163 refreshRoute(router);
167 public void onRouteRemoved(MediaRouter router, RouteInfo info) {
168 refreshRoute(router);
172 public void onRouteChanged(MediaRouter router, RouteInfo info) {
173 refreshRoute(router);
176 private void refreshRoute(MediaRouter router) {
177 MediaRouteActionProvider provider = mProviderWeak.get();
178 if (provider != null) {
179 provider.refreshRoute();
181 router.removeCallback(this);