MediaRouteButton.java revision fa0c1799716878268ad8705818bb2cbe47338c9d
111417b1cfde8f1749905f2d735623af9214148afJeff Brown/*
211417b1cfde8f1749905f2d735623af9214148afJeff Brown * Copyright (C) 2013 The Android Open Source Project
311417b1cfde8f1749905f2d735623af9214148afJeff Brown *
411417b1cfde8f1749905f2d735623af9214148afJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
511417b1cfde8f1749905f2d735623af9214148afJeff Brown * you may not use this file except in compliance with the License.
611417b1cfde8f1749905f2d735623af9214148afJeff Brown * You may obtain a copy of the License at
711417b1cfde8f1749905f2d735623af9214148afJeff Brown *
811417b1cfde8f1749905f2d735623af9214148afJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
911417b1cfde8f1749905f2d735623af9214148afJeff Brown *
1011417b1cfde8f1749905f2d735623af9214148afJeff Brown * Unless required by applicable law or agreed to in writing, software
1111417b1cfde8f1749905f2d735623af9214148afJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1211417b1cfde8f1749905f2d735623af9214148afJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1311417b1cfde8f1749905f2d735623af9214148afJeff Brown * See the License for the specific language governing permissions and
1411417b1cfde8f1749905f2d735623af9214148afJeff Brown * limitations under the License.
1511417b1cfde8f1749905f2d735623af9214148afJeff Brown */
1611417b1cfde8f1749905f2d735623af9214148afJeff Brown
1711417b1cfde8f1749905f2d735623af9214148afJeff Brownpackage android.support.v7.app;
1811417b1cfde8f1749905f2d735623af9214148afJeff Brown
1911417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.app.Activity;
2011417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.content.Context;
2111417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.content.ContextWrapper;
2211417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.content.res.TypedArray;
2311417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.graphics.Canvas;
2411417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.graphics.Rect;
2511417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.graphics.drawable.Drawable;
26429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbyeimport android.support.annotation.NonNull;
2711417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v4.app.FragmentActivity;
2811417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v4.app.FragmentManager;
2911417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v4.graphics.drawable.DrawableCompat;
3011417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v4.view.GravityCompat;
3111417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v7.media.MediaRouter;
3211417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v7.media.MediaRouteSelector;
3311417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.support.v7.mediarouter.R;
3411417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.text.TextUtils;
3511417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.util.AttributeSet;
3611417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.util.Log;
3711417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.view.Gravity;
3811417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.view.HapticFeedbackConstants;
3911417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.view.SoundEffectConstants;
4011417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.view.View;
4111417b1cfde8f1749905f2d735623af9214148afJeff Brownimport android.widget.Toast;
4211417b1cfde8f1749905f2d735623af9214148afJeff Brown
4311417b1cfde8f1749905f2d735623af9214148afJeff Brown/**
4411417b1cfde8f1749905f2d735623af9214148afJeff Brown * The media route button allows the user to select routes and to control the
4511417b1cfde8f1749905f2d735623af9214148afJeff Brown * currently selected route.
469942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * <p>
479942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * The application must specify the kinds of routes that the user should be allowed
489942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * to select by specifying a {@link MediaRouteSelector selector} with the
499942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * {@link #setRouteSelector} method.
509942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p><p>
519942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * When the default route is selected or when the currently selected route does not
529942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * match the {@link #getRouteSelector() selector}, the button will appear in
539942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * an inactive state indicating that the application is not connected to a
549942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * route of the kind that it wants to use.  Clicking on the button opens
559942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * a {@link MediaRouteChooserDialog} to allow the user to select a route.
569942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * If no non-default routes match the selector and it is not possible for an active
579942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * scan to discover any matching routes, then the button is disabled and cannot
589942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * be clicked.
599942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p><p>
609942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * When a non-default route is selected that matches the selector, the button will
619942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * appear in an active state indicating that the application is connected
629942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * to a route of the kind that it wants to use.  The button may also appear
639942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * in an intermediary connecting state if the route is in the process of connecting
649942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * to the destination but has not yet completed doing so.  In either case, clicking
659942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * on the button opens a {@link MediaRouteControllerDialog} to allow the user
669942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * to control or disconnect from the current route.
679942d40d0d952b03b583fe66f434676793697aa2Jeff Brown * </p>
6811417b1cfde8f1749905f2d735623af9214148afJeff Brown *
6911417b1cfde8f1749905f2d735623af9214148afJeff Brown * <h3>Prerequisites</h3>
7011417b1cfde8f1749905f2d735623af9214148afJeff Brown * <p>
7111417b1cfde8f1749905f2d735623af9214148afJeff Brown * To use the media route button, the activity must be a subclass of
7211417b1cfde8f1749905f2d735623af9214148afJeff Brown * {@link FragmentActivity} from the <code>android.support.v4</code>
7311417b1cfde8f1749905f2d735623af9214148afJeff Brown * support library.  Refer to support library documentation for details.
7411417b1cfde8f1749905f2d735623af9214148afJeff Brown * </p>
7511417b1cfde8f1749905f2d735623af9214148afJeff Brown *
7611417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see MediaRouteActionProvider
7711417b1cfde8f1749905f2d735623af9214148afJeff Brown * @see #setRouteSelector
7811417b1cfde8f1749905f2d735623af9214148afJeff Brown */
7911417b1cfde8f1749905f2d735623af9214148afJeff Brownpublic class MediaRouteButton extends View {
8011417b1cfde8f1749905f2d735623af9214148afJeff Brown    private static final String TAG = "MediaRouteButton";
8111417b1cfde8f1749905f2d735623af9214148afJeff Brown
8211417b1cfde8f1749905f2d735623af9214148afJeff Brown    private static final String CHOOSER_FRAGMENT_TAG =
8311417b1cfde8f1749905f2d735623af9214148afJeff Brown            "android.support.v7.mediarouter:MediaRouteChooserDialogFragment";
8411417b1cfde8f1749905f2d735623af9214148afJeff Brown    private static final String CONTROLLER_FRAGMENT_TAG =
8511417b1cfde8f1749905f2d735623af9214148afJeff Brown            "android.support.v7.mediarouter:MediaRouteControllerDialogFragment";
8611417b1cfde8f1749905f2d735623af9214148afJeff Brown
8711417b1cfde8f1749905f2d735623af9214148afJeff Brown    private final MediaRouter mRouter;
8811417b1cfde8f1749905f2d735623af9214148afJeff Brown    private final MediaRouterCallback mCallback;
8911417b1cfde8f1749905f2d735623af9214148afJeff Brown
9011417b1cfde8f1749905f2d735623af9214148afJeff Brown    private MediaRouteSelector mSelector = MediaRouteSelector.EMPTY;
91eff7719415542ba819054863b0995f07742a7a8aJeff Brown    private MediaRouteDialogFactory mDialogFactory = MediaRouteDialogFactory.getDefault();
9211417b1cfde8f1749905f2d735623af9214148afJeff Brown
9311417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean mAttachedToWindow;
9411417b1cfde8f1749905f2d735623af9214148afJeff Brown
9511417b1cfde8f1749905f2d735623af9214148afJeff Brown    private Drawable mRemoteIndicator;
9611417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean mRemoteActive;
9711417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean mCheatSheetEnabled;
9811417b1cfde8f1749905f2d735623af9214148afJeff Brown    private boolean mIsConnecting;
9911417b1cfde8f1749905f2d735623af9214148afJeff Brown
10011417b1cfde8f1749905f2d735623af9214148afJeff Brown    private int mMinWidth;
10111417b1cfde8f1749905f2d735623af9214148afJeff Brown    private int mMinHeight;
10211417b1cfde8f1749905f2d735623af9214148afJeff Brown
10311417b1cfde8f1749905f2d735623af9214148afJeff Brown    // The checked state is used when connected to a remote route.
10411417b1cfde8f1749905f2d735623af9214148afJeff Brown    private static final int[] CHECKED_STATE_SET = {
10511417b1cfde8f1749905f2d735623af9214148afJeff Brown        android.R.attr.state_checked
10611417b1cfde8f1749905f2d735623af9214148afJeff Brown    };
10711417b1cfde8f1749905f2d735623af9214148afJeff Brown
10811417b1cfde8f1749905f2d735623af9214148afJeff Brown    // The checkable state is used while connecting to a remote route.
10911417b1cfde8f1749905f2d735623af9214148afJeff Brown    private static final int[] CHECKABLE_STATE_SET = {
11011417b1cfde8f1749905f2d735623af9214148afJeff Brown        android.R.attr.state_checkable
11111417b1cfde8f1749905f2d735623af9214148afJeff Brown    };
11211417b1cfde8f1749905f2d735623af9214148afJeff Brown
11311417b1cfde8f1749905f2d735623af9214148afJeff Brown    public MediaRouteButton(Context context) {
11411417b1cfde8f1749905f2d735623af9214148afJeff Brown        this(context, null);
11511417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
11611417b1cfde8f1749905f2d735623af9214148afJeff Brown
11711417b1cfde8f1749905f2d735623af9214148afJeff Brown    public MediaRouteButton(Context context, AttributeSet attrs) {
11811417b1cfde8f1749905f2d735623af9214148afJeff Brown        this(context, attrs, R.attr.mediaRouteButtonStyle);
11911417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
12011417b1cfde8f1749905f2d735623af9214148afJeff Brown
12111417b1cfde8f1749905f2d735623af9214148afJeff Brown    public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
12294be6100218126ce6a08bf1f56209578500b361fRoboErik        super(MediaRouterThemeHelper.createThemedContext(context), attrs, defStyleAttr);
12311417b1cfde8f1749905f2d735623af9214148afJeff Brown        context = getContext();
12411417b1cfde8f1749905f2d735623af9214148afJeff Brown
12511417b1cfde8f1749905f2d735623af9214148afJeff Brown        mRouter = MediaRouter.getInstance(context);
12611417b1cfde8f1749905f2d735623af9214148afJeff Brown        mCallback = new MediaRouterCallback();
12711417b1cfde8f1749905f2d735623af9214148afJeff Brown
12811417b1cfde8f1749905f2d735623af9214148afJeff Brown        TypedArray a = context.obtainStyledAttributes(attrs,
12911417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton, defStyleAttr, 0);
13011417b1cfde8f1749905f2d735623af9214148afJeff Brown        setRemoteIndicatorDrawable(a.getDrawable(
13111417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton_externalRouteEnabledDrawable));
13211417b1cfde8f1749905f2d735623af9214148afJeff Brown        mMinWidth = a.getDimensionPixelSize(
13311417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton_android_minWidth, 0);
13411417b1cfde8f1749905f2d735623af9214148afJeff Brown        mMinHeight = a.getDimensionPixelSize(
13511417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton_android_minHeight, 0);
13611417b1cfde8f1749905f2d735623af9214148afJeff Brown        a.recycle();
13711417b1cfde8f1749905f2d735623af9214148afJeff Brown
13811417b1cfde8f1749905f2d735623af9214148afJeff Brown        setClickable(true);
13911417b1cfde8f1749905f2d735623af9214148afJeff Brown        setLongClickable(true);
14011417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
14111417b1cfde8f1749905f2d735623af9214148afJeff Brown
14211417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
14311417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Gets the media route selector for filtering the routes that the user can
14411417b1cfde8f1749905f2d735623af9214148afJeff Brown     * select using the media route chooser dialog.
14511417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
14611417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @return The selector, never null.
14711417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
148429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye    @NonNull
14911417b1cfde8f1749905f2d735623af9214148afJeff Brown    public MediaRouteSelector getRouteSelector() {
15011417b1cfde8f1749905f2d735623af9214148afJeff Brown        return mSelector;
15111417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
15211417b1cfde8f1749905f2d735623af9214148afJeff Brown
15311417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
15411417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Sets the media route selector for filtering the routes that the user can
15511417b1cfde8f1749905f2d735623af9214148afJeff Brown     * select using the media route chooser dialog.
15611417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
15711417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @param selector The selector, must not be null.
15811417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
15911417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void setRouteSelector(MediaRouteSelector selector) {
16011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (selector == null) {
16111417b1cfde8f1749905f2d735623af9214148afJeff Brown            throw new IllegalArgumentException("selector must not be null");
16211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
16311417b1cfde8f1749905f2d735623af9214148afJeff Brown
16411417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!mSelector.equals(selector)) {
16511417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mAttachedToWindow) {
1669942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                if (!mSelector.isEmpty()) {
1679942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                    mRouter.removeCallback(mCallback);
1689942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                }
1699942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                if (!selector.isEmpty()) {
1709942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                    mRouter.addCallback(selector, mCallback);
1719942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                }
17211417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
1739942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            mSelector = selector;
17411417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
17511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
17611417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
17711417b1cfde8f1749905f2d735623af9214148afJeff Brown
17811417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
179eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Gets the media route dialog factory to use when showing the route chooser
180eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * or controller dialog.
181eff7719415542ba819054863b0995f07742a7a8aJeff Brown     *
182eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * @return The dialog factory, never null.
183eff7719415542ba819054863b0995f07742a7a8aJeff Brown     */
184429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye    @NonNull
185eff7719415542ba819054863b0995f07742a7a8aJeff Brown    public MediaRouteDialogFactory getDialogFactory() {
186eff7719415542ba819054863b0995f07742a7a8aJeff Brown        return mDialogFactory;
187eff7719415542ba819054863b0995f07742a7a8aJeff Brown    }
188eff7719415542ba819054863b0995f07742a7a8aJeff Brown
189eff7719415542ba819054863b0995f07742a7a8aJeff Brown    /**
190eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Sets the media route dialog factory to use when showing the route chooser
191eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * or controller dialog.
192eff7719415542ba819054863b0995f07742a7a8aJeff Brown     *
193eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * @param factory The dialog factory, must not be null.
194eff7719415542ba819054863b0995f07742a7a8aJeff Brown     */
195429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye    public void setDialogFactory(@NonNull MediaRouteDialogFactory factory) {
196eff7719415542ba819054863b0995f07742a7a8aJeff Brown        if (factory == null) {
197eff7719415542ba819054863b0995f07742a7a8aJeff Brown            throw new IllegalArgumentException("factory must not be null");
198eff7719415542ba819054863b0995f07742a7a8aJeff Brown        }
199eff7719415542ba819054863b0995f07742a7a8aJeff Brown
200eff7719415542ba819054863b0995f07742a7a8aJeff Brown        mDialogFactory = factory;
201eff7719415542ba819054863b0995f07742a7a8aJeff Brown    }
202eff7719415542ba819054863b0995f07742a7a8aJeff Brown
203eff7719415542ba819054863b0995f07742a7a8aJeff Brown    /**
20411417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Show the route chooser or controller dialog.
20511417b1cfde8f1749905f2d735623af9214148afJeff Brown     * <p>
2069942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * If the default route is selected or if the currently selected route does
2079942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * not match the {@link #getRouteSelector selector}, then shows the route chooser dialog.
2089942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * Otherwise, shows the route controller dialog to offer the user
20911417b1cfde8f1749905f2d735623af9214148afJeff Brown     * a choice to disconnect from the route or perform other control actions
21011417b1cfde8f1749905f2d735623af9214148afJeff Brown     * such as setting the route's volume.
2119942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * </p><p>
212eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * The application can customize the dialogs by calling {@link #setDialogFactory}
213eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * to provide a customized dialog factory.
21411417b1cfde8f1749905f2d735623af9214148afJeff Brown     * </p>
21511417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
21611417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @return True if the dialog was actually shown.
21711417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
21811417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @throws IllegalStateException if the activity is not a subclass of
21911417b1cfde8f1749905f2d735623af9214148afJeff Brown     * {@link FragmentActivity}.
22011417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
22111417b1cfde8f1749905f2d735623af9214148afJeff Brown    public boolean showDialog() {
22211417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!mAttachedToWindow) {
22311417b1cfde8f1749905f2d735623af9214148afJeff Brown            return false;
22411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
22511417b1cfde8f1749905f2d735623af9214148afJeff Brown
22611417b1cfde8f1749905f2d735623af9214148afJeff Brown        final FragmentManager fm = getFragmentManager();
22711417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (fm == null) {
22811417b1cfde8f1749905f2d735623af9214148afJeff Brown            throw new IllegalStateException("The activity must be a subclass of FragmentActivity");
22911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
23011417b1cfde8f1749905f2d735623af9214148afJeff Brown
2319942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
2329942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        if (route.isDefault() || !route.matchesSelector(mSelector)) {
23311417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) {
23411417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.w(TAG, "showDialog(): Route chooser dialog already showing!");
23511417b1cfde8f1749905f2d735623af9214148afJeff Brown                return false;
23611417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
237eff7719415542ba819054863b0995f07742a7a8aJeff Brown            MediaRouteChooserDialogFragment f =
238eff7719415542ba819054863b0995f07742a7a8aJeff Brown                    mDialogFactory.onCreateChooserDialogFragment();
23911417b1cfde8f1749905f2d735623af9214148afJeff Brown            f.setRouteSelector(mSelector);
24011417b1cfde8f1749905f2d735623af9214148afJeff Brown            f.show(fm, CHOOSER_FRAGMENT_TAG);
24111417b1cfde8f1749905f2d735623af9214148afJeff Brown        } else {
24211417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) {
24311417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.w(TAG, "showDialog(): Route controller dialog already showing!");
24411417b1cfde8f1749905f2d735623af9214148afJeff Brown                return false;
24511417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
246eff7719415542ba819054863b0995f07742a7a8aJeff Brown            MediaRouteControllerDialogFragment f =
247eff7719415542ba819054863b0995f07742a7a8aJeff Brown                    mDialogFactory.onCreateControllerDialogFragment();
24811417b1cfde8f1749905f2d735623af9214148afJeff Brown            f.show(fm, CONTROLLER_FRAGMENT_TAG);
24911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
25011417b1cfde8f1749905f2d735623af9214148afJeff Brown        return true;
25111417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
25211417b1cfde8f1749905f2d735623af9214148afJeff Brown
25311417b1cfde8f1749905f2d735623af9214148afJeff Brown    private FragmentManager getFragmentManager() {
25411417b1cfde8f1749905f2d735623af9214148afJeff Brown        Activity activity = getActivity();
25511417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (activity instanceof FragmentActivity) {
25611417b1cfde8f1749905f2d735623af9214148afJeff Brown            return ((FragmentActivity)activity).getSupportFragmentManager();
25711417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
25811417b1cfde8f1749905f2d735623af9214148afJeff Brown        return null;
25911417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
26011417b1cfde8f1749905f2d735623af9214148afJeff Brown
26111417b1cfde8f1749905f2d735623af9214148afJeff Brown    private Activity getActivity() {
26211417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Gross way of unwrapping the Activity so we can get the FragmentManager
26311417b1cfde8f1749905f2d735623af9214148afJeff Brown        Context context = getContext();
26411417b1cfde8f1749905f2d735623af9214148afJeff Brown        while (context instanceof ContextWrapper) {
26511417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (context instanceof Activity) {
26611417b1cfde8f1749905f2d735623af9214148afJeff Brown                return (Activity)context;
26711417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
26811417b1cfde8f1749905f2d735623af9214148afJeff Brown            context = ((ContextWrapper)context).getBaseContext();
26911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
27011417b1cfde8f1749905f2d735623af9214148afJeff Brown        return null;
27111417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
27211417b1cfde8f1749905f2d735623af9214148afJeff Brown
27311417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
27411417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Sets whether to enable showing a toast with the content descriptor of the
27511417b1cfde8f1749905f2d735623af9214148afJeff Brown     * button when the button is long pressed.
27611417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
27711417b1cfde8f1749905f2d735623af9214148afJeff Brown    void setCheatSheetEnabled(boolean enable) {
27811417b1cfde8f1749905f2d735623af9214148afJeff Brown        mCheatSheetEnabled = enable;
27911417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
28011417b1cfde8f1749905f2d735623af9214148afJeff Brown
28111417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
28211417b1cfde8f1749905f2d735623af9214148afJeff Brown    public boolean performClick() {
28311417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Send the appropriate accessibility events and call listeners
28411417b1cfde8f1749905f2d735623af9214148afJeff Brown        boolean handled = super.performClick();
28511417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!handled) {
28611417b1cfde8f1749905f2d735623af9214148afJeff Brown            playSoundEffect(SoundEffectConstants.CLICK);
28711417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
28811417b1cfde8f1749905f2d735623af9214148afJeff Brown        return showDialog() || handled;
28911417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
29011417b1cfde8f1749905f2d735623af9214148afJeff Brown
29111417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
29211417b1cfde8f1749905f2d735623af9214148afJeff Brown    public boolean performLongClick() {
29311417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (super.performLongClick()) {
29411417b1cfde8f1749905f2d735623af9214148afJeff Brown            return true;
29511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
29611417b1cfde8f1749905f2d735623af9214148afJeff Brown
29711417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!mCheatSheetEnabled) {
29811417b1cfde8f1749905f2d735623af9214148afJeff Brown            return false;
29911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
30011417b1cfde8f1749905f2d735623af9214148afJeff Brown
30111417b1cfde8f1749905f2d735623af9214148afJeff Brown        final CharSequence contentDesc = getContentDescription();
30211417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (TextUtils.isEmpty(contentDesc)) {
30311417b1cfde8f1749905f2d735623af9214148afJeff Brown            // Don't show the cheat sheet if we have no description
30411417b1cfde8f1749905f2d735623af9214148afJeff Brown            return false;
30511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
30611417b1cfde8f1749905f2d735623af9214148afJeff Brown
30711417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int[] screenPos = new int[2];
30811417b1cfde8f1749905f2d735623af9214148afJeff Brown        final Rect displayFrame = new Rect();
30911417b1cfde8f1749905f2d735623af9214148afJeff Brown        getLocationOnScreen(screenPos);
31011417b1cfde8f1749905f2d735623af9214148afJeff Brown        getWindowVisibleDisplayFrame(displayFrame);
31111417b1cfde8f1749905f2d735623af9214148afJeff Brown
31211417b1cfde8f1749905f2d735623af9214148afJeff Brown        final Context context = getContext();
31311417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int width = getWidth();
31411417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int height = getHeight();
31511417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int midy = screenPos[1] + height / 2;
31611417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
31711417b1cfde8f1749905f2d735623af9214148afJeff Brown
31811417b1cfde8f1749905f2d735623af9214148afJeff Brown        Toast cheatSheet = Toast.makeText(context, contentDesc, Toast.LENGTH_SHORT);
31911417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (midy < displayFrame.height()) {
32011417b1cfde8f1749905f2d735623af9214148afJeff Brown            // Show along the top; follow action buttons
32111417b1cfde8f1749905f2d735623af9214148afJeff Brown            cheatSheet.setGravity(Gravity.TOP | GravityCompat.END,
32211417b1cfde8f1749905f2d735623af9214148afJeff Brown                    screenWidth - screenPos[0] - width / 2, height);
32311417b1cfde8f1749905f2d735623af9214148afJeff Brown        } else {
32411417b1cfde8f1749905f2d735623af9214148afJeff Brown            // Show along the bottom center
32511417b1cfde8f1749905f2d735623af9214148afJeff Brown            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
32611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
32711417b1cfde8f1749905f2d735623af9214148afJeff Brown        cheatSheet.show();
32811417b1cfde8f1749905f2d735623af9214148afJeff Brown        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
32911417b1cfde8f1749905f2d735623af9214148afJeff Brown        return true;
33011417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
33111417b1cfde8f1749905f2d735623af9214148afJeff Brown
33211417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
33311417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected int[] onCreateDrawableState(int extraSpace) {
33411417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
33511417b1cfde8f1749905f2d735623af9214148afJeff Brown
33611417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Technically we should be handling this more completely, but these
33711417b1cfde8f1749905f2d735623af9214148afJeff Brown        // are implementation details here. Checkable is used to express the connecting
33811417b1cfde8f1749905f2d735623af9214148afJeff Brown        // drawable state and it's mutually exclusive with check for the purposes
33911417b1cfde8f1749905f2d735623af9214148afJeff Brown        // of state selection here.
34011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mIsConnecting) {
34111417b1cfde8f1749905f2d735623af9214148afJeff Brown            mergeDrawableStates(drawableState, CHECKABLE_STATE_SET);
34211417b1cfde8f1749905f2d735623af9214148afJeff Brown        } else if (mRemoteActive) {
34311417b1cfde8f1749905f2d735623af9214148afJeff Brown            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
34411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
34511417b1cfde8f1749905f2d735623af9214148afJeff Brown        return drawableState;
34611417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
34711417b1cfde8f1749905f2d735623af9214148afJeff Brown
34811417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
34911417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected void drawableStateChanged() {
35011417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.drawableStateChanged();
35111417b1cfde8f1749905f2d735623af9214148afJeff Brown
35211417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
35311417b1cfde8f1749905f2d735623af9214148afJeff Brown            int[] myDrawableState = getDrawableState();
35411417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setState(myDrawableState);
35511417b1cfde8f1749905f2d735623af9214148afJeff Brown            invalidate();
35611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
35711417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
35811417b1cfde8f1749905f2d735623af9214148afJeff Brown
359fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand    /**
360fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand     * Sets a drawable to use as the remote route indicator.
361fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand     */
362fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand    public void setRemoteIndicatorDrawable(Drawable d) {
36311417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
36411417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setCallback(null);
36511417b1cfde8f1749905f2d735623af9214148afJeff Brown            unscheduleDrawable(mRemoteIndicator);
36611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
36711417b1cfde8f1749905f2d735623af9214148afJeff Brown        mRemoteIndicator = d;
36811417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (d != null) {
36911417b1cfde8f1749905f2d735623af9214148afJeff Brown            d.setCallback(this);
37011417b1cfde8f1749905f2d735623af9214148afJeff Brown            d.setState(getDrawableState());
37111417b1cfde8f1749905f2d735623af9214148afJeff Brown            d.setVisible(getVisibility() == VISIBLE, false);
37211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
37311417b1cfde8f1749905f2d735623af9214148afJeff Brown
37411417b1cfde8f1749905f2d735623af9214148afJeff Brown        refreshDrawableState();
37511417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
37611417b1cfde8f1749905f2d735623af9214148afJeff Brown
37711417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
37811417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected boolean verifyDrawable(Drawable who) {
37911417b1cfde8f1749905f2d735623af9214148afJeff Brown        return super.verifyDrawable(who) || who == mRemoteIndicator;
38011417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
38111417b1cfde8f1749905f2d735623af9214148afJeff Brown
38211417b1cfde8f1749905f2d735623af9214148afJeff Brown    //@Override defined in v11
38311417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void jumpDrawablesToCurrentState() {
38411417b1cfde8f1749905f2d735623af9214148afJeff Brown        // We can't call super to handle the background so we do it ourselves.
38511417b1cfde8f1749905f2d735623af9214148afJeff Brown        //super.jumpDrawablesToCurrentState();
38611417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (getBackground() != null) {
38711417b1cfde8f1749905f2d735623af9214148afJeff Brown            DrawableCompat.jumpToCurrentState(getBackground());
38811417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
38911417b1cfde8f1749905f2d735623af9214148afJeff Brown
39011417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Handle our own remote indicator.
39111417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
39211417b1cfde8f1749905f2d735623af9214148afJeff Brown            DrawableCompat.jumpToCurrentState(mRemoteIndicator);
39311417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
39411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
39511417b1cfde8f1749905f2d735623af9214148afJeff Brown
39611417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
39711417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void setVisibility(int visibility) {
39811417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.setVisibility(visibility);
39911417b1cfde8f1749905f2d735623af9214148afJeff Brown
40011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
40111417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
40211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
40311417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
40411417b1cfde8f1749905f2d735623af9214148afJeff Brown
40511417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
40611417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void onAttachedToWindow() {
40711417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.onAttachedToWindow();
40811417b1cfde8f1749905f2d735623af9214148afJeff Brown
40911417b1cfde8f1749905f2d735623af9214148afJeff Brown        mAttachedToWindow = true;
4109942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        if (!mSelector.isEmpty()) {
4119942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            mRouter.addCallback(mSelector, mCallback);
41211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
4139942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        refreshRoute();
41411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
41511417b1cfde8f1749905f2d735623af9214148afJeff Brown
41611417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
41711417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void onDetachedFromWindow() {
41811417b1cfde8f1749905f2d735623af9214148afJeff Brown        mAttachedToWindow = false;
4199942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        if (!mSelector.isEmpty()) {
4209942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            mRouter.removeCallback(mCallback);
4219942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        }
42211417b1cfde8f1749905f2d735623af9214148afJeff Brown
42311417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.onDetachedFromWindow();
42411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
42511417b1cfde8f1749905f2d735623af9214148afJeff Brown
42611417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
42711417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
42811417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
42911417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
43011417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
43111417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
43211417b1cfde8f1749905f2d735623af9214148afJeff Brown
43311417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int minWidth = Math.max(mMinWidth,
43411417b1cfde8f1749905f2d735623af9214148afJeff Brown                mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicWidth() : 0);
43511417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int minHeight = Math.max(mMinHeight,
43611417b1cfde8f1749905f2d735623af9214148afJeff Brown                mRemoteIndicator != null ? mRemoteIndicator.getIntrinsicHeight() : 0);
43711417b1cfde8f1749905f2d735623af9214148afJeff Brown
43811417b1cfde8f1749905f2d735623af9214148afJeff Brown        int width;
43911417b1cfde8f1749905f2d735623af9214148afJeff Brown        switch (widthMode) {
44011417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.EXACTLY:
44111417b1cfde8f1749905f2d735623af9214148afJeff Brown                width = widthSize;
44211417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
44311417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.AT_MOST:
44411417b1cfde8f1749905f2d735623af9214148afJeff Brown                width = Math.min(widthSize, minWidth + getPaddingLeft() + getPaddingRight());
44511417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
44611417b1cfde8f1749905f2d735623af9214148afJeff Brown            default:
44711417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.UNSPECIFIED:
44811417b1cfde8f1749905f2d735623af9214148afJeff Brown                width = minWidth + getPaddingLeft() + getPaddingRight();
44911417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
45011417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
45111417b1cfde8f1749905f2d735623af9214148afJeff Brown
45211417b1cfde8f1749905f2d735623af9214148afJeff Brown        int height;
45311417b1cfde8f1749905f2d735623af9214148afJeff Brown        switch (heightMode) {
45411417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.EXACTLY:
45511417b1cfde8f1749905f2d735623af9214148afJeff Brown                height = heightSize;
45611417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
45711417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.AT_MOST:
45811417b1cfde8f1749905f2d735623af9214148afJeff Brown                height = Math.min(heightSize, minHeight + getPaddingTop() + getPaddingBottom());
45911417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
46011417b1cfde8f1749905f2d735623af9214148afJeff Brown            default:
46111417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.UNSPECIFIED:
46211417b1cfde8f1749905f2d735623af9214148afJeff Brown                height = minHeight + getPaddingTop() + getPaddingBottom();
46311417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
46411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
46511417b1cfde8f1749905f2d735623af9214148afJeff Brown
46611417b1cfde8f1749905f2d735623af9214148afJeff Brown        setMeasuredDimension(width, height);
46711417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
46811417b1cfde8f1749905f2d735623af9214148afJeff Brown
46911417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
47011417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected void onDraw(Canvas canvas) {
47111417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.onDraw(canvas);
47211417b1cfde8f1749905f2d735623af9214148afJeff Brown
47311417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
47411417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int left = getPaddingLeft();
47511417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int right = getWidth() - getPaddingRight();
47611417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int top = getPaddingTop();
47711417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int bottom = getHeight() - getPaddingBottom();
47811417b1cfde8f1749905f2d735623af9214148afJeff Brown
47911417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
48011417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
48111417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawLeft = left + (right - left - drawWidth) / 2;
48211417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawTop = top + (bottom - top - drawHeight) / 2;
48311417b1cfde8f1749905f2d735623af9214148afJeff Brown
48411417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setBounds(drawLeft, drawTop,
48511417b1cfde8f1749905f2d735623af9214148afJeff Brown                    drawLeft + drawWidth, drawTop + drawHeight);
48611417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.draw(canvas);
48711417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
48811417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
48911417b1cfde8f1749905f2d735623af9214148afJeff Brown
49011417b1cfde8f1749905f2d735623af9214148afJeff Brown    private void refreshRoute() {
49111417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mAttachedToWindow) {
4929942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
4939942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            final boolean isRemote = !route.isDefault() && route.matchesSelector(mSelector);
4949942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            final boolean isConnecting = isRemote && route.isConnecting();
49511417b1cfde8f1749905f2d735623af9214148afJeff Brown
49611417b1cfde8f1749905f2d735623af9214148afJeff Brown            boolean needsRefresh = false;
49711417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mRemoteActive != isRemote) {
49811417b1cfde8f1749905f2d735623af9214148afJeff Brown                mRemoteActive = isRemote;
49911417b1cfde8f1749905f2d735623af9214148afJeff Brown                needsRefresh = true;
50011417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
50111417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mIsConnecting != isConnecting) {
50211417b1cfde8f1749905f2d735623af9214148afJeff Brown                mIsConnecting = isConnecting;
50311417b1cfde8f1749905f2d735623af9214148afJeff Brown                needsRefresh = true;
50411417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
50511417b1cfde8f1749905f2d735623af9214148afJeff Brown
50611417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (needsRefresh) {
50711417b1cfde8f1749905f2d735623af9214148afJeff Brown                refreshDrawableState();
50811417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
50911417b1cfde8f1749905f2d735623af9214148afJeff Brown
51011417b1cfde8f1749905f2d735623af9214148afJeff Brown            setEnabled(mRouter.isRouteAvailable(mSelector,
511d11aa1784335270b8d85e385f2c8be79ee6a586cJeff Brown                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
51211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
51311417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
51411417b1cfde8f1749905f2d735623af9214148afJeff Brown
51511417b1cfde8f1749905f2d735623af9214148afJeff Brown    private final class MediaRouterCallback extends MediaRouter.Callback {
51611417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
51711417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
51811417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
51911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
52011417b1cfde8f1749905f2d735623af9214148afJeff Brown
52111417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
52211417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
52311417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
52411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
52511417b1cfde8f1749905f2d735623af9214148afJeff Brown
52611417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
52711417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
52811417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
52911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
53011417b1cfde8f1749905f2d735623af9214148afJeff Brown
53111417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
53211417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
53311417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
53411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
53511417b1cfde8f1749905f2d735623af9214148afJeff Brown
53611417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
53711417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
53811417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
53911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
54011417b1cfde8f1749905f2d735623af9214148afJeff Brown
54111417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
54211417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onProviderAdded(MediaRouter router, MediaRouter.ProviderInfo provider) {
54311417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
54411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
54511417b1cfde8f1749905f2d735623af9214148afJeff Brown
54611417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
54711417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onProviderRemoved(MediaRouter router, MediaRouter.ProviderInfo provider) {
54811417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
54911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
55011417b1cfde8f1749905f2d735623af9214148afJeff Brown
55111417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
55211417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onProviderChanged(MediaRouter router, MediaRouter.ProviderInfo provider) {
55311417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
55411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
55511417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
55611417b1cfde8f1749905f2d735623af9214148afJeff Brown}
557