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) {
1234448a8e5ed20d230cb838042ff73b6409106cf80Sungsoo Lim        super(MediaRouterThemeHelper.createThemedContext(context, defStyleAttr), attrs,
1244448a8e5ed20d230cb838042ff73b6409106cf80Sungsoo Lim                defStyleAttr);
12511417b1cfde8f1749905f2d735623af9214148afJeff Brown        context = getContext();
12611417b1cfde8f1749905f2d735623af9214148afJeff Brown
12711417b1cfde8f1749905f2d735623af9214148afJeff Brown        mRouter = MediaRouter.getInstance(context);
12811417b1cfde8f1749905f2d735623af9214148afJeff Brown        mCallback = new MediaRouterCallback();
12911417b1cfde8f1749905f2d735623af9214148afJeff Brown
13011417b1cfde8f1749905f2d735623af9214148afJeff Brown        TypedArray a = context.obtainStyledAttributes(attrs,
13111417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton, defStyleAttr, 0);
13211417b1cfde8f1749905f2d735623af9214148afJeff Brown        setRemoteIndicatorDrawable(a.getDrawable(
13311417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton_externalRouteEnabledDrawable));
13411417b1cfde8f1749905f2d735623af9214148afJeff Brown        mMinWidth = a.getDimensionPixelSize(
13511417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton_android_minWidth, 0);
13611417b1cfde8f1749905f2d735623af9214148afJeff Brown        mMinHeight = a.getDimensionPixelSize(
13711417b1cfde8f1749905f2d735623af9214148afJeff Brown                R.styleable.MediaRouteButton_android_minHeight, 0);
13811417b1cfde8f1749905f2d735623af9214148afJeff Brown        a.recycle();
13911417b1cfde8f1749905f2d735623af9214148afJeff Brown
140a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        updateContentDescription();
14111417b1cfde8f1749905f2d735623af9214148afJeff Brown        setClickable(true);
14211417b1cfde8f1749905f2d735623af9214148afJeff Brown        setLongClickable(true);
14311417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
14411417b1cfde8f1749905f2d735623af9214148afJeff Brown
14511417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
14611417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Gets the media route selector for filtering the routes that the user can
14711417b1cfde8f1749905f2d735623af9214148afJeff Brown     * select using the media route chooser dialog.
14811417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
14911417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @return The selector, never null.
15011417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
151429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye    @NonNull
15211417b1cfde8f1749905f2d735623af9214148afJeff Brown    public MediaRouteSelector getRouteSelector() {
15311417b1cfde8f1749905f2d735623af9214148afJeff Brown        return mSelector;
15411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
15511417b1cfde8f1749905f2d735623af9214148afJeff Brown
15611417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
15711417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Sets the media route selector for filtering the routes that the user can
15811417b1cfde8f1749905f2d735623af9214148afJeff Brown     * select using the media route chooser dialog.
15911417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
16011417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @param selector The selector, must not be null.
16111417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
16211417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void setRouteSelector(MediaRouteSelector selector) {
16311417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (selector == null) {
16411417b1cfde8f1749905f2d735623af9214148afJeff Brown            throw new IllegalArgumentException("selector must not be null");
16511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
16611417b1cfde8f1749905f2d735623af9214148afJeff Brown
16711417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!mSelector.equals(selector)) {
16811417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mAttachedToWindow) {
1699942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                if (!mSelector.isEmpty()) {
1709942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                    mRouter.removeCallback(mCallback);
1719942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                }
1729942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                if (!selector.isEmpty()) {
1739942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                    mRouter.addCallback(selector, mCallback);
1749942d40d0d952b03b583fe66f434676793697aa2Jeff Brown                }
17511417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
1769942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            mSelector = selector;
17711417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
17811417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
17911417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
18011417b1cfde8f1749905f2d735623af9214148afJeff Brown
18111417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
182eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Gets the media route dialog factory to use when showing the route chooser
183eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * or controller dialog.
184eff7719415542ba819054863b0995f07742a7a8aJeff Brown     *
185eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * @return The dialog factory, never null.
186eff7719415542ba819054863b0995f07742a7a8aJeff Brown     */
187429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye    @NonNull
188eff7719415542ba819054863b0995f07742a7a8aJeff Brown    public MediaRouteDialogFactory getDialogFactory() {
189eff7719415542ba819054863b0995f07742a7a8aJeff Brown        return mDialogFactory;
190eff7719415542ba819054863b0995f07742a7a8aJeff Brown    }
191eff7719415542ba819054863b0995f07742a7a8aJeff Brown
192eff7719415542ba819054863b0995f07742a7a8aJeff Brown    /**
193eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * Sets the media route dialog factory to use when showing the route chooser
194eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * or controller dialog.
195eff7719415542ba819054863b0995f07742a7a8aJeff Brown     *
196eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * @param factory The dialog factory, must not be null.
197eff7719415542ba819054863b0995f07742a7a8aJeff Brown     */
198429c3b17b88ebd8c4512e9179fd9d48333c0979eTor Norbye    public void setDialogFactory(@NonNull MediaRouteDialogFactory factory) {
199eff7719415542ba819054863b0995f07742a7a8aJeff Brown        if (factory == null) {
200eff7719415542ba819054863b0995f07742a7a8aJeff Brown            throw new IllegalArgumentException("factory must not be null");
201eff7719415542ba819054863b0995f07742a7a8aJeff Brown        }
202eff7719415542ba819054863b0995f07742a7a8aJeff Brown
203eff7719415542ba819054863b0995f07742a7a8aJeff Brown        mDialogFactory = factory;
204eff7719415542ba819054863b0995f07742a7a8aJeff Brown    }
205eff7719415542ba819054863b0995f07742a7a8aJeff Brown
206eff7719415542ba819054863b0995f07742a7a8aJeff Brown    /**
20711417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Show the route chooser or controller dialog.
20811417b1cfde8f1749905f2d735623af9214148afJeff Brown     * <p>
2099942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * If the default route is selected or if the currently selected route does
2109942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * not match the {@link #getRouteSelector selector}, then shows the route chooser dialog.
2119942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * Otherwise, shows the route controller dialog to offer the user
21211417b1cfde8f1749905f2d735623af9214148afJeff Brown     * a choice to disconnect from the route or perform other control actions
21311417b1cfde8f1749905f2d735623af9214148afJeff Brown     * such as setting the route's volume.
2149942d40d0d952b03b583fe66f434676793697aa2Jeff Brown     * </p><p>
215eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * The application can customize the dialogs by calling {@link #setDialogFactory}
216eff7719415542ba819054863b0995f07742a7a8aJeff Brown     * to provide a customized dialog factory.
21711417b1cfde8f1749905f2d735623af9214148afJeff Brown     * </p>
21811417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
21911417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @return True if the dialog was actually shown.
22011417b1cfde8f1749905f2d735623af9214148afJeff Brown     *
22111417b1cfde8f1749905f2d735623af9214148afJeff Brown     * @throws IllegalStateException if the activity is not a subclass of
22211417b1cfde8f1749905f2d735623af9214148afJeff Brown     * {@link FragmentActivity}.
22311417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
22411417b1cfde8f1749905f2d735623af9214148afJeff Brown    public boolean showDialog() {
22511417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!mAttachedToWindow) {
22611417b1cfde8f1749905f2d735623af9214148afJeff Brown            return false;
22711417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
22811417b1cfde8f1749905f2d735623af9214148afJeff Brown
22911417b1cfde8f1749905f2d735623af9214148afJeff Brown        final FragmentManager fm = getFragmentManager();
23011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (fm == null) {
23111417b1cfde8f1749905f2d735623af9214148afJeff Brown            throw new IllegalStateException("The activity must be a subclass of FragmentActivity");
23211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
23311417b1cfde8f1749905f2d735623af9214148afJeff Brown
2349942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
235fa19abbe11335366feb6c885f8d75504ab8fe4f9Insun Kang        if (route.isDefaultOrBluetooth() || !route.matchesSelector(mSelector)) {
23611417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) {
23711417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.w(TAG, "showDialog(): Route chooser dialog already showing!");
23811417b1cfde8f1749905f2d735623af9214148afJeff Brown                return false;
23911417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
240eff7719415542ba819054863b0995f07742a7a8aJeff Brown            MediaRouteChooserDialogFragment f =
241eff7719415542ba819054863b0995f07742a7a8aJeff Brown                    mDialogFactory.onCreateChooserDialogFragment();
24211417b1cfde8f1749905f2d735623af9214148afJeff Brown            f.setRouteSelector(mSelector);
24311417b1cfde8f1749905f2d735623af9214148afJeff Brown            f.show(fm, CHOOSER_FRAGMENT_TAG);
24411417b1cfde8f1749905f2d735623af9214148afJeff Brown        } else {
24511417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) {
24611417b1cfde8f1749905f2d735623af9214148afJeff Brown                Log.w(TAG, "showDialog(): Route controller dialog already showing!");
24711417b1cfde8f1749905f2d735623af9214148afJeff Brown                return false;
24811417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
249eff7719415542ba819054863b0995f07742a7a8aJeff Brown            MediaRouteControllerDialogFragment f =
250eff7719415542ba819054863b0995f07742a7a8aJeff Brown                    mDialogFactory.onCreateControllerDialogFragment();
25111417b1cfde8f1749905f2d735623af9214148afJeff Brown            f.show(fm, CONTROLLER_FRAGMENT_TAG);
25211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
25311417b1cfde8f1749905f2d735623af9214148afJeff Brown        return true;
25411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
25511417b1cfde8f1749905f2d735623af9214148afJeff Brown
25611417b1cfde8f1749905f2d735623af9214148afJeff Brown    private FragmentManager getFragmentManager() {
25711417b1cfde8f1749905f2d735623af9214148afJeff Brown        Activity activity = getActivity();
25811417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (activity instanceof FragmentActivity) {
25911417b1cfde8f1749905f2d735623af9214148afJeff Brown            return ((FragmentActivity)activity).getSupportFragmentManager();
26011417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
26111417b1cfde8f1749905f2d735623af9214148afJeff Brown        return null;
26211417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
26311417b1cfde8f1749905f2d735623af9214148afJeff Brown
26411417b1cfde8f1749905f2d735623af9214148afJeff Brown    private Activity getActivity() {
26511417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Gross way of unwrapping the Activity so we can get the FragmentManager
26611417b1cfde8f1749905f2d735623af9214148afJeff Brown        Context context = getContext();
26711417b1cfde8f1749905f2d735623af9214148afJeff Brown        while (context instanceof ContextWrapper) {
26811417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (context instanceof Activity) {
26911417b1cfde8f1749905f2d735623af9214148afJeff Brown                return (Activity)context;
27011417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
27111417b1cfde8f1749905f2d735623af9214148afJeff Brown            context = ((ContextWrapper)context).getBaseContext();
27211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
27311417b1cfde8f1749905f2d735623af9214148afJeff Brown        return null;
27411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
27511417b1cfde8f1749905f2d735623af9214148afJeff Brown
27611417b1cfde8f1749905f2d735623af9214148afJeff Brown    /**
27711417b1cfde8f1749905f2d735623af9214148afJeff Brown     * Sets whether to enable showing a toast with the content descriptor of the
27811417b1cfde8f1749905f2d735623af9214148afJeff Brown     * button when the button is long pressed.
27911417b1cfde8f1749905f2d735623af9214148afJeff Brown     */
28011417b1cfde8f1749905f2d735623af9214148afJeff Brown    void setCheatSheetEnabled(boolean enable) {
28111417b1cfde8f1749905f2d735623af9214148afJeff Brown        mCheatSheetEnabled = enable;
28211417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
28311417b1cfde8f1749905f2d735623af9214148afJeff Brown
28411417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
28511417b1cfde8f1749905f2d735623af9214148afJeff Brown    public boolean performClick() {
28611417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Send the appropriate accessibility events and call listeners
28711417b1cfde8f1749905f2d735623af9214148afJeff Brown        boolean handled = super.performClick();
28811417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!handled) {
28911417b1cfde8f1749905f2d735623af9214148afJeff Brown            playSoundEffect(SoundEffectConstants.CLICK);
29011417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
29111417b1cfde8f1749905f2d735623af9214148afJeff Brown        return showDialog() || handled;
29211417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
29311417b1cfde8f1749905f2d735623af9214148afJeff Brown
29411417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
29511417b1cfde8f1749905f2d735623af9214148afJeff Brown    public boolean performLongClick() {
29611417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (super.performLongClick()) {
29711417b1cfde8f1749905f2d735623af9214148afJeff Brown            return true;
29811417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
29911417b1cfde8f1749905f2d735623af9214148afJeff Brown
30011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (!mCheatSheetEnabled) {
30111417b1cfde8f1749905f2d735623af9214148afJeff Brown            return false;
30211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
30311417b1cfde8f1749905f2d735623af9214148afJeff Brown
30411417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int[] screenPos = new int[2];
30511417b1cfde8f1749905f2d735623af9214148afJeff Brown        final Rect displayFrame = new Rect();
30611417b1cfde8f1749905f2d735623af9214148afJeff Brown        getLocationOnScreen(screenPos);
30711417b1cfde8f1749905f2d735623af9214148afJeff Brown        getWindowVisibleDisplayFrame(displayFrame);
30811417b1cfde8f1749905f2d735623af9214148afJeff Brown
30911417b1cfde8f1749905f2d735623af9214148afJeff Brown        final Context context = getContext();
31011417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int width = getWidth();
31111417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int height = getHeight();
31211417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int midy = screenPos[1] + height / 2;
31311417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
31411417b1cfde8f1749905f2d735623af9214148afJeff Brown
315a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        Toast cheatSheet = Toast.makeText(context, R.string.mr_button_content_description,
316a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho                Toast.LENGTH_SHORT);
31711417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (midy < displayFrame.height()) {
31811417b1cfde8f1749905f2d735623af9214148afJeff Brown            // Show along the top; follow action buttons
31911417b1cfde8f1749905f2d735623af9214148afJeff Brown            cheatSheet.setGravity(Gravity.TOP | GravityCompat.END,
32011417b1cfde8f1749905f2d735623af9214148afJeff Brown                    screenWidth - screenPos[0] - width / 2, height);
32111417b1cfde8f1749905f2d735623af9214148afJeff Brown        } else {
32211417b1cfde8f1749905f2d735623af9214148afJeff Brown            // Show along the bottom center
32311417b1cfde8f1749905f2d735623af9214148afJeff Brown            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
32411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
32511417b1cfde8f1749905f2d735623af9214148afJeff Brown        cheatSheet.show();
32611417b1cfde8f1749905f2d735623af9214148afJeff Brown        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
32711417b1cfde8f1749905f2d735623af9214148afJeff Brown        return true;
32811417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
32911417b1cfde8f1749905f2d735623af9214148afJeff Brown
33011417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
33111417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected int[] onCreateDrawableState(int extraSpace) {
33211417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
33311417b1cfde8f1749905f2d735623af9214148afJeff Brown
33411417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Technically we should be handling this more completely, but these
33511417b1cfde8f1749905f2d735623af9214148afJeff Brown        // are implementation details here. Checkable is used to express the connecting
33611417b1cfde8f1749905f2d735623af9214148afJeff Brown        // drawable state and it's mutually exclusive with check for the purposes
33711417b1cfde8f1749905f2d735623af9214148afJeff Brown        // of state selection here.
33811417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mIsConnecting) {
33911417b1cfde8f1749905f2d735623af9214148afJeff Brown            mergeDrawableStates(drawableState, CHECKABLE_STATE_SET);
34011417b1cfde8f1749905f2d735623af9214148afJeff Brown        } else if (mRemoteActive) {
34111417b1cfde8f1749905f2d735623af9214148afJeff Brown            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
34211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
34311417b1cfde8f1749905f2d735623af9214148afJeff Brown        return drawableState;
34411417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
34511417b1cfde8f1749905f2d735623af9214148afJeff Brown
34611417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
34711417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected void drawableStateChanged() {
34811417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.drawableStateChanged();
34911417b1cfde8f1749905f2d735623af9214148afJeff Brown
35011417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
35111417b1cfde8f1749905f2d735623af9214148afJeff Brown            int[] myDrawableState = getDrawableState();
35211417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setState(myDrawableState);
35311417b1cfde8f1749905f2d735623af9214148afJeff Brown            invalidate();
35411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
35511417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
35611417b1cfde8f1749905f2d735623af9214148afJeff Brown
357fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand    /**
358fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand     * Sets a drawable to use as the remote route indicator.
359fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand     */
360fa0c1799716878268ad8705818bb2cbe47338c9dP.Y. Laligand    public void setRemoteIndicatorDrawable(Drawable d) {
36111417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
36211417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setCallback(null);
36311417b1cfde8f1749905f2d735623af9214148afJeff Brown            unscheduleDrawable(mRemoteIndicator);
36411417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
36511417b1cfde8f1749905f2d735623af9214148afJeff Brown        mRemoteIndicator = d;
36611417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (d != null) {
36711417b1cfde8f1749905f2d735623af9214148afJeff Brown            d.setCallback(this);
36811417b1cfde8f1749905f2d735623af9214148afJeff Brown            d.setState(getDrawableState());
36911417b1cfde8f1749905f2d735623af9214148afJeff Brown            d.setVisible(getVisibility() == VISIBLE, false);
37011417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
37111417b1cfde8f1749905f2d735623af9214148afJeff Brown
37211417b1cfde8f1749905f2d735623af9214148afJeff Brown        refreshDrawableState();
37311417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
37411417b1cfde8f1749905f2d735623af9214148afJeff Brown
37511417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
37611417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected boolean verifyDrawable(Drawable who) {
37711417b1cfde8f1749905f2d735623af9214148afJeff Brown        return super.verifyDrawable(who) || who == mRemoteIndicator;
37811417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
37911417b1cfde8f1749905f2d735623af9214148afJeff Brown
38011417b1cfde8f1749905f2d735623af9214148afJeff Brown    //@Override defined in v11
38111417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void jumpDrawablesToCurrentState() {
38211417b1cfde8f1749905f2d735623af9214148afJeff Brown        // We can't call super to handle the background so we do it ourselves.
38311417b1cfde8f1749905f2d735623af9214148afJeff Brown        //super.jumpDrawablesToCurrentState();
38411417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (getBackground() != null) {
38511417b1cfde8f1749905f2d735623af9214148afJeff Brown            DrawableCompat.jumpToCurrentState(getBackground());
38611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
38711417b1cfde8f1749905f2d735623af9214148afJeff Brown
38811417b1cfde8f1749905f2d735623af9214148afJeff Brown        // Handle our own remote indicator.
38911417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
39011417b1cfde8f1749905f2d735623af9214148afJeff Brown            DrawableCompat.jumpToCurrentState(mRemoteIndicator);
39111417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
39211417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
39311417b1cfde8f1749905f2d735623af9214148afJeff Brown
39411417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
39511417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void setVisibility(int visibility) {
39611417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.setVisibility(visibility);
39711417b1cfde8f1749905f2d735623af9214148afJeff Brown
39811417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
39911417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
40011417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
40111417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
40211417b1cfde8f1749905f2d735623af9214148afJeff Brown
40311417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
40411417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void onAttachedToWindow() {
40511417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.onAttachedToWindow();
40611417b1cfde8f1749905f2d735623af9214148afJeff Brown
40711417b1cfde8f1749905f2d735623af9214148afJeff Brown        mAttachedToWindow = true;
4089942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        if (!mSelector.isEmpty()) {
4099942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            mRouter.addCallback(mSelector, mCallback);
41011417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
4119942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        refreshRoute();
41211417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
41311417b1cfde8f1749905f2d735623af9214148afJeff Brown
41411417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
41511417b1cfde8f1749905f2d735623af9214148afJeff Brown    public void onDetachedFromWindow() {
41611417b1cfde8f1749905f2d735623af9214148afJeff Brown        mAttachedToWindow = false;
4179942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        if (!mSelector.isEmpty()) {
4189942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            mRouter.removeCallback(mCallback);
4199942d40d0d952b03b583fe66f434676793697aa2Jeff Brown        }
42011417b1cfde8f1749905f2d735623af9214148afJeff Brown
42111417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.onDetachedFromWindow();
42211417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
42311417b1cfde8f1749905f2d735623af9214148afJeff Brown
42411417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
42511417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
42611417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
42711417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
42811417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
42911417b1cfde8f1749905f2d735623af9214148afJeff Brown        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
43011417b1cfde8f1749905f2d735623af9214148afJeff Brown
4315a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang        final int width = Math.max(mMinWidth, mRemoteIndicator != null ?
4325a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                mRemoteIndicator.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight() : 0);
4335a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang        final int height = Math.max(mMinHeight, mRemoteIndicator != null ?
4345a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                mRemoteIndicator.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom() : 0);
43511417b1cfde8f1749905f2d735623af9214148afJeff Brown
4365a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang        int measuredWidth;
43711417b1cfde8f1749905f2d735623af9214148afJeff Brown        switch (widthMode) {
43811417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.EXACTLY:
4395a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                measuredWidth = widthSize;
44011417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
44111417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.AT_MOST:
4425a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                measuredWidth = Math.min(widthSize, width);
44311417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
44411417b1cfde8f1749905f2d735623af9214148afJeff Brown            default:
44511417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.UNSPECIFIED:
4465a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                measuredWidth = width;
44711417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
44811417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
44911417b1cfde8f1749905f2d735623af9214148afJeff Brown
4505a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang        int measuredHeight;
45111417b1cfde8f1749905f2d735623af9214148afJeff Brown        switch (heightMode) {
45211417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.EXACTLY:
4535a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                measuredHeight = heightSize;
45411417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
45511417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.AT_MOST:
4565a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                measuredHeight = Math.min(heightSize, height);
45711417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
45811417b1cfde8f1749905f2d735623af9214148afJeff Brown            default:
45911417b1cfde8f1749905f2d735623af9214148afJeff Brown            case MeasureSpec.UNSPECIFIED:
4605a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang                measuredHeight = height;
46111417b1cfde8f1749905f2d735623af9214148afJeff Brown                break;
46211417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
46311417b1cfde8f1749905f2d735623af9214148afJeff Brown
4645a7cd823706ba63d809545516bdbbc6e8ac8b998Dongwon Kang        setMeasuredDimension(measuredWidth, measuredHeight);
46511417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
46611417b1cfde8f1749905f2d735623af9214148afJeff Brown
46711417b1cfde8f1749905f2d735623af9214148afJeff Brown    @Override
46811417b1cfde8f1749905f2d735623af9214148afJeff Brown    protected void onDraw(Canvas canvas) {
46911417b1cfde8f1749905f2d735623af9214148afJeff Brown        super.onDraw(canvas);
47011417b1cfde8f1749905f2d735623af9214148afJeff Brown
47111417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mRemoteIndicator != null) {
47211417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int left = getPaddingLeft();
47311417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int right = getWidth() - getPaddingRight();
47411417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int top = getPaddingTop();
47511417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int bottom = getHeight() - getPaddingBottom();
47611417b1cfde8f1749905f2d735623af9214148afJeff Brown
47711417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
47811417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
47911417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawLeft = left + (right - left - drawWidth) / 2;
48011417b1cfde8f1749905f2d735623af9214148afJeff Brown            final int drawTop = top + (bottom - top - drawHeight) / 2;
48111417b1cfde8f1749905f2d735623af9214148afJeff Brown
48211417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.setBounds(drawLeft, drawTop,
48311417b1cfde8f1749905f2d735623af9214148afJeff Brown                    drawLeft + drawWidth, drawTop + drawHeight);
48411417b1cfde8f1749905f2d735623af9214148afJeff Brown            mRemoteIndicator.draw(canvas);
48511417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
48611417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
48711417b1cfde8f1749905f2d735623af9214148afJeff Brown
488e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas    void refreshRoute() {
48911417b1cfde8f1749905f2d735623af9214148afJeff Brown        if (mAttachedToWindow) {
4909942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
491fa19abbe11335366feb6c885f8d75504ab8fe4f9Insun Kang            final boolean isRemote = !route.isDefaultOrBluetooth()
492fa19abbe11335366feb6c885f8d75504ab8fe4f9Insun Kang                    && route.matchesSelector(mSelector);
4939942d40d0d952b03b583fe66f434676793697aa2Jeff Brown            final boolean isConnecting = isRemote && route.isConnecting();
49411417b1cfde8f1749905f2d735623af9214148afJeff Brown
49511417b1cfde8f1749905f2d735623af9214148afJeff Brown            boolean needsRefresh = false;
49611417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mRemoteActive != isRemote) {
49711417b1cfde8f1749905f2d735623af9214148afJeff Brown                mRemoteActive = isRemote;
49811417b1cfde8f1749905f2d735623af9214148afJeff Brown                needsRefresh = true;
49911417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
50011417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (mIsConnecting != isConnecting) {
50111417b1cfde8f1749905f2d735623af9214148afJeff Brown                mIsConnecting = isConnecting;
50211417b1cfde8f1749905f2d735623af9214148afJeff Brown                needsRefresh = true;
50311417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
50411417b1cfde8f1749905f2d735623af9214148afJeff Brown
50511417b1cfde8f1749905f2d735623af9214148afJeff Brown            if (needsRefresh) {
506a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho                updateContentDescription();
50711417b1cfde8f1749905f2d735623af9214148afJeff Brown                refreshDrawableState();
5086dc709cd8ea483663e1a9d6730e081eb82bdb02aSungsoo Lim                if (mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
50939dd5560fa1d7ed609dba6945b2579619c9af5b4Sungsoo Lim                    AnimationDrawable curDrawable =
51039dd5560fa1d7ed609dba6945b2579619c9af5b4Sungsoo Lim                            (AnimationDrawable) mRemoteIndicator.getCurrent();
51139dd5560fa1d7ed609dba6945b2579619c9af5b4Sungsoo Lim                    if (!curDrawable.isRunning()) {
51239dd5560fa1d7ed609dba6945b2579619c9af5b4Sungsoo Lim                        curDrawable.start();
51339dd5560fa1d7ed609dba6945b2579619c9af5b4Sungsoo Lim                    }
51439dd5560fa1d7ed609dba6945b2579619c9af5b4Sungsoo Lim                }
51511417b1cfde8f1749905f2d735623af9214148afJeff Brown            }
516dffce799b08cbea89247cffc19c8f91bc592ec81Sungsoo Lim
517dffce799b08cbea89247cffc19c8f91bc592ec81Sungsoo Lim            setEnabled(mRouter.isRouteAvailable(mSelector,
518dffce799b08cbea89247cffc19c8f91bc592ec81Sungsoo Lim                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
51911417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
52011417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
52111417b1cfde8f1749905f2d735623af9214148afJeff Brown
522a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho    private void updateContentDescription() {
523a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        int resId;
524a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        if (mIsConnecting) {
525a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho            resId = R.string.mr_cast_button_connecting;
526a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        } else if (mRemoteActive) {
527a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho            resId = R.string.mr_cast_button_connected;
528a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        } else {
529a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho            resId = R.string.mr_cast_button_disconnected;
530a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        }
531a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho        setContentDescription(getContext().getString(resId));
532a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho    }
533a4667c7f746b153a401442f41ecd94a2487419ffDonghyun Cho
53411417b1cfde8f1749905f2d735623af9214148afJeff Brown    private final class MediaRouterCallback extends MediaRouter.Callback {
535e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        MediaRouterCallback() {
536e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas        }
537e2c6a94b6e4aab502f9b88dd3ff664bd90b25839Aurimas Liutikas
53811417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
53911417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
54011417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
54111417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
54211417b1cfde8f1749905f2d735623af9214148afJeff Brown
54311417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
54411417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
54511417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
54611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
54711417b1cfde8f1749905f2d735623af9214148afJeff Brown
54811417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
54911417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
55011417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
55111417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
55211417b1cfde8f1749905f2d735623af9214148afJeff Brown
55311417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
55411417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
55511417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
55611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
55711417b1cfde8f1749905f2d735623af9214148afJeff Brown
55811417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
55911417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
56011417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
56111417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
56211417b1cfde8f1749905f2d735623af9214148afJeff Brown
56311417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
56411417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onProviderAdded(MediaRouter router, MediaRouter.ProviderInfo provider) {
56511417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
56611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
56711417b1cfde8f1749905f2d735623af9214148afJeff Brown
56811417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
56911417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onProviderRemoved(MediaRouter router, MediaRouter.ProviderInfo provider) {
57011417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
57111417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
57211417b1cfde8f1749905f2d735623af9214148afJeff Brown
57311417b1cfde8f1749905f2d735623af9214148afJeff Brown        @Override
57411417b1cfde8f1749905f2d735623af9214148afJeff Brown        public void onProviderChanged(MediaRouter router, MediaRouter.ProviderInfo provider) {
57511417b1cfde8f1749905f2d735623af9214148afJeff Brown            refreshRoute();
57611417b1cfde8f1749905f2d735623af9214148afJeff Brown        }
57711417b1cfde8f1749905f2d735623af9214148afJeff Brown    }
57811417b1cfde8f1749905f2d735623af9214148afJeff Brown}
579