blob: dffa969a7148adaad2167d63406f96c833ba8295 [file] [log] [blame]
Adam Powell690ffb42012-06-04 19:22:45 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package android.app;
18
19import android.content.Context;
20import android.media.MediaRouter;
Adam Powell39d5c612012-06-16 14:25:38 -070021import android.media.MediaRouter.RouteInfo;
Adam Powell690ffb42012-06-04 19:22:45 -070022import android.util.Log;
23import android.view.ActionProvider;
24import android.view.MenuItem;
25import android.view.View;
Adam Powell8c1b02e2012-07-16 17:58:18 -070026import android.view.ViewGroup;
Adam Powell690ffb42012-06-04 19:22:45 -070027
Adam Powell39d5c612012-06-16 14:25:38 -070028import java.lang.ref.WeakReference;
29
Jeff Brown0abd3a62013-11-09 17:48:23 -080030/**
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.
34 * <p>
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.
37 * </p><p>
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.
43 * </p>
44 */
Adam Powell690ffb42012-06-04 19:22:45 -070045public class MediaRouteActionProvider extends ActionProvider {
46 private static final String TAG = "MediaRouteActionProvider";
47
Jeff Brown0abd3a62013-11-09 17:48:23 -080048 private final Context mContext;
49 private final MediaRouter mRouter;
50 private final MediaRouterCallback mCallback;
51
Adam Powell690ffb42012-06-04 19:22:45 -070052 private int mRouteTypes;
Jeff Brown0abd3a62013-11-09 17:48:23 -080053 private MediaRouteButton mButton;
Adam Powellb35c4452012-06-12 11:25:54 -070054 private View.OnClickListener mExtendedSettingsListener;
Adam Powell690ffb42012-06-04 19:22:45 -070055
56 public MediaRouteActionProvider(Context context) {
57 super(context);
Jeff Brown0abd3a62013-11-09 17:48:23 -080058
Adam Powell690ffb42012-06-04 19:22:45 -070059 mContext = context;
Adam Powellb35c4452012-06-12 11:25:54 -070060 mRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
Jeff Brown0abd3a62013-11-09 17:48:23 -080061 mCallback = new MediaRouterCallback(this);
Adam Powell690ffb42012-06-04 19:22:45 -070062
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);
67 }
68
Jeff Brown0abd3a62013-11-09 17:48:23 -080069 /**
70 * Sets the types of routes that will be shown in the media route chooser dialog
71 * launched by this button.
72 *
73 * @param types The route types to match.
74 */
Adam Powell690ffb42012-06-04 19:22:45 -070075 public void setRouteTypes(int types) {
Jeff Brown0abd3a62013-11-09 17:48:23 -080076 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);
86 }
87 mRouteTypes = types;
88 if (types != 0) {
89 mRouter.addCallback(types, mCallback,
90 MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
91 }
92 refreshRoute();
93
94 if (mButton != null) {
95 mButton.setRouteTypes(mRouteTypes);
96 }
Adam Powell39d5c612012-06-16 14:25:38 -070097 }
Jeff Brown0abd3a62013-11-09 17:48:23 -080098 }
99
100 public void setExtendedSettingsClickListener(View.OnClickListener listener) {
101 mExtendedSettingsListener = listener;
102 if (mButton != null) {
103 mButton.setExtendedSettingsClickListener(listener);
Adam Powell690ffb42012-06-04 19:22:45 -0700104 }
Adam Powell690ffb42012-06-04 19:22:45 -0700105 }
106
107 @Override
Jeff Brown0abd3a62013-11-09 17:48:23 -0800108 @SuppressWarnings("deprecation")
Adam Powell690ffb42012-06-04 19:22:45 -0700109 public View onCreateActionView() {
110 throw new UnsupportedOperationException("Use onCreateActionView(MenuItem) instead.");
111 }
112
113 @Override
114 public View onCreateActionView(MenuItem item) {
Jeff Brown0abd3a62013-11-09 17:48:23 -0800115 if (mButton != null) {
Adam Powell690ffb42012-06-04 19:22:45 -0700116 Log.e(TAG, "onCreateActionView: this ActionProvider is already associated " +
117 "with a menu item. Don't reuse MediaRouteActionProvider instances! " +
118 "Abandoning the old one...");
119 }
Jeff Brown0abd3a62013-11-09 17:48:23 -0800120
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,
Adam Powell8c1b02e2012-07-16 17:58:18 -0700127 ViewGroup.LayoutParams.MATCH_PARENT));
Jeff Brown0abd3a62013-11-09 17:48:23 -0800128 return mButton;
Adam Powell690ffb42012-06-04 19:22:45 -0700129 }
130
131 @Override
132 public boolean onPerformDefaultAction() {
Jeff Brown0abd3a62013-11-09 17:48:23 -0800133 if (mButton != null) {
134 return mButton.showDialogInternal();
Adam Powell70e11e52012-06-12 16:59:45 -0700135 }
Jeff Brown0abd3a62013-11-09 17:48:23 -0800136 return false;
Adam Powellb35c4452012-06-12 11:25:54 -0700137 }
138
Adam Powell130b4572012-06-15 19:21:34 -0700139 @Override
140 public boolean overridesItemVisibility() {
141 return true;
142 }
Adam Powell690ffb42012-06-04 19:22:45 -0700143
Adam Powell130b4572012-06-15 19:21:34 -0700144 @Override
145 public boolean isVisible() {
Jeff Brown0abd3a62013-11-09 17:48:23 -0800146 return mRouter.isRouteAvailable(mRouteTypes,
147 MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE);
Adam Powell690ffb42012-06-04 19:22:45 -0700148 }
Adam Powell39d5c612012-06-16 14:25:38 -0700149
Jeff Brown0abd3a62013-11-09 17:48:23 -0800150 private void refreshRoute() {
151 refreshVisibility();
152 }
Adam Powell39d5c612012-06-16 14:25:38 -0700153
Jeff Brown0abd3a62013-11-09 17:48:23 -0800154 private static class MediaRouterCallback extends MediaRouter.SimpleCallback {
155 private final WeakReference<MediaRouteActionProvider> mProviderWeak;
156
157 public MediaRouterCallback(MediaRouteActionProvider provider) {
158 mProviderWeak = new WeakReference<MediaRouteActionProvider>(provider);
Adam Powell39d5c612012-06-16 14:25:38 -0700159 }
160
161 @Override
162 public void onRouteAdded(MediaRouter router, RouteInfo info) {
Jeff Brown0abd3a62013-11-09 17:48:23 -0800163 refreshRoute(router);
Adam Powell39d5c612012-06-16 14:25:38 -0700164 }
165
166 @Override
167 public void onRouteRemoved(MediaRouter router, RouteInfo info) {
Jeff Brown0abd3a62013-11-09 17:48:23 -0800168 refreshRoute(router);
169 }
Adam Powell39d5c612012-06-16 14:25:38 -0700170
Jeff Brown0abd3a62013-11-09 17:48:23 -0800171 @Override
172 public void onRouteChanged(MediaRouter router, RouteInfo info) {
173 refreshRoute(router);
174 }
175
176 private void refreshRoute(MediaRouter router) {
177 MediaRouteActionProvider provider = mProviderWeak.get();
178 if (provider != null) {
179 provider.refreshRoute();
180 } else {
181 router.removeCallback(this);
182 }
Adam Powell39d5c612012-06-16 14:25:38 -0700183 }
184 }
Adam Powell690ffb42012-06-04 19:22:45 -0700185}