void refreshRoute() { if (mAttachedToWindow) { final MediaRouter.RouteInfo route = mRouter.getSelectedRoute(); final boolean isRemote = !route.isDefaultOrBluetooth() && route.matchesSelector(mSelector); final boolean isConnecting = isRemote && route.isConnecting(); boolean needsRefresh = false; if (mRemoteActive != isRemote) { mRemoteActive = isRemote; needsRefresh = true; } if (mIsConnecting != isConnecting) { mIsConnecting = isConnecting; needsRefresh = true; } if (needsRefresh) { updateContentDescription(); refreshDrawableState(); if (mRemoteIndicator.getCurrent() instanceof AnimationDrawable) { AnimationDrawable curDrawable = (AnimationDrawable) mRemoteIndicator.getCurrent(); if (!curDrawable.isRunning()) { curDrawable.start(); } } } } }
/** * Show the route chooser or controller dialog. * * <p>If the default route is selected or if the currently selected route does not match the * {@link #getRouteSelector selector}, then shows the route chooser dialog. Otherwise, shows the * route controller dialog to offer the user a choice to disconnect from the route or perform * other control actions such as setting the route's volume. * * <p>The application can customize the dialogs by calling {@link #setDialogFactory} to provide a * customized dialog factory. * * @return True if the dialog was actually shown. * @throws IllegalStateException if the activity is not a subclass of {@link FragmentActivity}. */ public boolean showDialog() { if (!mAttachedToWindow) { return false; } final FragmentManager fm = getFragmentManager(); if (fm == null) { throw new IllegalStateException("The activity must be a subclass of FragmentActivity"); } MediaRouter.RouteInfo route = mRouter.getSelectedRoute(); if (route.isDefaultOrBluetooth() || !route.matchesSelector(mSelector)) { if (fm.findFragmentByTag(CHOOSER_FRAGMENT_TAG) != null) { Log.w(TAG, "showDialog(): Route chooser dialog already showing!"); return false; } MediaRouteChooserDialogFragment f = mDialogFactory.onCreateChooserDialogFragment(); f.setRouteSelector(mSelector); f.show(fm, CHOOSER_FRAGMENT_TAG); } else { if (fm.findFragmentByTag(CONTROLLER_FRAGMENT_TAG) != null) { Log.w(TAG, "showDialog(): Route controller dialog already showing!"); return false; } MediaRouteControllerDialogFragment f = mDialogFactory.onCreateControllerDialogFragment(); f.show(fm, CONTROLLER_FRAGMENT_TAG); } return true; }
@Override public void unregisterRoute(MediaRouter router) { if (mRemoteControl == null) { return; } router.removeRemoteControlClient(mRemoteControl); }
/** * Test method for {@link AbstractMediaRouteController#addMediaStateListener(MediaStateListener)} * and {@link AbstractMediaRouteController#removeMediaStateListener(MediaStateListener)} * * <p>Makes sure that listeners gets notified when they are added and don't get notified when * removed. */ @Test @Feature({"MediaRemote"}) public void testAddRemoveMediaStateListener() { MediaStateListener listener = mock(MediaStateListener.class); MediaStateListener otherListener = mock(MediaStateListener.class); MediaRouter mediaRouter = ShadowMediaRouter.createCapturingMock(); when(mediaRouter.isRouteAvailable(any(MediaRouteSelector.class), anyInt())).thenReturn(true); ShadowMediaRouter.sMediaRouter = mediaRouter; // Creating the MediaRouteController AbstractMediaRouteController mediaRouteController = new DummyMediaRouteController(); assertNotNull(mediaRouteController.getMediaRouter()); // 1. #addMediaStateListener() mediaRouteController.addMediaStateListener(listener); // The route selector should get notified of new states. verify(mediaRouter).addCallback(any(MediaRouteSelector.class), any(Callback.class), anyInt()); verify(listener).onRouteAvailabilityChanged(true); // Check the behavior difference between the first and subsequent additions. mediaRouteController.addMediaStateListener(otherListener); verify(otherListener).onRouteAvailabilityChanged(true); // The call count should not change. verify(mediaRouter).addCallback(any(MediaRouteSelector.class), any(Callback.class), anyInt()); verify(listener).onRouteAvailabilityChanged(true); // 2. #removeMediaStateListener() mediaRouteController.removeMediaStateListener(otherListener); // The removed listener should not be notified of changes anymore. when(mediaRouter.isRouteAvailable(any(MediaRouteSelector.class), anyInt())).thenReturn(false); ShadowMediaRouter.sCallback.onRouteRemoved(mediaRouter, null); verifyNoMoreInteractions(otherListener); verify(listener).onRouteAvailabilityChanged(false); verify(mediaRouter, times(0)).removeCallback(any(Callback.class)); mediaRouteController.removeMediaStateListener(listener); when(mediaRouter.isRouteAvailable(any(MediaRouteSelector.class), anyInt())).thenReturn(true); ShadowMediaRouter.sCallback.onRouteAdded(mediaRouter, null); verifyNoMoreInteractions(otherListener); verifyNoMoreInteractions(listener); verify(mediaRouter).removeCallback(any(Callback.class)); }
@Override public void onDisconnected() { LogHelper.d(TAG, "onDisconnected"); mSessionExtras.remove(EXTRA_CONNECTED_CAST); mSession.setExtras(mSessionExtras); Playback playback = new LocalPlayback(MusicService.this, mMusicProvider); mMediaRouter.setMediaSession(null); switchToPlayer(playback, false); }
@Override public void onDetachedFromWindow() { mAttachedToWindow = false; if (!mSelector.isEmpty()) { mRouter.removeCallback(mCallback); } super.onDetachedFromWindow(); }
/** * Sets the media route selector for filtering the routes that the user can select using the media * route chooser dialog. * * @param selector The selector, must not be null. */ public void setRouteSelector(MediaRouteSelector selector) { if (selector == null) { throw new IllegalArgumentException("selector must not be null"); } if (!mSelector.equals(selector)) { if (mAttachedToWindow) { if (!mSelector.isEmpty()) { mRouter.removeCallback(mCallback); } if (!selector.isEmpty()) { mRouter.addCallback(selector, mCallback); } } mSelector = selector; refreshRoute(); } }
@Override public void onAttachedToWindow() { super.onAttachedToWindow(); mAttachedToWindow = true; if (!mSelector.isEmpty()) { mRouter.addCallback(mSelector, mCallback); } refreshRoute(); }
@Override public void onApplicationConnected( ApplicationMetadata appMetadata, String sessionId, boolean wasLaunched) { // In case we are casting, send the device name as an extra on MediaSession metadata. mSessionExtras.putString(EXTRA_CONNECTED_CAST, mCastManager.getDeviceName()); mSession.setExtras(mSessionExtras); // Now we can switch to CastPlayback Playback playback = new CastPlayback(MusicService.this, mMusicProvider); mMediaRouter.setMediaSession(mSession); switchToPlayer(playback, true); }
/** Test method for {@link AbstractMediaRouteController#isRemotePlaybackAvailable()}. */ @Test @Feature({"MediaRemote"}) public void testIsRemotePlaybackAvailable() { MediaRouter mediaRouter = mock(MediaRouter.class); AbstractMediaRouteController mediaRouteCtrl = new DummyMediaRouteController(); when(mediaRouter.getSelectedRoute()) .thenReturn(createRouteInfo(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)); when(mediaRouter.isRouteAvailable(any(MediaRouteSelector.class), anyInt())).thenReturn(true); // Default assertFalse(mediaRouteCtrl.isRemotePlaybackAvailable()); ShadowMediaRouter.sMediaRouter = mediaRouter; mediaRouteCtrl = spy(new DummyMediaRouteController()); assertTrue(mediaRouteCtrl.isRemotePlaybackAvailable()); when(mediaRouter.getSelectedRoute()) .thenReturn(createRouteInfo(MediaRouter.RouteInfo.PLAYBACK_TYPE_LOCAL)); assertTrue(mediaRouteCtrl.isRemotePlaybackAvailable()); when(mediaRouter.isRouteAvailable(any(MediaRouteSelector.class), anyInt())).thenReturn(false); assertFalse(mediaRouteCtrl.isRemotePlaybackAvailable()); when(mediaRouter.getSelectedRoute()) .thenReturn(createRouteInfo(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)); assertTrue(mediaRouteCtrl.isRemotePlaybackAvailable()); }
public MediaRouteButton(Context context, AttributeSet attrs, int defStyleAttr) { super(MediaRouterThemeHelper.createThemedContext(context, defStyleAttr), attrs, defStyleAttr); context = getContext(); mRouter = MediaRouter.getInstance(context); mCallback = new MediaRouterCallback(); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MediaRouteButton, defStyleAttr, 0); setRemoteIndicatorDrawable( a.getDrawable(R.styleable.MediaRouteButton_externalRouteEnabledDrawable)); mMinWidth = a.getDimensionPixelSize(R.styleable.MediaRouteButton_android_minWidth, 0); mMinHeight = a.getDimensionPixelSize(R.styleable.MediaRouteButton_android_minHeight, 0); a.recycle(); updateContentDescription(); setClickable(true); setLongClickable(true); }
/* * (non-Javadoc) * @see android.app.Service#onCreate() */ @Override public void onCreate() { super.onCreate(); LogHelper.d(TAG, "onCreate"); mPlayingQueue = new ArrayList<>(); mMusicProvider = new MusicProvider(); mPackageValidator = new PackageValidator(this); // Start a new MediaSession mSession = new MediaSession(this, "MusicService"); setSessionToken(mSession.getSessionToken()); mSession.setCallback(new MediaSessionCallback()); mSession.setFlags( MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS); mPlayback = new LocalPlayback(this, mMusicProvider); mPlayback.setState(PlaybackState.STATE_NONE); mPlayback.setCallback(this); mPlayback.start(); Context context = getApplicationContext(); Intent intent = new Intent(context, NowPlayingActivity.class); PendingIntent pi = PendingIntent.getActivity( context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT); mSession.setSessionActivity(pi); mSessionExtras = new Bundle(); CarHelper.setSlotReservationFlags(mSessionExtras, true, true, true); mSession.setExtras(mSessionExtras); updatePlaybackState(null); mMediaNotificationManager = new MediaNotificationManager(this); mCastManager = ((UAMPApplication) getApplication()).getCastManager(getApplicationContext()); mCastManager.addVideoCastConsumer(mCastConsumer); mMediaRouter = MediaRouter.getInstance(getApplicationContext()); }
public void removeFromMediaRouter(MediaRouter router) { if (null != mActualRemoteControlClient) { router.removeRemoteControlClient(mActualRemoteControlClient); } }
/** * Registers with {@link MediaRouter} * * @param router */ public void addToMediaRouter(MediaRouter router) { if (null != mActualRemoteControlClient) { router.addRemoteControlClient(mActualRemoteControlClient); } }
/* * (non-Javadoc) * @see android.app.Service#onCreate() */ @Override public void onCreate() { super.onCreate(); LogHelper.d(TAG, "onCreate"); mPlayingQueue = new ArrayList<>(); mMusicProvider = new MusicProvider(); mPackageValidator = new PackageValidator(this); ComponentName mediaButtonReceiver = new ComponentName(this, RemoteControlReceiver.class); Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mediaButtonReceiver); PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0); // Start a new MediaSessionCompat mSession = new MediaSessionCompat(this, "MusicService", mediaButtonReceiver, mediaPendingIntent); /* final MediaSessionCallback cb = new MediaSessionCallback(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Shouldn't really have to do this but the MediaSessionCompat method uses // an internal proxy class, which doesn't forward events such as // onPlayFromMediaId when running on Lollipop. final MediaSession session = (MediaSession) mSession.getMediaSession(); session.setCallback(new MediaSessionCallbackProxy(cb)); } else { mSession.setCallback(cb); } */ setSessionToken(mSession.getSessionToken()); mSession.setCallback(new MediaSessionCallback()); mSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); mPlayback = new LocalPlayback(this, mMusicProvider); mPlayback.setState(PlaybackStateCompat.STATE_NONE); mPlayback.setCallback(this); mPlayback.start(); Context context = getApplicationContext(); Intent intent = new Intent(context, NowPlayingActivity.class); PendingIntent pi = PendingIntent.getActivity( context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT); mSession.setSessionActivity(pi); mSessionExtras = new Bundle(); CarHelper.setSlotReservationFlags(mSessionExtras, true, true, true); WearHelper.setSlotReservationFlags(mSessionExtras, true, true); WearHelper.setUseBackgroundFromTheme(mSessionExtras, true); mSession.setExtras(mSessionExtras); updatePlaybackState(null); mMediaNotificationManager = new MediaNotificationManager(this); mCastManager = VideoCastManager.getInstance(); mCastManager.addVideoCastConsumer(mCastConsumer); mMediaRouter = MediaRouter.getInstance(getApplicationContext()); IntentFilter filter = new IntentFilter(CarHelper.ACTION_MEDIA_STATUS); mCarConnectionReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String connectionEvent = intent.getStringExtra(CarHelper.MEDIA_CONNECTION_STATUS); mIsConnectedToCar = CarHelper.MEDIA_CONNECTED.equals(connectionEvent); LogHelper.i( TAG, "Connection event to Android Auto: ", connectionEvent, " isConnectedToCar=", mIsConnectedToCar); } }; registerReceiver(mCarConnectionReceiver, filter); }