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