MediaRouteButton.java revision 0bfa950527f7b5b44658d32346fd444073b8b6d8
1692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim/*
2692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * Copyright 2018 The Android Open Source Project
3692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim *
4692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * Licensed under the Apache License, Version 2.0 (the "License");
5692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * you may not use this file except in compliance with the License.
6692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * You may obtain a copy of the License at
7692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim *
8692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim *      http://www.apache.org/licenses/LICENSE-2.0
9692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim *
10692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * Unless required by applicable law or agreed to in writing, software
11692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * distributed under the License is distributed on an "AS IS" BASIS,
12692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * See the License for the specific language governing permissions and
14692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * limitations under the License.
15692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim */
16692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
17692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limpackage com.android.support.mediarouter.app;
18692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
19692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.annotation.NonNull;
20692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.app.Activity;
210bfa950527f7b5b44658d32346fd444073b8b6d8Sungsoo Limimport android.app.FragmentManager;
22692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.content.Context;
23692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.content.ContextWrapper;
24692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.content.res.ColorStateList;
25f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Limimport android.content.res.Resources;
26692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.content.res.TypedArray;
27692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.graphics.Canvas;
28692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.graphics.drawable.AnimationDrawable;
29692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.graphics.drawable.Drawable;
30692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.os.AsyncTask;
31692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.support.v4.graphics.drawable.DrawableCompat;
32692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.support.v7.widget.TooltipCompat;
33692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.util.AttributeSet;
34692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.util.Log;
35692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.util.SparseArray;
36692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.view.SoundEffectConstants;
37692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport android.view.View;
38692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
39f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Limimport com.android.media.update.ApiHelper;
40692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport com.android.media.update.R;
41692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport com.android.support.mediarouter.media.MediaRouteSelector;
42692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limimport com.android.support.mediarouter.media.MediaRouter;
43692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
44692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim/**
45692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * The media route button allows the user to select routes and to control the
46692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * currently selected route.
47692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * <p>
48692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * The application must specify the kinds of routes that the user should be allowed
49692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * to select by specifying a {@link MediaRouteSelector selector} with the
50692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * {@link #setRouteSelector} method.
51692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * </p><p>
52692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * When the default route is selected or when the currently selected route does not
53692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * match the {@link #getRouteSelector() selector}, the button will appear in
54692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * an inactive state indicating that the application is not connected to a
55692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * route of the kind that it wants to use.  Clicking on the button opens
56692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * a {@link MediaRouteChooserDialog} to allow the user to select a route.
57692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * If no non-default routes match the selector and it is not possible for an active
58692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * scan to discover any matching routes, then the button is disabled and cannot
59692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * be clicked.
60692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * </p><p>
61692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * When a non-default route is selected that matches the selector, the button will
62692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * appear in an active state indicating that the application is connected
63692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * to a route of the kind that it wants to use.  The button may also appear
64692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * in an intermediary connecting state if the route is in the process of connecting
65692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * to the destination but has not yet completed doing so.  In either case, clicking
66692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * on the button opens a {@link MediaRouteControllerDialog} to allow the user
67692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * to control or disconnect from the current route.
68692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * </p>
69692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim *
70692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * <h3>Prerequisites</h3>
71692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * <p>
72692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * To use the media route button, the activity must be a subclass of
73692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * {@link FragmentActivity} from the <code>android.support.v4</code>
74692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * support library.  Refer to support library documentation for details.
75692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * </p>
76692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim *
77692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * @see MediaRouteActionProvider
78692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim * @see #setRouteSelector
79692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim */
80692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Limpublic class MediaRouteButton extends View {
81692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private static final String TAG = "MediaRouteButton";
82692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
83692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private static final String CHOOSER_FRAGMENT_TAG =
84692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            "android.support.v7.mediarouter:MediaRouteChooserDialogFragment";
85692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private static final String CONTROLLER_FRAGMENT_TAG =
86692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            "android.support.v7.mediarouter:MediaRouteControllerDialogFragment";
87692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
88692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private final MediaRouter mRouter;
89692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private final MediaRouterCallback mCallback;
90692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
91692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private MediaRouteSelector mSelector = MediaRouteSelector.EMPTY;
92839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim    private int mRouteCallbackFlags;
93692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private MediaRouteDialogFactory mDialogFactory = MediaRouteDialogFactory.getDefault();
94692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
95692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private boolean mAttachedToWindow;
96692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
97692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private static final SparseArray<Drawable.ConstantState> sRemoteIndicatorCache =
98692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            new SparseArray<>(2);
99692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private RemoteIndicatorLoader mRemoteIndicatorLoader;
100692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private Drawable mRemoteIndicator;
101692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private boolean mRemoteActive;
102692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private boolean mIsConnecting;
103692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
104692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private ColorStateList mButtonTint;
105692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private int mMinWidth;
106692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private int mMinHeight;
107692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
108692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    // The checked state is used when connected to a remote route.
109692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private static final int[] CHECKED_STATE_SET = {
110692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        android.R.attr.state_checked
111692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    };
112692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
113692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    // The checkable state is used while connecting to a remote route.
114692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private static final int[] CHECKABLE_STATE_SET = {
115692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        android.R.attr.state_checkable
116692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    };
117692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
118692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public MediaRouteButton(Context context) {
119692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        this(context, null);
120692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
121692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
122692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public MediaRouteButton(Context context, AttributeSet attrs) {
123692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        this(context, attrs, R.attr.mediaRouteButtonStyle);
124692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
125692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
126692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) {
127692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super(MediaRouterThemeHelper.createThemedButtonContext(context), attrs, defStyleAttr);
128692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        context = getContext();
129692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
130692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mRouter = MediaRouter.getInstance(context);
131692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mCallback = new MediaRouterCallback();
132692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
133f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim        Resources.Theme theme = ApiHelper.getLibResources().newTheme();
134f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim        theme.applyStyle(MediaRouterThemeHelper.getRouterThemeId(context), true);
135f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim        TypedArray a = theme.obtainStyledAttributes(attrs,
136692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                R.styleable.MediaRouteButton, defStyleAttr, 0);
137f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim
138692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mButtonTint = a.getColorStateList(R.styleable.MediaRouteButton_mediaRouteButtonTint);
139692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mMinWidth = a.getDimensionPixelSize(
140692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                R.styleable.MediaRouteButton_android_minWidth, 0);
141692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mMinHeight = a.getDimensionPixelSize(
142692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                R.styleable.MediaRouteButton_android_minHeight, 0);
143692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int remoteIndicatorResId = a.getResourceId(
144692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                R.styleable.MediaRouteButton_externalRouteEnabledDrawable, 0);
145692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        a.recycle();
146692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
147692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (remoteIndicatorResId != 0) {
148692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            Drawable.ConstantState remoteIndicatorState =
149692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    sRemoteIndicatorCache.get(remoteIndicatorResId);
150692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (remoteIndicatorState != null) {
151692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                setRemoteIndicatorDrawable(remoteIndicatorState.newDrawable());
152692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            } else {
153692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                mRemoteIndicatorLoader = new RemoteIndicatorLoader(remoteIndicatorResId);
154692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                mRemoteIndicatorLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
155692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
156692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
157692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
158692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        updateContentDescription();
159692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        setClickable(true);
160692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
161692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
162692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
163692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Gets the media route selector for filtering the routes that the user can
164692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * select using the media route chooser dialog.
165692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     *
166692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * @return The selector, never null.
167692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
168692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @NonNull
169692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public MediaRouteSelector getRouteSelector() {
170692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return mSelector;
171692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
172692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
173692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
174692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Sets the media route selector for filtering the routes that the user can
175692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * select using the media route chooser dialog.
176692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     *
177839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     * @param selector The selector.
178692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
179692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void setRouteSelector(MediaRouteSelector selector) {
180839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        setRouteSelector(selector, 0);
181839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim    }
182839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim
183839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim    /**
184839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     * Sets the media route selector for filtering the routes that the user can
185839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     * select using the media route chooser dialog.
186839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     *
187839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     * @param selector The selector.
188839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     * @param flags Flags to control the behavior of the callback. May be zero or a combination of
189839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     *              {@link #MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN} and
190839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     *              {@link #MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS}.
191839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim     */
192839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim    public void setRouteSelector(MediaRouteSelector selector, int flags) {
193839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        if (mSelector.equals(selector) && mRouteCallbackFlags == flags) {
194839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            return;
195839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        }
196839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        if (!mSelector.isEmpty()) {
197839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            mRouter.removeCallback(mCallback);
198839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        }
199839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        if (selector == null || selector.isEmpty()) {
200839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            mSelector = MediaRouteSelector.EMPTY;
201839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            return;
202692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
203692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
204839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        mSelector = selector;
205839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        mRouteCallbackFlags = flags;
206839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim
207839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim        if (mAttachedToWindow) {
208839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            mRouter.addCallback(selector, mCallback, flags);
209692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
210692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
211692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
212692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
213692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
214692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Gets the media route dialog factory to use when showing the route chooser
215692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * or controller dialog.
216692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     *
217692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * @return The dialog factory, never null.
218692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
219692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @NonNull
220692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public MediaRouteDialogFactory getDialogFactory() {
221692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return mDialogFactory;
222692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
223692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
224692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
225692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Sets the media route dialog factory to use when showing the route chooser
226692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * or controller dialog.
227692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     *
228692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * @param factory The dialog factory, must not be null.
229692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
230692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void setDialogFactory(@NonNull MediaRouteDialogFactory factory) {
231692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (factory == null) {
232692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            throw new IllegalArgumentException("factory must not be null");
233692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
234692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
235692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mDialogFactory = factory;
236692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
237692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
238692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
239692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Show the route chooser or controller dialog.
240692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * <p>
241692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * If the default route is selected or if the currently selected route does
242692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * not match the {@link #getRouteSelector selector}, then shows the route chooser dialog.
243692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Otherwise, shows the route controller dialog to offer the user
244692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * a choice to disconnect from the route or perform other control actions
245692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * such as setting the route's volume.
246692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * </p><p>
247692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * The application can customize the dialogs by calling {@link #setDialogFactory}
248692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * to provide a customized dialog factory.
249692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * </p>
250692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     *
251692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * @return True if the dialog was actually shown.
252692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     *
253692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * @throws IllegalStateException if the activity is not a subclass of
254692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * {@link FragmentActivity}.
255692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
256692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public boolean showDialog() {
257692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!mAttachedToWindow) {
258692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            return false;
259692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
260692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
2610bfa950527f7b5b44658d32346fd444073b8b6d8Sungsoo Lim        final FragmentManager fm = getActivity().getFragmentManager();
262692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (fm == null) {
263692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            throw new IllegalStateException("The activity must be a subclass of FragmentActivity");
264692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
265692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
266692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
267692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (route.isDefaultOrBluetooth() || !route.matchesSelector(mSelector)) {
268692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) {
269692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                Log.w(TAG, "showDialog(): Route chooser dialog already showing!");
270692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                return false;
271692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
272692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            MediaRouteChooserDialogFragment f =
273692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    mDialogFactory.onCreateChooserDialogFragment();
274692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            f.setRouteSelector(mSelector);
275692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            f.show(fm, CHOOSER_FRAGMENT_TAG);
276692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else {
277692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) {
278692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                Log.w(TAG, "showDialog(): Route controller dialog already showing!");
279692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                return false;
280692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
281692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            MediaRouteControllerDialogFragment f =
282692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    mDialogFactory.onCreateControllerDialogFragment();
283692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            f.show(fm, CONTROLLER_FRAGMENT_TAG);
284692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
285692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return true;
286692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
287692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
288692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
289692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private Activity getActivity() {
290692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Gross way of unwrapping the Activity so we can get the FragmentManager
291692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        Context context = getContext();
292692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        while (context instanceof ContextWrapper) {
293692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (context instanceof Activity) {
294692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                return (Activity)context;
295692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
296692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            context = ((ContextWrapper)context).getBaseContext();
297692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
298692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return null;
299692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
300692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
301692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
302692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Sets whether to enable showing a toast with the content descriptor of the
303692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * button when the button is long pressed.
304692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
305692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    void setCheatSheetEnabled(boolean enable) {
306f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim        TooltipCompat.setTooltipText(this, enable
307f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim                ? ApiHelper.getLibResources().getString(R.string.mr_button_content_description)
308f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim                : null);
309692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
310692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
311692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
312692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public boolean performClick() {
313692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Send the appropriate accessibility events and call listeners
314692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        boolean handled = super.performClick();
315692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!handled) {
316692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            playSoundEffect(SoundEffectConstants.CLICK);
317692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
318692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return showDialog() || handled;
319692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
320692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
321692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
322692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected int[] onCreateDrawableState(int extraSpace) {
323692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
324692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
325692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Technically we should be handling this more completely, but these
326692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // are implementation details here. Checkable is used to express the connecting
327692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // drawable state and it's mutually exclusive with check for the purposes
328692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // of state selection here.
329692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mIsConnecting) {
330692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mergeDrawableStates(drawableState, CHECKABLE_STATE_SET);
331692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else if (mRemoteActive) {
332692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
333692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
334692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return drawableState;
335692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
336692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
337692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
338692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected void drawableStateChanged() {
339692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.drawableStateChanged();
340692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
341692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
342692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            int[] myDrawableState = getDrawableState();
343692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setState(myDrawableState);
344692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            invalidate();
345692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
346692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
347692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
348692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
349692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Sets a drawable to use as the remote route indicator.
350692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
351692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void setRemoteIndicatorDrawable(Drawable d) {
352692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicatorLoader != null) {
353692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicatorLoader.cancel(false);
354692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
355692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
356692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
357692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setCallback(null);
358692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            unscheduleDrawable(mRemoteIndicator);
359692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
360692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (d != null) {
361692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (mButtonTint != null) {
362692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                d = DrawableCompat.wrap(d.mutate());
363692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                DrawableCompat.setTintList(d, mButtonTint);
364692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
365692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            d.setCallback(this);
366692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            d.setState(getDrawableState());
367692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            d.setVisible(getVisibility() == VISIBLE, false);
368692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
369692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mRemoteIndicator = d;
370692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
371692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        refreshDrawableState();
372692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mAttachedToWindow && mRemoteIndicator != null
373692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                && mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
374692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            AnimationDrawable curDrawable = (AnimationDrawable) mRemoteIndicator.getCurrent();
375692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (mIsConnecting) {
376692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if (!curDrawable.isRunning()) {
377692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.start();
378692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
379692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            } else if (mRemoteActive) {
380692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if (curDrawable.isRunning()) {
381692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.stop();
382692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
383692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                curDrawable.selectDrawable(curDrawable.getNumberOfFrames() - 1);
384692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
385692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
386692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
387692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
388692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
389692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected boolean verifyDrawable(Drawable who) {
390692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return super.verifyDrawable(who) || who == mRemoteIndicator;
391692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
392692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
393692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
394692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void jumpDrawablesToCurrentState() {
395692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // We can't call super to handle the background so we do it ourselves.
396692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        //super.jumpDrawablesToCurrentState();
397692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (getBackground() != null) {
398692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            DrawableCompat.jumpToCurrentState(getBackground());
399692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
400692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
401692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Handle our own remote indicator.
402692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
403692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            DrawableCompat.jumpToCurrentState(mRemoteIndicator);
404692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
405692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
406692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
407692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
408692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void setVisibility(int visibility) {
409692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.setVisibility(visibility);
410692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
411692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
412692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
413692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
414692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
415692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
416692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
417692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void onAttachedToWindow() {
418692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.onAttachedToWindow();
419692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
420692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mAttachedToWindow = true;
421692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!mSelector.isEmpty()) {
422839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            mRouter.addCallback(mSelector, mCallback, mRouteCallbackFlags);
423692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
424692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        refreshRoute();
425692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
426692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
427692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
428692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void onDetachedFromWindow() {
429692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mAttachedToWindow = false;
430692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!mSelector.isEmpty()) {
431692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRouter.removeCallback(mCallback);
432692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
433692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
434692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.onDetachedFromWindow();
435692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
436692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
437692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
438692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
439692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
440692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
441692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
442692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
443692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
444692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int width = Math.max(mMinWidth, mRemoteIndicator != null ?
445692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                mRemoteIndicator.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight() : 0);
446692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int height = Math.max(mMinHeight, mRemoteIndicator != null ?
447692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                mRemoteIndicator.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom() : 0);
448692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
449692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int measuredWidth;
450692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        switch (widthMode) {
451692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.EXACTLY:
452692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredWidth = widthSize;
453692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
454692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.AT_MOST:
455692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredWidth = Math.min(widthSize, width);
456692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
457692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            default:
458692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.UNSPECIFIED:
459692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredWidth = width;
460692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
461692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
462692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
463692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int measuredHeight;
464692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        switch (heightMode) {
465692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.EXACTLY:
466692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredHeight = heightSize;
467692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
468692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.AT_MOST:
469692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredHeight = Math.min(heightSize, height);
470692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
471692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            default:
472692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.UNSPECIFIED:
473692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredHeight = height;
474692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
475692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
476692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
477692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        setMeasuredDimension(measuredWidth, measuredHeight);
478692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
479692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
480692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
481692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected void onDraw(Canvas canvas) {
482692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.onDraw(canvas);
483692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
484692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
485692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int left = getPaddingLeft();
486692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int right = getWidth() - getPaddingRight();
487692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int top = getPaddingTop();
488692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int bottom = getHeight() - getPaddingBottom();
489692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
490692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
491692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
492692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawLeft = left + (right - left - drawWidth) / 2;
493692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawTop = top + (bottom - top - drawHeight) / 2;
494692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
495692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setBounds(drawLeft, drawTop,
496692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    drawLeft + drawWidth, drawTop + drawHeight);
497692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.draw(canvas);
498692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
499692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
500692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
501692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    void refreshRoute() {
502692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
503692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final boolean isRemote = !route.isDefaultOrBluetooth() && route.matchesSelector(mSelector);
504692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final boolean isConnecting = isRemote && route.isConnecting();
505692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        boolean needsRefresh = false;
506692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteActive != isRemote) {
507692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteActive = isRemote;
508692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            needsRefresh = true;
509692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
510692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mIsConnecting != isConnecting) {
511692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mIsConnecting = isConnecting;
512692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            needsRefresh = true;
513692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
514692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
515692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (needsRefresh) {
516692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            updateContentDescription();
517692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshDrawableState();
518692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
519692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mAttachedToWindow) {
520692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            setEnabled(mRouter.isRouteAvailable(mSelector,
521692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
522692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
523692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null
524692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                && mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
525692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            AnimationDrawable curDrawable = (AnimationDrawable) mRemoteIndicator.getCurrent();
526692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (mAttachedToWindow) {
527692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if ((needsRefresh || isConnecting) && !curDrawable.isRunning()) {
528692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.start();
529692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
530692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            } else if (isRemote && !isConnecting) {
531692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                // When the route is already connected before the view is attached, show the last
532692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                // frame of the connected animation immediately.
533692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if (curDrawable.isRunning()) {
534692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.stop();
535692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
536692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                curDrawable.selectDrawable(curDrawable.getNumberOfFrames() - 1);
537692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
538692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
539692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
540692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
541692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private void updateContentDescription() {
542692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int resId;
543692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mIsConnecting) {
544692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            resId = R.string.mr_cast_button_connecting;
545692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else if (mRemoteActive) {
546692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            resId = R.string.mr_cast_button_connected;
547692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else {
548692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            resId = R.string.mr_cast_button_disconnected;
549692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
550f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim        setContentDescription(ApiHelper.getLibResources().getString(resId));
551692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
552692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
553692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private final class MediaRouterCallback extends MediaRouter.Callback {
554692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        MediaRouterCallback() {
555692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
556692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
557692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
558692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
559692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
560692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
561692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
562692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
563692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
564692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
565692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
566692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
567692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
568692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
569692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
570692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
571692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
572692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
573692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
574692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
575692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
576692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
577692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
578692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
579692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
580692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
581692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
582692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
583692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onProviderAdded(MediaRouter router, MediaRouter.ProviderInfo provider) {
584692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
585692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
586692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
587692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
588692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onProviderRemoved(MediaRouter router, MediaRouter.ProviderInfo provider) {
589692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
590692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
591692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
592692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
593692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onProviderChanged(MediaRouter router, MediaRouter.ProviderInfo provider) {
594692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
595692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
596692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
597692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
598692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private final class RemoteIndicatorLoader extends AsyncTask<Void, Void, Drawable> {
599692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        private final int mResId;
600692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
601692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        RemoteIndicatorLoader(int resId) {
602692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mResId = resId;
603692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
604692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
605692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
606692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        protected Drawable doInBackground(Void... params) {
607f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim            return ApiHelper.getLibResources().getDrawable(mResId);
608692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
609692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
610692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
611692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        protected void onPostExecute(Drawable remoteIndicator) {
612692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            cacheAndReset(remoteIndicator);
613692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            setRemoteIndicatorDrawable(remoteIndicator);
614692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
615692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
616692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
617692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        protected void onCancelled(Drawable remoteIndicator) {
618692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            cacheAndReset(remoteIndicator);
619692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
620692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
621692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        private void cacheAndReset(Drawable remoteIndicator) {
622692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (remoteIndicator != null) {
623692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                sRemoteIndicatorCache.put(mResId, remoteIndicator.getConstantState());
624692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
625692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicatorLoader = null;
626692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
627692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
628692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim}
629