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