Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66f3b39e authored by Jeff Brown's avatar Jeff Brown
Browse files

Add an API to allow a callback to request active scans.

This API is needed by the support library media router to ensure
that wifi display routes can be discovered while the route
chooser dialog is open.

Bug: 8175766
Change-Id: I3773773d93384aa4a3c009e71a5444ee8ce37caf
parent 77e59fef
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -12202,6 +12202,7 @@ package android.media {
  public class MediaRouter {
    method public void addCallback(int, android.media.MediaRouter.Callback);
    method public void addCallback(int, android.media.MediaRouter.Callback, int);
    method public void addUserRoute(android.media.MediaRouter.UserRouteInfo);
    method public void clearUserRoutes();
    method public android.media.MediaRouter.RouteCategory createRouteCategory(java.lang.CharSequence, boolean);
@@ -12216,6 +12217,8 @@ package android.media {
    method public void removeCallback(android.media.MediaRouter.Callback);
    method public void removeUserRoute(android.media.MediaRouter.UserRouteInfo);
    method public void selectRoute(int, android.media.MediaRouter.RouteInfo);
    field public static final int CALLBACK_FLAG_ACTIVE_SCAN = 1; // 0x1
    field public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 2; // 0x2
    field public static final int ROUTE_TYPE_LIVE_AUDIO = 1; // 0x1
    field public static final int ROUTE_TYPE_LIVE_VIDEO = 2; // 0x2
    field public static final int ROUTE_TYPE_USER = 8388608; // 0x800000
+1 −20
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
    };

    MediaRouter mRouter;
    DisplayManager mDisplayService;
    private int mRouteTypes;

    private LayoutInflater mInflater;
@@ -98,7 +97,7 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mRouter = (MediaRouter) activity.getSystemService(Context.MEDIA_ROUTER_SERVICE);
        mDisplayService = (DisplayManager) activity.getSystemService(Context.DISPLAY_SERVICE);
        mRouter.addCallback(mRouteTypes, mCallback, MediaRouter.CALLBACK_FLAG_ACTIVE_SCAN);
    }

    @Override
@@ -121,15 +120,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {

    public void setRouteTypes(int types) {
        mRouteTypes = types;
        if ((mRouteTypes & MediaRouter.ROUTE_TYPE_LIVE_VIDEO) != 0 && mDisplayService == null) {
            final Context activity = getActivity();
            if (activity != null) {
                mDisplayService = (DisplayManager) activity.getSystemService(
                        Context.DISPLAY_SERVICE);
            }
        } else {
            mDisplayService = null;
        }
    }

    void updateVolume() {
@@ -192,7 +182,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
        list.setOnItemClickListener(mAdapter);

        mListView = list;
        mRouter.addCallback(mRouteTypes, mCallback);

        mAdapter.scrollToSelectedItem();

@@ -204,14 +193,6 @@ public class MediaRouteChooserDialogFragment extends DialogFragment {
        return new RouteChooserDialog(getActivity(), getTheme());
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mDisplayService != null) {
            mDisplayService.scanWifiDisplays();
        }
    }

    private static class ViewHolder {
        public TextView text1;
        public TextView text2;
+143 −28
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@ public class MediaRouter {
    private static final String TAG = "MediaRouter";

    static class Static implements DisplayManager.DisplayListener {
        // Time between wifi display scans when actively scanning in milliseconds.
        private static final int WIFI_DISPLAY_SCAN_INTERVAL = 15000;

        final Resources mResources;
        final IAudioService mAudioService;
        final DisplayManager mDisplayService;
@@ -73,8 +76,10 @@ public class MediaRouter {
        RouteInfo mSelectedRoute;

        WifiDisplayStatus mLastKnownWifiDisplayStatus;
        boolean mActivelyScanningWifiDisplays;

        final IAudioRoutesObserver.Stub mAudioRoutesObserver = new IAudioRoutesObserver.Stub() {
            @Override
            public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
                mHandler.post(new Runnable() {
                    @Override public void run() {
@@ -84,6 +89,16 @@ public class MediaRouter {
            }
        };

        final Runnable mScanWifiDisplays = new Runnable() {
            @Override
            public void run() {
                if (mActivelyScanningWifiDisplays) {
                    mDisplayService.scanWifiDisplays();
                    mHandler.postDelayed(this, WIFI_DISPLAY_SCAN_INTERVAL);
                }
            }
        };

        Static(Context appContext) {
            mResources = Resources.getSystem();
            mHandler = new Handler(appContext.getMainLooper());
@@ -195,6 +210,32 @@ public class MediaRouter {
            }
        }

        void updateActiveScan() {
            if (hasActiveScanCallbackOfType(ROUTE_TYPE_LIVE_VIDEO)) {
                if (!mActivelyScanningWifiDisplays) {
                    mActivelyScanningWifiDisplays = true;
                    mHandler.post(mScanWifiDisplays);
                }
            } else {
                if (mActivelyScanningWifiDisplays) {
                    mActivelyScanningWifiDisplays = false;
                    mHandler.removeCallbacks(mScanWifiDisplays);
                }
            }
        }

        private boolean hasActiveScanCallbackOfType(int type) {
            final int count = mCallbacks.size();
            for (int i = 0; i < count; i++) {
                CallbackInfo cbi = mCallbacks.get(i);
                if ((cbi.flags & CALLBACK_FLAG_ACTIVE_SCAN) != 0
                        && (cbi.type & type) != 0) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public void onDisplayAdded(int displayId) {
            updatePresentationDisplays(displayId);
@@ -270,6 +311,33 @@ public class MediaRouter {
     */
    public static final int ROUTE_TYPE_USER = 0x00800000;

    /**
     * Flag for {@link #addCallback}: Actively scan for routes while this callback
     * is registered.
     * <p>
     * When this flag is specified, the media router will actively scan for new
     * routes.  Certain routes, such as wifi display routes, may not be discoverable
     * except when actively scanning.  This flag is typically used when the route picker
     * dialog has been opened by the user to ensure that the route information is
     * up to date.
     * </p><p>
     * Active scanning may consume a significant amount of power and may have intrusive
     * effects on wireless connectivity.  Therefore it is important that active scanning
     * only be requested when it is actually needed to satisfy a user request to
     * discover and select a new route.
     * </p>
     */
    public static final int CALLBACK_FLAG_ACTIVE_SCAN = 1 << 0;

    /**
     * Flag for {@link #addCallback}: Do not filter route events.
     * <p>
     * When this flag is specified, the callback will be invoked for event that affect any
     * route event if they do not match the callback's associated media route selector.
     * </p>
     */
    public static final int CALLBACK_FLAG_UNFILTERED_EVENTS = 1 << 1;

    // Maps application contexts
    static final HashMap<Context, MediaRouter> sRouters = new HashMap<Context, MediaRouter>();

@@ -343,20 +411,48 @@ public class MediaRouter {
     * Add a callback to listen to events about specific kinds of media routes.
     * If the specified callback is already registered, its registration will be updated for any
     * additional route types specified.
     * <p>
     * This is a convenience method that has the same effect as calling
     * {@link #addCallback(int, Callback, int)} without flags.
     * </p>
     *
     * @param types Types of routes this callback is interested in
     * @param cb Callback to add
     */
    public void addCallback(int types, Callback cb) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            final CallbackInfo info = sStatic.mCallbacks.get(i);
            if (info.cb == cb) {
        addCallback(types, cb, 0);
    }

    /**
     * Add a callback to listen to events about specific kinds of media routes.
     * If the specified callback is already registered, its registration will be updated for any
     * additional route types specified.
     * <p>
     * By default, the callback will only be invoked for events that affect routes
     * that match the specified selector.  The filtering may be disabled by specifying
     * the {@link #CALLBACK_FLAG_UNFILTERED_EVENTS} flag.
     * </p>
     *
     * @param types Types of routes this callback is interested in
     * @param cb Callback to add
     * @param flags Flags to control the behavior of the callback.
     * May be zero or a combination of {@link #CALLBACK_FLAG_ACTIVE_SCAN} and
     * {@link #CALLBACK_FLAG_UNFILTERED_EVENTS}.
     */
    public void addCallback(int types, Callback cb, int flags) {
        CallbackInfo info;
        int index = findCallbackInfo(cb);
        if (index >= 0) {
            info = sStatic.mCallbacks.get(index);
            info.type |= types;
                return;
            info.flags |= flags;
        } else {
            info = new CallbackInfo(cb, types, flags, this);
            sStatic.mCallbacks.add(info);
        }
        if ((info.flags & CALLBACK_FLAG_ACTIVE_SCAN) != 0) {
            sStatic.updateActiveScan();
        }
        sStatic.mCallbacks.add(new CallbackInfo(cb, types, this));
    }

    /**
@@ -365,14 +461,26 @@ public class MediaRouter {
     * @param cb Callback to remove
     */
    public void removeCallback(Callback cb) {
        int index = findCallbackInfo(cb);
        if (index >= 0) {
            CallbackInfo info = sStatic.mCallbacks.remove(index);
            if ((info.flags & CALLBACK_FLAG_ACTIVE_SCAN) != 0) {
                sStatic.updateActiveScan();
            }
        } else {
            Log.w(TAG, "removeCallback(" + cb + "): callback not registered");
        }
    }

    private int findCallbackInfo(Callback cb) {
        final int count = sStatic.mCallbacks.size();
        for (int i = 0; i < count; i++) {
            if (sStatic.mCallbacks.get(i).cb == cb) {
                sStatic.mCallbacks.remove(i);
                return;
            final CallbackInfo info = sStatic.mCallbacks.get(i);
            if (info.cb == cb) {
                return i;
            }
        }
        Log.w(TAG, "removeCallback(" + cb + "): callback not registered");
        return -1;
    }

    /**
@@ -431,12 +539,10 @@ public class MediaRouter {
        }

        if (oldRoute != null) {
            // TODO filter types properly
            dispatchRouteUnselected(types & oldRoute.getSupportedTypes(), oldRoute);
        }
        sStatic.mSelectedRoute = route;
        if (route != null) {
            // TODO filter types properly
            dispatchRouteSelected(types & route.getSupportedTypes(), route);
        }
    }
@@ -671,7 +777,7 @@ public class MediaRouter {

    static void dispatchRouteSelected(int type, RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & type) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRouteSelected(cbi.router, type, info);
            }
        }
@@ -679,7 +785,7 @@ public class MediaRouter {

    static void dispatchRouteUnselected(int type, RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & type) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRouteUnselected(cbi.router, type, info);
            }
        }
@@ -687,7 +793,7 @@ public class MediaRouter {

    static void dispatchRouteChanged(RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRouteChanged(cbi.router, info);
            }
        }
@@ -695,7 +801,7 @@ public class MediaRouter {

    static void dispatchRouteAdded(RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRouteAdded(cbi.router, info);
            }
        }
@@ -703,7 +809,7 @@ public class MediaRouter {

    static void dispatchRouteRemoved(RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRouteRemoved(cbi.router, info);
            }
        }
@@ -711,7 +817,7 @@ public class MediaRouter {

    static void dispatchRouteGrouped(RouteInfo info, RouteGroup group, int index) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & group.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(group)) {
                cbi.cb.onRouteGrouped(cbi.router, info, group, index);
            }
        }
@@ -719,7 +825,7 @@ public class MediaRouter {

    static void dispatchRouteUngrouped(RouteInfo info, RouteGroup group) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & group.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(group)) {
                cbi.cb.onRouteUngrouped(cbi.router, info, group);
            }
        }
@@ -727,7 +833,7 @@ public class MediaRouter {

    static void dispatchRouteVolumeChanged(RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRouteVolumeChanged(cbi.router, info);
            }
        }
@@ -735,7 +841,7 @@ public class MediaRouter {

    static void dispatchRoutePresentationDisplayChanged(RouteInfo info) {
        for (CallbackInfo cbi : sStatic.mCallbacks) {
            if ((cbi.type & info.mSupportedTypes) != 0) {
            if (cbi.filterRouteEvent(info)) {
                cbi.cb.onRoutePresentationDisplayChanged(cbi.router, info);
            }
        }
@@ -1892,24 +1998,33 @@ public class MediaRouter {

    static class CallbackInfo {
        public int type;
        public int flags;
        public final Callback cb;
        public final MediaRouter router;

        public CallbackInfo(Callback cb, int type, MediaRouter router) {
        public CallbackInfo(Callback cb, int type, int flags, MediaRouter router) {
            this.cb = cb;
            this.type = type;
            this.flags = flags;
            this.router = router;
        }

        public boolean filterRouteEvent(RouteInfo route) {
            return (flags & CALLBACK_FLAG_UNFILTERED_EVENTS) != 0
                    || (type & route.mSupportedTypes) != 0;
        }
    }

    /**
     * Interface for receiving events about media routing changes.
     * All methods of this interface will be called from the application's main thread.
     * <p>
     * A Callback will only receive events relevant to routes that the callback
     * was registered for unless the {@link MediaRouter#CALLBACK_FLAG_UNFILTERED_EVENTS}
     * flag was specified in {@link MediaRouter#addCallback(int, Callback, int)}.
     * </p>
     *
     * <p>A Callback will only receive events relevant to routes that the callback
     * was registered for.</p>
     *
     * @see MediaRouter#addCallback(int, Callback)
     * @see MediaRouter#addCallback(int, Callback, int)
     * @see MediaRouter#removeCallback(Callback)
     */
    public static abstract class Callback {