• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 
17 package android.support.v7.media;
18 
19 import android.content.Context;
20 import android.graphics.drawable.Drawable;
21 import android.os.Build;
22 import android.util.Log;
23 
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.util.ArrayList;
27 import java.util.List;
28 
29 final class MediaRouterJellybean {
30     private static final String TAG = "MediaRouterJellybean";
31 
32     public static final int ROUTE_TYPE_LIVE_AUDIO = 0x1;
33     public static final int ROUTE_TYPE_LIVE_VIDEO = 0x2;
34     public static final int ROUTE_TYPE_USER = 0x00800000;
35 
36     public static final int ALL_ROUTE_TYPES =
37             MediaRouterJellybean.ROUTE_TYPE_LIVE_AUDIO
38             | MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO
39             | MediaRouterJellybean.ROUTE_TYPE_USER;
40 
getMediaRouter(Context context)41     public static Object getMediaRouter(Context context) {
42         return context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
43     }
44 
45     @SuppressWarnings({ "rawtypes", "unchecked" })
getRoutes(Object routerObj)46     public static List getRoutes(Object routerObj) {
47         final android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
48         final int count = router.getRouteCount();
49         List out = new ArrayList(count);
50         for (int i = 0; i < count; i++) {
51             out.add(router.getRouteAt(i));
52         }
53         return out;
54     }
55 
56     @SuppressWarnings({ "rawtypes", "unchecked" })
getCategories(Object routerObj)57     public static List getCategories(Object routerObj) {
58         final android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
59         final int count = router.getCategoryCount();
60         List out = new ArrayList(count);
61         for (int i = 0; i < count; i++) {
62             out.add(router.getCategoryAt(i));
63         }
64         return out;
65     }
66 
getSelectedRoute(Object routerObj, int type)67     public static Object getSelectedRoute(Object routerObj, int type) {
68         return ((android.media.MediaRouter)routerObj).getSelectedRoute(type);
69     }
70 
selectRoute(Object routerObj, int types, Object routeObj)71     public static void selectRoute(Object routerObj, int types, Object routeObj) {
72         ((android.media.MediaRouter)routerObj).selectRoute(types,
73                 (android.media.MediaRouter.RouteInfo)routeObj);
74     }
75 
addCallback(Object routerObj, int types, Object callbackObj)76     public static void addCallback(Object routerObj, int types, Object callbackObj) {
77         ((android.media.MediaRouter)routerObj).addCallback(types,
78                 (android.media.MediaRouter.Callback)callbackObj);
79     }
80 
removeCallback(Object routerObj, Object callbackObj)81     public static void removeCallback(Object routerObj, Object callbackObj) {
82         ((android.media.MediaRouter)routerObj).removeCallback(
83                 (android.media.MediaRouter.Callback)callbackObj);
84     }
85 
createRouteCategory(Object routerObj, String name, boolean isGroupable)86     public static Object createRouteCategory(Object routerObj,
87             String name, boolean isGroupable) {
88         return ((android.media.MediaRouter)routerObj).createRouteCategory(name, isGroupable);
89     }
90 
createUserRoute(Object routerObj, Object categoryObj)91     public static Object createUserRoute(Object routerObj, Object categoryObj) {
92         return ((android.media.MediaRouter)routerObj).createUserRoute(
93                 (android.media.MediaRouter.RouteCategory)categoryObj);
94     }
95 
addUserRoute(Object routerObj, Object routeObj)96     public static void addUserRoute(Object routerObj, Object routeObj) {
97         ((android.media.MediaRouter)routerObj).addUserRoute(
98                 (android.media.MediaRouter.UserRouteInfo)routeObj);
99     }
100 
removeUserRoute(Object routerObj, Object routeObj)101     public static void removeUserRoute(Object routerObj, Object routeObj) {
102         ((android.media.MediaRouter)routerObj).removeUserRoute(
103                 (android.media.MediaRouter.UserRouteInfo)routeObj);
104     }
105 
createCallback(Callback callback)106     public static Object createCallback(Callback callback) {
107         return new CallbackProxy<Callback>(callback);
108     }
109 
createVolumeCallback(VolumeCallback callback)110     public static Object createVolumeCallback(VolumeCallback callback) {
111         return new VolumeCallbackProxy<VolumeCallback>(callback);
112     }
113 
114     public static final class RouteInfo {
getName(Object routeObj, Context context)115         public static CharSequence getName(Object routeObj, Context context) {
116             return ((android.media.MediaRouter.RouteInfo)routeObj).getName(context);
117         }
118 
getStatus(Object routeObj)119         public static CharSequence getStatus(Object routeObj) {
120             return ((android.media.MediaRouter.RouteInfo)routeObj).getStatus();
121         }
122 
getSupportedTypes(Object routeObj)123         public static int getSupportedTypes(Object routeObj) {
124             return ((android.media.MediaRouter.RouteInfo)routeObj).getSupportedTypes();
125         }
126 
getCategory(Object routeObj)127         public static Object getCategory(Object routeObj) {
128             return ((android.media.MediaRouter.RouteInfo)routeObj).getCategory();
129         }
130 
getIconDrawable(Object routeObj)131         public static Drawable getIconDrawable(Object routeObj) {
132             return ((android.media.MediaRouter.RouteInfo)routeObj).getIconDrawable();
133         }
134 
getPlaybackType(Object routeObj)135         public static int getPlaybackType(Object routeObj) {
136             return ((android.media.MediaRouter.RouteInfo)routeObj).getPlaybackType();
137         }
138 
getPlaybackStream(Object routeObj)139         public static int getPlaybackStream(Object routeObj) {
140             return ((android.media.MediaRouter.RouteInfo)routeObj).getPlaybackStream();
141         }
142 
getVolume(Object routeObj)143         public static int getVolume(Object routeObj) {
144             return ((android.media.MediaRouter.RouteInfo)routeObj).getVolume();
145         }
146 
getVolumeMax(Object routeObj)147         public static int getVolumeMax(Object routeObj) {
148             return ((android.media.MediaRouter.RouteInfo)routeObj).getVolumeMax();
149         }
150 
getVolumeHandling(Object routeObj)151         public static int getVolumeHandling(Object routeObj) {
152             return ((android.media.MediaRouter.RouteInfo)routeObj).getVolumeHandling();
153         }
154 
getTag(Object routeObj)155         public static Object getTag(Object routeObj) {
156             return ((android.media.MediaRouter.RouteInfo)routeObj).getTag();
157         }
158 
setTag(Object routeObj, Object tag)159         public static void setTag(Object routeObj, Object tag) {
160             ((android.media.MediaRouter.RouteInfo)routeObj).setTag(tag);
161         }
162 
requestSetVolume(Object routeObj, int volume)163         public static void requestSetVolume(Object routeObj, int volume) {
164             ((android.media.MediaRouter.RouteInfo)routeObj).requestSetVolume(volume);
165         }
166 
requestUpdateVolume(Object routeObj, int direction)167         public static void requestUpdateVolume(Object routeObj, int direction) {
168             ((android.media.MediaRouter.RouteInfo)routeObj).requestUpdateVolume(direction);
169         }
170 
getGroup(Object routeObj)171         public static Object getGroup(Object routeObj) {
172             return ((android.media.MediaRouter.RouteInfo)routeObj).getGroup();
173         }
174 
isGroup(Object routeObj)175         public static boolean isGroup(Object routeObj) {
176             return routeObj instanceof android.media.MediaRouter.RouteGroup;
177         }
178     }
179 
180     public static final class RouteGroup {
181         @SuppressWarnings({ "rawtypes", "unchecked" })
getGroupedRoutes(Object groupObj)182         public static List getGroupedRoutes(Object groupObj) {
183             final android.media.MediaRouter.RouteGroup group =
184                     (android.media.MediaRouter.RouteGroup)groupObj;
185             final int count = group.getRouteCount();
186             List out = new ArrayList(count);
187             for (int i = 0; i < count; i++) {
188                 out.add(group.getRouteAt(i));
189             }
190             return out;
191         }
192     }
193 
194     public static final class UserRouteInfo {
setName(Object routeObj, CharSequence name)195         public static void setName(Object routeObj, CharSequence name) {
196             ((android.media.MediaRouter.UserRouteInfo)routeObj).setName(name);
197         }
198 
setStatus(Object routeObj, CharSequence status)199         public static void setStatus(Object routeObj, CharSequence status) {
200             ((android.media.MediaRouter.UserRouteInfo)routeObj).setStatus(status);
201         }
202 
setIconDrawable(Object routeObj, Drawable icon)203         public static void setIconDrawable(Object routeObj, Drawable icon) {
204             ((android.media.MediaRouter.UserRouteInfo)routeObj).setIconDrawable(icon);
205         }
206 
setPlaybackType(Object routeObj, int type)207         public static void setPlaybackType(Object routeObj, int type) {
208             ((android.media.MediaRouter.UserRouteInfo)routeObj).setPlaybackType(type);
209         }
210 
setPlaybackStream(Object routeObj, int stream)211         public static void setPlaybackStream(Object routeObj, int stream) {
212             ((android.media.MediaRouter.UserRouteInfo)routeObj).setPlaybackStream(stream);
213         }
214 
setVolume(Object routeObj, int volume)215         public static void setVolume(Object routeObj, int volume) {
216             ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolume(volume);
217         }
218 
setVolumeMax(Object routeObj, int volumeMax)219         public static void setVolumeMax(Object routeObj, int volumeMax) {
220             ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolumeMax(volumeMax);
221         }
222 
setVolumeHandling(Object routeObj, int volumeHandling)223         public static void setVolumeHandling(Object routeObj, int volumeHandling) {
224             ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolumeHandling(volumeHandling);
225         }
226 
setVolumeCallback(Object routeObj, Object volumeCallbackObj)227         public static void setVolumeCallback(Object routeObj, Object volumeCallbackObj) {
228             ((android.media.MediaRouter.UserRouteInfo)routeObj).setVolumeCallback(
229                     (android.media.MediaRouter.VolumeCallback)volumeCallbackObj);
230         }
231 
setRemoteControlClient(Object routeObj, Object rccObj)232         public static void setRemoteControlClient(Object routeObj, Object rccObj) {
233             ((android.media.MediaRouter.UserRouteInfo)routeObj).setRemoteControlClient(
234                     (android.media.RemoteControlClient)rccObj);
235         }
236     }
237 
238     public static final class RouteCategory {
getName(Object categoryObj, Context context)239         public static CharSequence getName(Object categoryObj, Context context) {
240             return ((android.media.MediaRouter.RouteCategory)categoryObj).getName(context);
241         }
242 
243         @SuppressWarnings({ "rawtypes", "unchecked" })
getRoutes(Object categoryObj)244         public static List getRoutes(Object categoryObj) {
245             ArrayList out = new ArrayList();
246             ((android.media.MediaRouter.RouteCategory)categoryObj).getRoutes(out);
247             return out;
248         }
249 
getSupportedTypes(Object categoryObj)250         public static int getSupportedTypes(Object categoryObj) {
251             return ((android.media.MediaRouter.RouteCategory)categoryObj).getSupportedTypes();
252         }
253 
isGroupable(Object categoryObj)254         public static boolean isGroupable(Object categoryObj) {
255             return ((android.media.MediaRouter.RouteCategory)categoryObj).isGroupable();
256         }
257     }
258 
259     public static interface Callback {
onRouteSelected(int type, Object routeObj)260         public void onRouteSelected(int type, Object routeObj);
onRouteUnselected(int type, Object routeObj)261         public void onRouteUnselected(int type, Object routeObj);
onRouteAdded(Object routeObj)262         public void onRouteAdded(Object routeObj);
onRouteRemoved(Object routeObj)263         public void onRouteRemoved(Object routeObj);
onRouteChanged(Object routeObj)264         public void onRouteChanged(Object routeObj);
onRouteGrouped(Object routeObj, Object groupObj, int index)265         public void onRouteGrouped(Object routeObj, Object groupObj, int index);
onRouteUngrouped(Object routeObj, Object groupObj)266         public void onRouteUngrouped(Object routeObj, Object groupObj);
onRouteVolumeChanged(Object routeObj)267         public void onRouteVolumeChanged(Object routeObj);
268     }
269 
270     public static interface VolumeCallback {
onVolumeSetRequest(Object routeObj, int volume)271         public void onVolumeSetRequest(Object routeObj, int volume);
onVolumeUpdateRequest(Object routeObj, int direction)272         public void onVolumeUpdateRequest(Object routeObj, int direction);
273     }
274 
275     /**
276      * Workaround for limitations of selectRoute() on JB and JB MR1.
277      * Do not use on JB MR2 and above.
278      */
279     public static final class SelectRouteWorkaround {
280         private Method mSelectRouteIntMethod;
281 
SelectRouteWorkaround()282         public SelectRouteWorkaround() {
283             if (Build.VERSION.SDK_INT < 16 || Build.VERSION.SDK_INT > 17) {
284                 throw new UnsupportedOperationException();
285             }
286             try {
287                 mSelectRouteIntMethod = android.media.MediaRouter.class.getMethod(
288                         "selectRouteInt", int.class, android.media.MediaRouter.RouteInfo.class);
289             } catch (NoSuchMethodException ex) {
290             }
291         }
292 
selectRoute(Object routerObj, int types, Object routeObj)293         public void selectRoute(Object routerObj, int types, Object routeObj) {
294             android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
295             android.media.MediaRouter.RouteInfo route =
296                     (android.media.MediaRouter.RouteInfo)routeObj;
297 
298             int routeTypes = route.getSupportedTypes();
299             if ((routeTypes & ROUTE_TYPE_USER) == 0) {
300                 // Handle non-user routes.
301                 // On JB and JB MR1, the selectRoute() API only supports programmatically
302                 // selecting user routes.  So instead we rely on the hidden selectRouteInt()
303                 // method on these versions of the platform.
304                 // This limitation was removed in JB MR2.
305                 if (mSelectRouteIntMethod != null) {
306                     try {
307                         mSelectRouteIntMethod.invoke(router, types, route);
308                         return; // success!
309                     } catch (IllegalAccessException ex) {
310                         Log.w(TAG, "Cannot programmatically select non-user route.  "
311                                 + "Media routing may not work.", ex);
312                     } catch (InvocationTargetException ex) {
313                         Log.w(TAG, "Cannot programmatically select non-user route.  "
314                                 + "Media routing may not work.", ex);
315                     }
316                 } else {
317                     Log.w(TAG, "Cannot programmatically select non-user route "
318                             + "because the platform is missing the selectRouteInt() "
319                             + "method.  Media routing may not work.");
320                 }
321             }
322 
323             // Default handling.
324             router.selectRoute(types, route);
325         }
326     }
327 
328     /**
329      * Workaround the fact that the getDefaultRoute() method does not exist in JB and JB MR1.
330      * Do not use on JB MR2 and above.
331      */
332     public static final class GetDefaultRouteWorkaround {
333         private Method mGetSystemAudioRouteMethod;
334 
GetDefaultRouteWorkaround()335         public GetDefaultRouteWorkaround() {
336             if (Build.VERSION.SDK_INT < 16 || Build.VERSION.SDK_INT > 17) {
337                 throw new UnsupportedOperationException();
338             }
339             try {
340                 mGetSystemAudioRouteMethod =
341                         android.media.MediaRouter.class.getMethod("getSystemAudioRoute");
342             } catch (NoSuchMethodException ex) {
343             }
344         }
345 
getDefaultRoute(Object routerObj)346         public Object getDefaultRoute(Object routerObj) {
347             android.media.MediaRouter router = (android.media.MediaRouter)routerObj;
348 
349             if (mGetSystemAudioRouteMethod != null) {
350                 try {
351                     return mGetSystemAudioRouteMethod.invoke(router);
352                 } catch (IllegalAccessException ex) {
353                 } catch (InvocationTargetException ex) {
354                 }
355             }
356 
357             // Could not find the method or it does not work.
358             // Return the first route and hope for the best.
359             return router.getRouteAt(0);
360         }
361     }
362 
363     static class CallbackProxy<T extends Callback>
364             extends android.media.MediaRouter.Callback {
365         protected final T mCallback;
366 
CallbackProxy(T callback)367         public CallbackProxy(T callback) {
368             mCallback = callback;
369         }
370 
371         @Override
onRouteSelected(android.media.MediaRouter router, int type, android.media.MediaRouter.RouteInfo route)372         public void onRouteSelected(android.media.MediaRouter router,
373                 int type, android.media.MediaRouter.RouteInfo route) {
374             mCallback.onRouteSelected(type, route);
375         }
376 
377         @Override
onRouteUnselected(android.media.MediaRouter router, int type, android.media.MediaRouter.RouteInfo route)378         public void onRouteUnselected(android.media.MediaRouter router,
379                 int type, android.media.MediaRouter.RouteInfo route) {
380             mCallback.onRouteUnselected(type, route);
381         }
382 
383         @Override
onRouteAdded(android.media.MediaRouter router, android.media.MediaRouter.RouteInfo route)384         public void onRouteAdded(android.media.MediaRouter router,
385                 android.media.MediaRouter.RouteInfo route) {
386             mCallback.onRouteAdded(route);
387         }
388 
389         @Override
onRouteRemoved(android.media.MediaRouter router, android.media.MediaRouter.RouteInfo route)390         public void onRouteRemoved(android.media.MediaRouter router,
391                 android.media.MediaRouter.RouteInfo route) {
392             mCallback.onRouteRemoved(route);
393         }
394 
395         @Override
onRouteChanged(android.media.MediaRouter router, android.media.MediaRouter.RouteInfo route)396         public void onRouteChanged(android.media.MediaRouter router,
397                 android.media.MediaRouter.RouteInfo route) {
398             mCallback.onRouteChanged(route);
399         }
400 
401         @Override
onRouteGrouped(android.media.MediaRouter router, android.media.MediaRouter.RouteInfo route, android.media.MediaRouter.RouteGroup group, int index)402         public void onRouteGrouped(android.media.MediaRouter router,
403                 android.media.MediaRouter.RouteInfo route,
404                 android.media.MediaRouter.RouteGroup group, int index) {
405             mCallback.onRouteGrouped(route, group, index);
406         }
407 
408         @Override
onRouteUngrouped(android.media.MediaRouter router, android.media.MediaRouter.RouteInfo route, android.media.MediaRouter.RouteGroup group)409         public void onRouteUngrouped(android.media.MediaRouter router,
410                 android.media.MediaRouter.RouteInfo route,
411                 android.media.MediaRouter.RouteGroup group) {
412             mCallback.onRouteUngrouped(route, group);
413         }
414 
415         @Override
onRouteVolumeChanged(android.media.MediaRouter router, android.media.MediaRouter.RouteInfo route)416         public void onRouteVolumeChanged(android.media.MediaRouter router,
417                 android.media.MediaRouter.RouteInfo route) {
418             mCallback.onRouteVolumeChanged(route);
419         }
420     }
421 
422     static class VolumeCallbackProxy<T extends VolumeCallback>
423             extends android.media.MediaRouter.VolumeCallback {
424         protected final T mCallback;
425 
VolumeCallbackProxy(T callback)426         public VolumeCallbackProxy(T callback) {
427             mCallback = callback;
428         }
429 
430         @Override
onVolumeSetRequest(android.media.MediaRouter.RouteInfo route, int volume)431         public void onVolumeSetRequest(android.media.MediaRouter.RouteInfo route,
432                 int volume) {
433             mCallback.onVolumeSetRequest(route, volume);
434         }
435 
436         @Override
onVolumeUpdateRequest(android.media.MediaRouter.RouteInfo route, int direction)437         public void onVolumeUpdateRequest(android.media.MediaRouter.RouteInfo route,
438                 int direction) {
439             mCallback.onVolumeUpdateRequest(route, direction);
440         }
441     }
442 }
443