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