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
13392fd9a9e07a33a01d12ef9c47f73b2c7193a5fd9Christofer Ã…kersten        Resources.Theme theme = ApiHelper.getLibResources(context).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
30792fd9a9e07a33a01d12ef9c47f73b2c7193a5fd9Christofer Ã…kersten                ? ApiHelper.getLibResources(getContext())
30892fd9a9e07a33a01d12ef9c47f73b2c7193a5fd9Christofer Ã…kersten                    .getString(R.string.mr_button_content_description)
309f77d2e6b97a9ce69164387eb5c7c6168f7f569ccSungsoo Lim                : null);
310692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
311692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
312692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
313692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public boolean performClick() {
314692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Send the appropriate accessibility events and call listeners
315692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        boolean handled = super.performClick();
316692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!handled) {
317692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            playSoundEffect(SoundEffectConstants.CLICK);
318692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
319692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return showDialog() || handled;
320692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
321692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
322692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
323692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected int[] onCreateDrawableState(int extraSpace) {
324692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
325692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
326692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Technically we should be handling this more completely, but these
327692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // are implementation details here. Checkable is used to express the connecting
328692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // drawable state and it's mutually exclusive with check for the purposes
329692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // of state selection here.
330692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mIsConnecting) {
331692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mergeDrawableStates(drawableState, CHECKABLE_STATE_SET);
332692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else if (mRemoteActive) {
333692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
334692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
335692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return drawableState;
336692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
337692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
338692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
339692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected void drawableStateChanged() {
340692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.drawableStateChanged();
341692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
342692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
343692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            int[] myDrawableState = getDrawableState();
344692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setState(myDrawableState);
345692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            invalidate();
346692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
347692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
348692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
349692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    /**
350692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     * Sets a drawable to use as the remote route indicator.
351692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim     */
352692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void setRemoteIndicatorDrawable(Drawable d) {
353692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicatorLoader != null) {
354692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicatorLoader.cancel(false);
355692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
356692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
357692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
358692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setCallback(null);
359692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            unscheduleDrawable(mRemoteIndicator);
360692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
361692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (d != null) {
362692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (mButtonTint != null) {
363692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                d = DrawableCompat.wrap(d.mutate());
364692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                DrawableCompat.setTintList(d, mButtonTint);
365692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
366692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            d.setCallback(this);
367692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            d.setState(getDrawableState());
368692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            d.setVisible(getVisibility() == VISIBLE, false);
369692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
370692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mRemoteIndicator = d;
371692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
372692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        refreshDrawableState();
373692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mAttachedToWindow && mRemoteIndicator != null
374692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                && mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
375692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            AnimationDrawable curDrawable = (AnimationDrawable) mRemoteIndicator.getCurrent();
376692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (mIsConnecting) {
377692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if (!curDrawable.isRunning()) {
378692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.start();
379692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
380692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            } else if (mRemoteActive) {
381692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if (curDrawable.isRunning()) {
382692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.stop();
383692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
384692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                curDrawable.selectDrawable(curDrawable.getNumberOfFrames() - 1);
385692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
386692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
387692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
388692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
389692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
390692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected boolean verifyDrawable(Drawable who) {
391692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        return super.verifyDrawable(who) || who == mRemoteIndicator;
392692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
393692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
394692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
395692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void jumpDrawablesToCurrentState() {
396692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // We can't call super to handle the background so we do it ourselves.
397692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        //super.jumpDrawablesToCurrentState();
398692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (getBackground() != null) {
399692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            DrawableCompat.jumpToCurrentState(getBackground());
400692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
401692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
402692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        // Handle our own remote indicator.
403692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
404692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            DrawableCompat.jumpToCurrentState(mRemoteIndicator);
405692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
406692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
407692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
408692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
409692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void setVisibility(int visibility) {
410692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.setVisibility(visibility);
411692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
412692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
413692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setVisible(getVisibility() == VISIBLE, false);
414692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
415692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
416692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
417692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
418692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void onAttachedToWindow() {
419692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.onAttachedToWindow();
420692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
421692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mAttachedToWindow = true;
422692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!mSelector.isEmpty()) {
423839daf18d567c0cd5982ba7baf4c433d55e875a5Sungsoo Lim            mRouter.addCallback(mSelector, mCallback, mRouteCallbackFlags);
424692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
425692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        refreshRoute();
426692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
427692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
428692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
429692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    public void onDetachedFromWindow() {
430692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        mAttachedToWindow = false;
431692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (!mSelector.isEmpty()) {
432692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRouter.removeCallback(mCallback);
433692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
434692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
435692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.onDetachedFromWindow();
436692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
437692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
438692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
439692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
440692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
441692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
442692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
443692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
444692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
445692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int width = Math.max(mMinWidth, mRemoteIndicator != null ?
446692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                mRemoteIndicator.getIntrinsicWidth() + getPaddingLeft() + getPaddingRight() : 0);
447692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final int height = Math.max(mMinHeight, mRemoteIndicator != null ?
448692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                mRemoteIndicator.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom() : 0);
449692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
450692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int measuredWidth;
451692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        switch (widthMode) {
452692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.EXACTLY:
453692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredWidth = widthSize;
454692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
455692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.AT_MOST:
456692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredWidth = Math.min(widthSize, width);
457692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
458692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            default:
459692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.UNSPECIFIED:
460692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredWidth = width;
461692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
462692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
463692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
464692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int measuredHeight;
465692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        switch (heightMode) {
466692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.EXACTLY:
467692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredHeight = heightSize;
468692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
469692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.AT_MOST:
470692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredHeight = Math.min(heightSize, height);
471692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
472692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            default:
473692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            case MeasureSpec.UNSPECIFIED:
474692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                measuredHeight = height;
475692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                break;
476692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
477692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
478692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        setMeasuredDimension(measuredWidth, measuredHeight);
479692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
480692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
481692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    @Override
482692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    protected void onDraw(Canvas canvas) {
483692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        super.onDraw(canvas);
484692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
485692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null) {
486692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int left = getPaddingLeft();
487692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int right = getWidth() - getPaddingRight();
488692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int top = getPaddingTop();
489692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int bottom = getHeight() - getPaddingBottom();
490692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
491692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawWidth = mRemoteIndicator.getIntrinsicWidth();
492692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawHeight = mRemoteIndicator.getIntrinsicHeight();
493692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawLeft = left + (right - left - drawWidth) / 2;
494692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            final int drawTop = top + (bottom - top - drawHeight) / 2;
495692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
496692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.setBounds(drawLeft, drawTop,
497692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    drawLeft + drawWidth, drawTop + drawHeight);
498692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicator.draw(canvas);
499692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
500692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
501692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
502692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    void refreshRoute() {
503692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final MediaRouter.RouteInfo route = mRouter.getSelectedRoute();
504692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final boolean isRemote = !route.isDefaultOrBluetooth() && route.matchesSelector(mSelector);
505692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        final boolean isConnecting = isRemote && route.isConnecting();
506692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        boolean needsRefresh = false;
507692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteActive != isRemote) {
508692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteActive = isRemote;
509692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            needsRefresh = true;
510692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
511692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mIsConnecting != isConnecting) {
512692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mIsConnecting = isConnecting;
513692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            needsRefresh = true;
514692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
515692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
516692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (needsRefresh) {
517692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            updateContentDescription();
518692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshDrawableState();
519692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
520692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mAttachedToWindow) {
521692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            setEnabled(mRouter.isRouteAvailable(mSelector,
522692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    MediaRouter.AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE));
523692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
524692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mRemoteIndicator != null
525692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                && mRemoteIndicator.getCurrent() instanceof AnimationDrawable) {
526692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            AnimationDrawable curDrawable = (AnimationDrawable) mRemoteIndicator.getCurrent();
527692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (mAttachedToWindow) {
528692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if ((needsRefresh || isConnecting) && !curDrawable.isRunning()) {
529692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.start();
530692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
531692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            } else if (isRemote && !isConnecting) {
532692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                // When the route is already connected before the view is attached, show the last
533692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                // frame of the connected animation immediately.
534692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                if (curDrawable.isRunning()) {
535692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                    curDrawable.stop();
536692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                }
537692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                curDrawable.selectDrawable(curDrawable.getNumberOfFrames() - 1);
538692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
539692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
540692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
541692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
542692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private void updateContentDescription() {
543692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        int resId;
544692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        if (mIsConnecting) {
545692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            resId = R.string.mr_cast_button_connecting;
546692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else if (mRemoteActive) {
547692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            resId = R.string.mr_cast_button_connected;
548692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        } else {
549692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            resId = R.string.mr_cast_button_disconnected;
550692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
55192fd9a9e07a33a01d12ef9c47f73b2c7193a5fd9Christofer Ã…kersten        setContentDescription(ApiHelper.getLibResources(getContext()).getString(resId));
552692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
553692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
554692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private final class MediaRouterCallback extends MediaRouter.Callback {
555692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        MediaRouterCallback() {
556692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
557692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
558692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
559692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo info) {
560692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
561692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
562692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
563692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
564692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo info) {
565692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
566692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
567692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
568692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
569692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo info) {
570692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
571692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
572692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
573692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
574692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
575692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
576692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
577692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
578692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
579692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
580692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
581692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
582692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
583692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
584692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onProviderAdded(MediaRouter router, MediaRouter.ProviderInfo provider) {
585692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
586692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
587692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
588692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
589692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onProviderRemoved(MediaRouter router, MediaRouter.ProviderInfo provider) {
590692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
591692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
592692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
593692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
594692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        public void onProviderChanged(MediaRouter router, MediaRouter.ProviderInfo provider) {
595692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            refreshRoute();
596692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
597692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
598692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
599692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    private final class RemoteIndicatorLoader extends AsyncTask<Void, Void, Drawable> {
600692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        private final int mResId;
601692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
602692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        RemoteIndicatorLoader(int resId) {
603692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mResId = resId;
604692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
605692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
606692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
607692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        protected Drawable doInBackground(Void... params) {
60892fd9a9e07a33a01d12ef9c47f73b2c7193a5fd9Christofer Ã…kersten            return ApiHelper.getLibResources(getContext()).getDrawable(mResId);
609692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
610692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
611692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
612692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        protected void onPostExecute(Drawable remoteIndicator) {
613692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            cacheAndReset(remoteIndicator);
614692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            setRemoteIndicatorDrawable(remoteIndicator);
615692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
616692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
617692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        @Override
618692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        protected void onCancelled(Drawable remoteIndicator) {
619692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            cacheAndReset(remoteIndicator);
620692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
621692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim
622692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        private void cacheAndReset(Drawable remoteIndicator) {
623692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            if (remoteIndicator != null) {
624692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim                sRemoteIndicatorCache.put(mResId, remoteIndicator.getConstantState());
625692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            }
626692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim            mRemoteIndicatorLoader = null;
627692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim        }
628692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim    }
629692a547730bbc95ad277d5214ef3d786ce1e499fSungsoo Lim}
630