Home | History | Annotate | Download | only in media
      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.hardware.display.DisplayManager;
     21 import android.os.Build;
     22 import android.os.Handler;
     23 import android.util.Log;
     24 import android.view.Display;
     25 
     26 import java.lang.reflect.Field;
     27 import java.lang.reflect.InvocationTargetException;
     28 import java.lang.reflect.Method;
     29 
     30 final class MediaRouterJellybeanMr1 {
     31     private static final String TAG = "MediaRouterJellybeanMr1";
     32 
     33     public static Object createCallback(Callback callback) {
     34         return new CallbackProxy<Callback>(callback);
     35     }
     36 
     37     public static final class RouteInfo {
     38         public static boolean isEnabled(Object routeObj) {
     39             return ((android.media.MediaRouter.RouteInfo)routeObj).isEnabled();
     40         }
     41 
     42         public static Display getPresentationDisplay(Object routeObj) {
     43             return ((android.media.MediaRouter.RouteInfo)routeObj).getPresentationDisplay();
     44         }
     45     }
     46 
     47     public static interface Callback extends MediaRouterJellybean.Callback {
     48         public void onRoutePresentationDisplayChanged(Object routeObj);
     49     }
     50 
     51     /**
     52      * Workaround the fact that the version of MediaRouter.addCallback() that accepts a
     53      * flag to perform an active scan does not exist in JB MR1 so we need to force
     54      * wifi display scans directly through the DisplayManager.
     55      * Do not use on JB MR2 and above.
     56      */
     57     public static final class ActiveScanWorkaround implements Runnable {
     58         // Time between wifi display scans when actively scanning in milliseconds.
     59         private static final int WIFI_DISPLAY_SCAN_INTERVAL = 15000;
     60 
     61         private final DisplayManager mDisplayManager;
     62         private final Handler mHandler;
     63         private Method mScanWifiDisplaysMethod;
     64 
     65         private boolean mActivelyScanningWifiDisplays;
     66 
     67         public ActiveScanWorkaround(Context context, Handler handler) {
     68             if (Build.VERSION.SDK_INT != 17) {
     69                 throw new UnsupportedOperationException();
     70             }
     71 
     72             mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
     73             mHandler = handler;
     74             try {
     75                 mScanWifiDisplaysMethod = DisplayManager.class.getMethod("scanWifiDisplays");
     76             } catch (NoSuchMethodException ex) {
     77             }
     78         }
     79 
     80         public void setActiveScanRouteTypes(int routeTypes) {
     81             // On JB MR1, there is no API to scan wifi display routes.
     82             // Instead we must make a direct call into the DisplayManager to scan
     83             // wifi displays on this version but only when live video routes are requested.
     84             // See also the JellybeanMr2Impl implementation of this method.
     85             // This was fixed in JB MR2 by adding a new overload of addCallback() to
     86             // enable active scanning on request.
     87             if ((routeTypes & MediaRouterJellybean.ROUTE_TYPE_LIVE_VIDEO) != 0) {
     88                 if (!mActivelyScanningWifiDisplays) {
     89                     if (mScanWifiDisplaysMethod != null) {
     90                         mActivelyScanningWifiDisplays = true;
     91                         mHandler.post(this);
     92                     } else {
     93                         Log.w(TAG, "Cannot scan for wifi displays because the "
     94                                 + "DisplayManager.scanWifiDisplays() method is "
     95                                 + "not available on this device.");
     96                     }
     97                 }
     98             } else {
     99                 if (mActivelyScanningWifiDisplays) {
    100                     mActivelyScanningWifiDisplays = false;
    101                     mHandler.removeCallbacks(this);
    102                 }
    103             }
    104         }
    105 
    106         @Override
    107         public void run() {
    108             if (mActivelyScanningWifiDisplays) {
    109                 try {
    110                     mScanWifiDisplaysMethod.invoke(mDisplayManager);
    111                 } catch (IllegalAccessException ex) {
    112                     Log.w(TAG, "Cannot scan for wifi displays.", ex);
    113                 } catch (InvocationTargetException ex) {
    114                     Log.w(TAG, "Cannot scan for wifi displays.", ex);
    115                 }
    116                 mHandler.postDelayed(this, WIFI_DISPLAY_SCAN_INTERVAL);
    117             }
    118         }
    119     }
    120 
    121     /**
    122      * Workaround the fact that the isConnecting() method does not exist in JB MR1.
    123      * Do not use on JB MR2 and above.
    124      */
    125     public static final class IsConnectingWorkaround {
    126         private Method mGetStatusCodeMethod;
    127         private int mStatusConnecting;
    128 
    129         public IsConnectingWorkaround() {
    130             if (Build.VERSION.SDK_INT != 17) {
    131                 throw new UnsupportedOperationException();
    132             }
    133 
    134             try {
    135                 Field statusConnectingField =
    136                         android.media.MediaRouter.RouteInfo.class.getField("STATUS_CONNECTING");
    137                 mStatusConnecting = statusConnectingField.getInt(null);
    138                 mGetStatusCodeMethod =
    139                         android.media.MediaRouter.RouteInfo.class.getMethod("getStatusCode");
    140             } catch (NoSuchFieldException ex) {
    141             } catch (NoSuchMethodException ex) {
    142             } catch (IllegalAccessException ex) {
    143             }
    144         }
    145 
    146         public boolean isConnecting(Object routeObj) {
    147             android.media.MediaRouter.RouteInfo route =
    148                     (android.media.MediaRouter.RouteInfo)routeObj;
    149 
    150             if (mGetStatusCodeMethod != null) {
    151                 try {
    152                     int statusCode = (Integer)mGetStatusCodeMethod.invoke(route);
    153                     return statusCode == mStatusConnecting;
    154                 } catch (IllegalAccessException ex) {
    155                 } catch (InvocationTargetException ex) {
    156                 }
    157             }
    158 
    159             // Assume not connecting.
    160             return false;
    161         }
    162     }
    163 
    164     static class CallbackProxy<T extends Callback>
    165             extends MediaRouterJellybean.CallbackProxy<T> {
    166         public CallbackProxy(T callback) {
    167             super(callback);
    168         }
    169 
    170         @Override
    171         public void onRoutePresentationDisplayChanged(android.media.MediaRouter router,
    172                 android.media.MediaRouter.RouteInfo route) {
    173             mCallback.onRoutePresentationDisplayChanged(route);
    174         }
    175     }
    176 }
    177