MediaRouteButton.java revision de0d5d746fc030770b64858b64eac2b1c26e4ba6
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) {
76617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        this(context, attrs, defStyleAttr, 0);
77617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
78617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
79617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    public MediaRouteButton(
80617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
81617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        super(context, attrs, defStyleAttr, defStyleRes);
82690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
83b58b8f832d06b0ffa8886eba5a4916578a3b8743Dianne Hackborn        mRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
840abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mCallback = new MediaRouterCallback();
85690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
86617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette        final TypedArray a = context.obtainStyledAttributes(attrs,
87617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                com.android.internal.R.styleable.MediaRouteButton, defStyleAttr, defStyleRes);
88690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        setRemoteIndicatorDrawable(a.getDrawable(
89690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton_externalRouteEnabledDrawable));
90690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mMinWidth = a.getDimensionPixelSize(
91690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton_minWidth, 0);
92690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mMinHeight = a.getDimensionPixelSize(
93690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                com.android.internal.R.styleable.MediaRouteButton_minHeight, 0);
94849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell        final int routeTypes = a.getInteger(
95849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell                com.android.internal.R.styleable.MediaRouteButton_mediaRouteTypes,
96849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell                MediaRouter.ROUTE_TYPE_LIVE_AUDIO);
97690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        a.recycle();
98690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
99690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        setClickable(true);
100e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        setLongClickable(true);
101849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell
102849df0b5a7a5ef72610d687a8b1c2f0a23f873abAdam Powell        setRouteTypes(routeTypes);
103690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
104690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1050abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Gets the media route types for filtering the routes that the user can
1070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * select using the media route chooser dialog.
1080abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     *
1090abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * @return The route types.
1100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
1110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public int getRouteTypes() {
1120abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        return mRouteTypes;
1130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1140abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1160abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Sets the types of routes that will be shown in the media route chooser dialog
1170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * launched by this button.
1180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     *
1190abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * @param types The route types to match.
1200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
1210abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public void setRouteTypes(int types) {
1220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mRouteTypes != types) {
1230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mAttachedToWindow && mRouteTypes != 0) {
1240abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRouter.removeCallback(mCallback);
1250abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
1260abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1270abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRouteTypes = types;
1280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1290abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mAttachedToWindow && types != 0) {
1300abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRouter.addCallback(types, mCallback,
1310abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                        MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
1320abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
1330abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1340abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
135690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
1360abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
137690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1380abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public void setExtendedSettingsClickListener(OnClickListener listener) {
1390abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mExtendedSettingsClickListener = listener;
140690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
141690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1420abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1430abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Show the route chooser or controller dialog.
1440abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * <p>
1450abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * If the default route is selected or if the currently selected route does
1460abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * not match the {@link #getRouteTypes route types}, then shows the route chooser dialog.
1470abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Otherwise, shows the route controller dialog to offer the user
1480abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * a choice to disconnect from the route or perform other control actions
1490abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * such as setting the route's volume.
1500abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * </p><p>
1510abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * This will attach a {@link DialogFragment} to the containing Activity.
1520abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * </p>
1530abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
1540abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public void showDialog() {
1550abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        showDialogInternal();
1560abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1570abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1580abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    boolean showDialogInternal() {
1590abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (!mAttachedToWindow) {
1600abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            return false;
161690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
162690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1630abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        DialogFragment f = MediaRouteDialogPresenter.showDialogFragment(getActivity(),
1640abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRouteTypes, mExtendedSettingsClickListener);
1650abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        return f != null;
1660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private Activity getActivity() {
1690abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        // Gross way of unwrapping the Activity so we can get the FragmentManager
1700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        Context context = getContext();
1710abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        while (context instanceof ContextWrapper) {
1720abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (context instanceof Activity) {
1730abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                return (Activity)context;
174690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            }
1750abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            context = ((ContextWrapper)context).getBaseContext();
176690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
1770abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        throw new IllegalStateException("The MediaRouteButton's Context is not an Activity.");
178690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
179690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
1800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    /**
1810abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * Sets whether to enable showing a toast with the content descriptor of the
1820abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     * button when the button is long pressed.
1830abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown     */
184e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    void setCheatSheetEnabled(boolean enable) {
185e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        mCheatSheetEnabled = enable;
186e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    }
187e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
188e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    @Override
1890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    public boolean performClick() {
1900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        // Send the appropriate accessibility events and call listeners
1910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        boolean handled = super.performClick();
1920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (!handled) {
1930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            playSoundEffect(SoundEffectConstants.CLICK);
1940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
1950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        return showDialogInternal() || handled;
1960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
1970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
1980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    @Override
199e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    public boolean performLongClick() {
200e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (super.performLongClick()) {
201e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            return true;
202e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
203e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
204e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (!mCheatSheetEnabled) {
205e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            return false;
206e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
207e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
208e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final CharSequence contentDesc = getContentDescription();
209e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (TextUtils.isEmpty(contentDesc)) {
210e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            // Don't show the cheat sheet if we have no description
211e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            return false;
212e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
213e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
214e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int[] screenPos = new int[2];
215e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final Rect displayFrame = new Rect();
216e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        getLocationOnScreen(screenPos);
217e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        getWindowVisibleDisplayFrame(displayFrame);
218e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
219e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final Context context = getContext();
220e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int width = getWidth();
221e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int height = getHeight();
222e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int midy = screenPos[1] + height / 2;
223e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
224e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
225e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        Toast cheatSheet = Toast.makeText(context, contentDesc, Toast.LENGTH_SHORT);
226e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        if (midy < displayFrame.height()) {
227e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            // Show along the top; follow action buttons
228e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            cheatSheet.setGravity(Gravity.TOP | Gravity.END,
229e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell                    screenWidth - screenPos[0] - width / 2, height);
230e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        } else {
231e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            // Show along the bottom center
232e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
233e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        }
234e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        cheatSheet.show();
235e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
236e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell        return true;
237e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell    }
238e4681878702edaf0833294b3f1ce835705d3ad04Adam Powell
239690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
240690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected int[] onCreateDrawableState(int extraSpace) {
241690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
2422ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell
2432ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // Technically we should be handling this more completely, but these
2442ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // are implementation details here. Checked is used to express the connecting
2452ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // drawable state and it's mutually exclusive with activated for the purposes
2462ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        // of state selection here.
2472ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        if (mIsConnecting) {
2482ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
2492ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        } else if (mRemoteActive) {
250690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mergeDrawableStates(drawableState, ACTIVATED_STATE_SET);
251690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
252690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        return drawableState;
253690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
254690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
255690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
256690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected void drawableStateChanged() {
257690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.drawableStateChanged();
258690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
259690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mRemoteIndicator != null) {
260690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            int[] myDrawableState = getDrawableState();
261690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mRemoteIndicator.setState(myDrawableState);
262690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            invalidate();
263690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
264690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
265690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
2660abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private void setRemoteIndicatorDrawable(Drawable d) {
2670abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mRemoteIndicator != null) {
2680abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRemoteIndicator.setCallback(null);
2690abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            unscheduleDrawable(mRemoteIndicator);
2700abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
2710abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mRemoteIndicator = d;
2720abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (d != null) {
2730abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            d.setCallback(this);
2740abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            d.setState(getDrawableState());
2750abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            d.setVisible(getVisibility() == VISIBLE, false);
2760abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
2770abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
2780abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        refreshDrawableState();
2790abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    }
2800abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
281690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
282690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected boolean verifyDrawable(Drawable who) {
283690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        return super.verifyDrawable(who) || who == mRemoteIndicator;
284690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
285690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
286690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
287690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public void jumpDrawablesToCurrentState() {
288690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.jumpDrawablesToCurrentState();
2890abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
2900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mRemoteIndicator != null) {
2910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRemoteIndicator.jumpToCurrentState();
2920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        }
293690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
294690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
295690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
296690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    public void setVisibility(int visibility) {
297690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.setVisibility(visibility);
2980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
299690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mRemoteIndicator != null) {
300690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
301690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
302690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
303690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
304690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
305101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    public void onAttachedToWindow() {
306101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        super.onAttachedToWindow();
3070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
308101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        mAttachedToWindow = true;
309101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        if (mRouteTypes != 0) {
3100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRouter.addCallback(mRouteTypes, mCallback,
31169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
312101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        }
3130abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        refreshRoute();
314101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    }
315101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich
316101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    @Override
317101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    public void onDetachedFromWindow() {
3180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mAttachedToWindow = false;
319101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        if (mRouteTypes != 0) {
3200abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            mRouter.removeCallback(mCallback);
321101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        }
3220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
323101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich        super.onDetachedFromWindow();
324101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    }
325101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich
326101c44915259fb76d14f917712a51fb0b08a7594Jack Palevich    @Override
327690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
328690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
329690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
330690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
331690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
332690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
333de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang        final int width = Math.max(mMinWidth, mRemoteIndicator != null ?
334de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                mRemoteIndicator.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight() : 0);
335de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang        final int height = Math.max(mMinHeight, mRemoteIndicator != null ?
336de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                mRemoteIndicator.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom() : 0);
337690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
338de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang        int measuredWidth;
339690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        switch (widthMode) {
340690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.EXACTLY:
341de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                measuredWidth = widthSize;
342690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
343690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.AT_MOST:
344de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                measuredWidth = Math.min(widthSize, width);
345690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
346690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            default:
347690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.UNSPECIFIED:
348de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                measuredWidth = width;
349690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
350690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
351690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
352de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang        int measuredHeight;
353690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        switch (heightMode) {
354690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.EXACTLY:
355de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                measuredHeight = heightSize;
356690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
357690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.AT_MOST:
358de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                measuredHeight = Math.min(heightSize, height);
359690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
360690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            default:
361690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell            case MeasureSpec.UNSPECIFIED:
362de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang                measuredHeight = height;
363690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell                break;
364690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
365690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
366de0d5d746fc030770b64858b64eac2b1c26e4ba6Dongwon Kang        setMeasuredDimension(measuredWidth, measuredHeight);
367690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
368690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
369690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    @Override
370690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    protected void onDraw(Canvas canvas) {
371690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        super.onDraw(canvas);
372690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
373690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        if (mRemoteIndicator == null) return;
374690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
375690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int left = getPaddingLeft();
376690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int right = getWidth() - getPaddingRight();
377690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int top = getPaddingTop();
378690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int bottom = getHeight() - getPaddingBottom();
379690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
380690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
381690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
382690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawLeft = left + (right - left - drawWidth) / 2;
383690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        final int drawTop = top + (bottom - top - drawHeight) / 2;
384690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
3850abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        mRemoteIndicator.setBounds(drawLeft, drawTop,
3860abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                drawLeft + drawWidth, drawTop + drawHeight);
387690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        mRemoteIndicator.draw(canvas);
388690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
389690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
3900abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private void refreshRoute() {
3910abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        if (mAttachedToWindow) {
3920abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
3930abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            final boolean isRemote = !route.isDefault() && route.matchesTypes(mRouteTypes);
3940abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            final boolean isConnecting = isRemote && route.isConnecting();
3950abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown
3960abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            boolean needsRefresh = false;
3970abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mRemoteActive != isRemote) {
3980abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mRemoteActive = isRemote;
3990abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                needsRefresh = true;
4000abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
4010abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (mIsConnecting != isConnecting) {
4020abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                mIsConnecting = isConnecting;
4030abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                needsRefresh = true;
4040abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            }
40570e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
4060abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            if (needsRefresh) {
4070abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                refreshDrawableState();
40870e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell            }
40970e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell
4100abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            setEnabled(mRouter.isRouteAvailable(mRouteTypes,
4110abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
41270e11e50eecfc8f1dfb76316d099e4331ebd28f7Adam Powell        }
413b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell    }
414b35c445f34e1a18e17aef3e3dfbc1c39b4d1815cAdam Powell
4150abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown    private final class MediaRouterCallback extends MediaRouter.SimpleCallback {
416690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4170abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteAdded(MediaRouter router, RouteInfo info) {
4180abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
419690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
420690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
421690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4220abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteRemoved(MediaRouter router, RouteInfo info) {
4230abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
424690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
425690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
426690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4272ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        public void onRouteChanged(MediaRouter router, RouteInfo info) {
4280abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
4292ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        }
4302ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell
4312ee6a2a83262d05a566bd713d238e89edfd33a29Adam Powell        @Override
4320abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
4330abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
434690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
435690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell
436690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        @Override
4370abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown        public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) {
4380abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
439690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell        }
440f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell
441f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        @Override
442f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        public void onRouteGrouped(MediaRouter router, RouteInfo info, RouteGroup group,
443f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell                int index) {
4440abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
445f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        }
446f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell
447f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        @Override
448f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        public void onRouteUngrouped(MediaRouter router, RouteInfo info, RouteGroup group) {
4490abd3a6ce83ed23abe614155e776b600ef2a66c3Jeff Brown            refreshRoute();
450f3b653a21cdffe04c94c275e69ecb56e00766e82Adam Powell        }
451690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell    }
452690ffb4e1f735148a15f2036d9a3c1962fba188cAdam Powell}
453