MediaRouteButton.java revision 0abd3a6ce83ed23abe614155e776b600ef2a66c3
1690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell/*
2690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Copyright (C) 2012 The Android Open Source Project
3690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *
4690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
5690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * you may not use this file except in compliance with the License.
6690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * You may obtain a copy of the License at
7690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *
8690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
9690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell *
10690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * Unless required by applicable law or agreed to in writing, software
11690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
12690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * See the License for the specific language governing permissions and
14690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell * limitations under the License.
15690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell */
16690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
17690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellpackage android.app;
18690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
19690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport com.android.internal.R;
200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brownimport com.android.internal.app.MediaRouteDialogPresenter;
21690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
22690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.content.Context;
2370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powellimport android.content.ContextWrapper;
24690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.content.res.TypedArray;
25690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.graphics.Canvas;
26e4681878702edaf0833294b3f1ce835705d3ad04Adam Powellimport android.graphics.Rect;
27690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.graphics.drawable.Drawable;
28690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.media.MediaRouter;
29f7e0a328c939fa61792d4b685e8f9047a3a0ad90Adam Powellimport android.media.MediaRouter.RouteGroup;
30690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.media.MediaRouter.RouteInfo;
31e4681878702edaf0833294b3f1ce835705d3ad04Adam Powellimport android.text.TextUtils;
32690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.util.AttributeSet;
33e4681878702edaf0833294b3f1ce835705d3ad04Adam Powellimport android.view.Gravity;
34e4681878702edaf0833294b3f1ce835705d3ad04Adam Powellimport android.view.HapticFeedbackConstants;
35690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.view.SoundEffectConstants;
36690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellimport android.view.View;
37e4681878702edaf0833294b3f1ce835705d3ad04Adam Powellimport android.widget.Toast;
38690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
39690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powellpublic class MediaRouteButton extends View {
400abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private final MediaRouter mRouter;
410abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private final MediaRouterCallback mCallback;
42690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
43690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private int mRouteTypes;
44690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
45101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    private boolean mAttachedToWindow;
46101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich
47690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private Drawable mRemoteIndicator;
48690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private boolean mRemoteActive;
49e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    private boolean mCheatSheetEnabled;
502ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell    private boolean mIsConnecting;
51690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
52690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private int mMinWidth;
53690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private int mMinHeight;
54690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
55b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell    private OnClickListener mExtendedSettingsClickListener;
56b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell
570abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    // The checked state is used when connected to a remote route.
582ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell    private static final int[] CHECKED_STATE_SET = {
592ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        R.attr.state_checked
602ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell    };
612ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell
620abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    // The activated state is used while connecting to a remote route.
63690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    private static final int[] ACTIVATED_STATE_SET = {
64690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        R.attr.state_activated
65690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    };
66690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
67690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public MediaRouteButton(Context context) {
68690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        this(context, null);
69690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
70690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
71690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public MediaRouteButton(Context context, AttributeSet attrs) {
7274d762a3ee7dd66fe9ce44f3232159811af8d5d8Adam Powell        this(context, attrs, com.android.internal.R.attr.mediaRouteButtonStyle);
73690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
74690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
75690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
76690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super(context, attrs, defStyleAttr);
77690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
78b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn        mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mCallback = new MediaRouterCallback();
80690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
81690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        TypedArray a = context.obtainStyledAttributes(attrs,
82690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton, defStyleAttr, 0);
83690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        setRemoteIndicatorDrawable(a.getDrawable(
84690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton_externalRouteEnabledDrawable));
85690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mMinWidth = a.getDimensionPixelSize(
86690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton_minWidth, 0);
87690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mMinHeight = a.getDimensionPixelSize(
88690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton_minHeight, 0);
89849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell        final int routeTypes = a.getInteger(
90849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell                com.android.internal.R.styleable.MediaRouteButton_mediaRouteTypes,
91849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell                MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
92690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        a.recycle();
93690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
94690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        setClickable(true);
95e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        setLongClickable(true);
96849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell
97849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell        setRouteTypes(routeTypes);
98690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
99690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Gets the media route types for filtering the routes that the user can
1020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * select using the media route chooser dialog.
1030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     *
1040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * @return The route types.
1050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
1060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public int getRouteTypes() {
1070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        return mRouteTypes;
1080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Sets the types of routes that will be shown in the media route chooser dialog
1120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * launched by this button.
1130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     *
1140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * @param types The route types to match.
1150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
1160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public void setRouteTypes(int types) {
1170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mRouteTypes != types) {
1180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mAttachedToWindow && mRouteTypes != 0) {
1190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRouter.removeCallback(mCallback);
1200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
1210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRouteTypes = types;
1230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1240abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mAttachedToWindow && types != 0) {
1250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRouter.addCallback(types, mCallback,
1260abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                        MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
1270abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
1280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1290abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
130690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
1310abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
132690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1330abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public void setExtendedSettingsClickListener(OnClickListener listener) {
1340abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mExtendedSettingsClickListener = listener;
135690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
136690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1370abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1380abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Show the route chooser or controller dialog.
1390abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * <p>
1400abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * If the default route is selected or if the currently selected route does
1410abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * not match the {@link #getRouteTypes route types}, then shows the route chooser dialog.
1420abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Otherwise, shows the route controller dialog to offer the user
1430abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * a choice to disconnect from the route or perform other control actions
1440abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * such as setting the route's volume.
1450abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * </p><p>
1460abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * This will attach a {@link DialogFragment} to the containing Activity.
1470abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * </p>
1480abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
1490abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public void showDialog() {
1500abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        showDialogInternal();
1510abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1520abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1530abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    boolean showDialogInternal() {
1540abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (!mAttachedToWindow) {
1550abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            return false;
156690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
157690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1580abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        DialogFragment f = MediaRouteDialogPresenter.showDialogFragment(getActivity(),
1590abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRouteTypes, mExtendedSettingsClickListener);
1600abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        return f != null;
1610abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1620abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1630abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private Activity getActivity() {
1640abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        // Gross way of unwrapping the Activity so we can get the FragmentManager
1650abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        Context context = getContext();
1660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        while (context instanceof ContextWrapper) {
1670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (context instanceof Activity) {
1680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                return (Activity)context;
169690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            }
1700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            context = ((ContextWrapper)context).getBaseContext();
171690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
1720abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        throw new IllegalStateException("The MediaRouteButton's Context is not an Activity.");
173690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
174690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1750abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1760abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Sets whether to enable showing a toast with the content descriptor of the
1770abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * button when the button is long pressed.
1780abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
179e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    void setCheatSheetEnabled(boolean enable) {
180e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        mCheatSheetEnabled = enable;
181e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    }
182e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
183e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    @Override
1840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public boolean performClick() {
1850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        // Send the appropriate accessibility events and call listeners
1860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        boolean handled = super.performClick();
1870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (!handled) {
1880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            playSoundEffect(SoundEffectConstants.CLICK);
1890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
1900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        return showDialogInternal() || handled;
1910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    @Override
194e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    public boolean performLongClick() {
195e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (super.performLongClick()) {
196e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            return true;
197e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
198e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
199e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (!mCheatSheetEnabled) {
200e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            return false;
201e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
202e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
203e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final CharSequence contentDesc = getContentDescription();
204e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (TextUtils.isEmpty(contentDesc)) {
205e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            // Don't show the cheat sheet if we have no description
206e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            return false;
207e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
208e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
209e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int[] screenPos = new int[2];
210e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final Rect displayFrame = new Rect();
211e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        getLocationOnScreen(screenPos);
212e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        getWindowVisibleDisplayFrame(displayFrame);
213e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
214e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final Context context = getContext();
215e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int width = getWidth();
216e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int height = getHeight();
217e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int midy = screenPos[1] + height / 2;
218e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
219e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
220e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        Toast cheatSheet = Toast.makeText(context, contentDesc, Toast.LENGTH_SHORT);
221e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (midy < displayFrame.height()) {
222e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            // Show along the top; follow action buttons
223e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            cheatSheet.setGravity(Gravity.TOP | Gravity.END,
224e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell                    screenWidth - screenPos[0] - width / 2, height);
225e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        } else {
226e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            // Show along the bottom center
227e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
228e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
229e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        cheatSheet.show();
230e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
231e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        return true;
232e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    }
233e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
234690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
235690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected int[] onCreateDrawableState(int extraSpace) {
236690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
2372ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell
2382ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // Technically we should be handling this more completely, but these
2392ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // are implementation details here. Checked is used to express the connecting
2402ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // drawable state and it's mutually exclusive with activated for the purposes
2412ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // of state selection here.
2422ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        if (mIsConnecting) {
2432ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
2442ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        } else if (mRemoteActive) {
245690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mergeDrawableStates(drawableState, ACTIVATED_STATE_SET);
246690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
247690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        return drawableState;
248690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
249690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
250690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
251690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected void drawableStateChanged() {
252690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.drawableStateChanged();
253690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
254690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mRemoteIndicator != null) {
255690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            int[] myDrawableState = getDrawableState();
256690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mRemoteIndicator.setState(myDrawableState);
257690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            invalidate();
258690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
259690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
260690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
2610abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private void setRemoteIndicatorDrawable(Drawable d) {
2620abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mRemoteIndicator != null) {
2630abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRemoteIndicator.setCallback(null);
2640abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            unscheduleDrawable(mRemoteIndicator);
2650abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
2660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mRemoteIndicator = d;
2670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (d != null) {
2680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            d.setCallback(this);
2690abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            d.setState(getDrawableState());
2700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            d.setVisible(getVisibility() == VISIBLE, false);
2710abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
2720abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
2730abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        refreshDrawableState();
2740abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
2750abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
276690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
277690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected boolean verifyDrawable(Drawable who) {
278690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        return super.verifyDrawable(who) || who == mRemoteIndicator;
279690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
280690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
281690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
282690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public void jumpDrawablesToCurrentState() {
283690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.jumpDrawablesToCurrentState();
2840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
2850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mRemoteIndicator != null) {
2860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRemoteIndicator.jumpToCurrentState();
2870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
288690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
289690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
290690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
291690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public void setVisibility(int visibility) {
292690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.setVisibility(visibility);
2930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
294690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mRemoteIndicator != null) {
295690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
296690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
297690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
298690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
299690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
300101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    public void onAttachedToWindow() {
301101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        super.onAttachedToWindow();
3020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
303101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        mAttachedToWindow = true;
304101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        if (mRouteTypes != 0) {
3050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRouter.addCallback(mRouteTypes, mCallback,
30669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
307101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        }
3080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        refreshRoute();
309101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    }
310101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich
311101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    @Override
312101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    public void onDetachedFromWindow() {
3130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mAttachedToWindow = false;
314101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        if (mRouteTypes != 0) {
3150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRouter.removeCallback(mCallback);
316101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        }
3170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
318101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        super.onDetachedFromWindow();
319101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    }
320101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich
321101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    @Override
322690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
323690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
324690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
325690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
326690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
327690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
328690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int minWidth = Math.max(mMinWidth,
329690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicWidth() : 0);
330690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int minHeight = Math.max(mMinHeight,
331690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicHeight() : 0);
332690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
333690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        int width;
334690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        switch (widthMode) {
335690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.EXACTLY:
336690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                width = widthSize;
337690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
338690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.AT_MOST:
339690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                width = Math.min(widthSize, minWidth + getPaddingLeft() + getPaddingRight());
340690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
341690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            default:
342690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.UNSPECIFIED:
343690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                width = minWidth + getPaddingLeft() + getPaddingRight();
344690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
345690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
346690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
347690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        int height;
348690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        switch (heightMode) {
349690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.EXACTLY:
350690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                height = heightSize;
351690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
352690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.AT_MOST:
353690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                height = Math.min(heightSize, minHeight + getPaddingTop() + getPaddingBottom());
354690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
355690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            default:
356690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.UNSPECIFIED:
357690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                height = minHeight + getPaddingTop() + getPaddingBottom();
358690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
359690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
360690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
361690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        setMeasuredDimension(width, height);
362690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
363690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
364690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
365690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected void onDraw(Canvas canvas) {
366690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.onDraw(canvas);
367690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
368690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mRemoteIndicator == null) return;
369690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
370690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int left = getPaddingLeft();
371690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int right = getWidth() - getPaddingRight();
372690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int top = getPaddingTop();
373690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int bottom = getHeight() - getPaddingBottom();
374690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
375690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
376690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
377690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawLeft = left + (right - left - drawWidth) / 2;
378690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawTop = top + (bottom - top - drawHeight) / 2;
379690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
3800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mRemoteIndicator.setBounds(drawLeft, drawTop,
3810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                drawLeft + drawWidth, drawTop + drawHeight);
382690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mRemoteIndicator.draw(canvas);
383690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
384690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
3850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private void refreshRoute() {
3860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mAttachedToWindow) {
3870abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
3880abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            final boolean isRemote = !route.isDefault() && route.matchesTypes(mRouteTypes);
3890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            final boolean isConnecting = isRemote && route.isConnecting();
3900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
3910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            boolean needsRefresh = false;
3920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mRemoteActive != isRemote) {
3930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRemoteActive = isRemote;
3940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                needsRefresh = true;
3950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
3960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mIsConnecting != isConnecting) {
3970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mIsConnecting = isConnecting;
3980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                needsRefresh = true;
3990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
40070e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
4010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (needsRefresh) {
4020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                refreshDrawableState();
40370e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
40470e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
4050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            setEnabled(mRouter.isRouteAvailable(mRouteTypes,
4060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
40770e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
408b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell    }
409b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell
4100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
411690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteAdded(MediaRouter router, RouteInfo info) {
4130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
414690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
415690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
416690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
4180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
419690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
420690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
421690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4222ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        public void onRouteChanged(MediaRouter router, RouteInfo info) {
4230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
4242ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        }
4252ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell
4262ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        @Override
4270abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
4280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
429690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
430690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
431690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4320abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
4330abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
434690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
435f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell
436f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        @Override
437f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
438f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell                int index) {
4390abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
440f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        }
441f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell
442f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        @Override
443f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
4440abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
445f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        }
446690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
447690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell}
448