blob: be611299b4d7e22afcc8b82d8a37983968f261d7 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.media.router.caf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.chromium.chrome.browser.media.router.caf.CafBaseMediaRouteProvider.NO_SINKS;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.gms.cast.framework.CastSession;
import com.google.android.gms.cast.framework.SessionManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowLooper;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.media.router.MediaRoute;
import org.chromium.chrome.browser.media.router.MediaRouteManager;
import org.chromium.chrome.browser.media.router.MediaSink;
import org.chromium.chrome.browser.media.router.MediaSource;
import java.util.ArrayList;
import java.util.List;
/**
* Robolectric tests for CafBaseMediaRouteProvider.
*/
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE,
shadows = {ShadowMediaRouter.class, ShadowCastContext.class, ShadowLooper.class})
public class CafBaseMediaRouteProviderTest {
private Context mContext;
private TestMRP mProvider;
private MediaRouterTestHelper mMediaRouterHelper;
private MediaRouter mMediaRouter;
@Mock
private MediaRouteManager mManager;
@Mock
private CastContext mCastContext;
@Mock
private CastSession mCastSession;
@Mock
private SessionManager mSessionManager;
@Mock
private BaseSessionController mSessionController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mMediaRouterHelper = new MediaRouterTestHelper();
ShadowCastContext.setInstance(mCastContext);
mMediaRouter = MediaRouter.getInstance(mContext);
mProvider = spy(new TestMRP(mMediaRouter, mManager));
doReturn(mSessionController).when(mProvider).sessionController();
doReturn(mSessionManager).when(mCastContext).getSessionManager();
}
@Test
public void testOnSinksReceived() {
List<MediaSink> sinks = new ArrayList<>();
sinks.add(mock(MediaSink.class));
sinks.add(mock(MediaSink.class));
mProvider.onSinksReceived("source-id", sinks);
ShadowLooper.idleMainLooper();
verify(mManager).onSinksReceived("source-id", mProvider, sinks);
}
@Test
public void testSupportsSource() {
// Source unsupported.
doReturn(null).when(mProvider).getSourceFromId(any(String.class));
assertFalse(mProvider.supportsSource("source-id"));
// Source supported.
doReturn(mock(MediaSource.class)).when(mProvider).getSourceFromId(any(String.class));
assertTrue(mProvider.supportsSource("source-id"));
}
@Test
public void testStartObservingMediaSinks_unsupportedSource() {
doReturn(null).when(mProvider).getSourceFromId(any(String.class));
mProvider.startObservingMediaSinks("source-id");
ShadowLooper.idleMainLooper();
verify(mManager).onSinksReceived("source-id", mProvider, NO_SINKS);
verify(mMediaRouterHelper.getShadowImpl(), never())
.addCallback(
any(MediaRouteSelector.class), any(MediaRouter.Callback.class), anyInt());
assertTrue(mProvider.mDiscoveryCallbacks.isEmpty());
}
@Test
public void testStartObservingMediaSinks_invalidSelector() {
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId(any(String.class));
doReturn(null).when(mockSource).buildRouteSelector();
mProvider.startObservingMediaSinks("source-id");
ShadowLooper.idleMainLooper();
verify(mManager).onSinksReceived("source-id", mProvider, NO_SINKS);
verify(mMediaRouterHelper.getShadowImpl(), never())
.addCallback(
any(MediaRouteSelector.class), any(MediaRouter.Callback.class), anyInt());
assertTrue(mProvider.mDiscoveryCallbacks.isEmpty());
}
@Test
@SuppressWarnings("unchecked")
public void testStartObservingMediaSinks_twoDifferentAppIds() {
MediaSource mockSource1 = mock(MediaSource.class);
MediaSource mockSource2 = mock(MediaSource.class);
MediaRouteSelector mockSelector1 = mock(MediaRouteSelector.class);
MediaRouteSelector mockSelector2 = mock(MediaRouteSelector.class);
prepareMediaSource(mockSource1, mockSelector1, "source-id-1", "app-id-1");
prepareMediaSource(mockSource2, mockSelector2, "source-id-2", "app-id-2");
mProvider.startObservingMediaSinks("source-id-1");
mProvider.startObservingMediaSinks("source-id-2");
ShadowLooper.idleMainLooper();
// Empty devices are published while the callbacks are constructed.
verify(mManager).onSinksReceived(eq("source-id-1"), eq(mProvider), eq(NO_SINKS));
verify(mManager).onSinksReceived(eq("source-id-2"), eq(mProvider), eq(NO_SINKS));
verify(mMediaRouterHelper.getShadowImpl())
.addCallback(eq(mockSelector1), any(MediaRouter.Callback.class),
eq(MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY));
verify(mMediaRouterHelper.getShadowImpl())
.addCallback(eq(mockSelector2), any(MediaRouter.Callback.class),
eq(MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY));
assertEquals(mProvider.mDiscoveryCallbacks.size(), 2);
assertTrue(mProvider.mDiscoveryCallbacks.containsKey("app-id-1"));
assertTrue(mProvider.mDiscoveryCallbacks.containsKey("app-id-2"));
// Add one route for source 1.
MediaRouter.RouteInfo routeInfo = mock(MediaRouter.RouteInfo.class);
doReturn(true).when(routeInfo).matchesSelector(any(MediaRouteSelector.class));
mProvider.mDiscoveryCallbacks.get("app-id-1").onRouteAdded(mMediaRouter, routeInfo);
ArgumentCaptor<List<MediaSink>> sinksCaptor = ArgumentCaptor.forClass(List.class);
verify(mManager, times(2))
.onSinksReceived(eq("source-id-1"), eq(mProvider), sinksCaptor.capture());
assertEquals(sinksCaptor.getAllValues().get(1).size(), 1);
}
@Test
@SuppressWarnings("unchecked")
public void testStartObservingMediaSinks_twoSameAppIds() {
MediaSource mockSource1 = mock(MediaSource.class);
MediaSource mockSource2 = mock(MediaSource.class);
MediaRouteSelector mockSelector1 = mock(MediaRouteSelector.class);
MediaRouteSelector mockSelector2 = mock(MediaRouteSelector.class);
prepareMediaSource(mockSource1, mockSelector1, "source-id-1", "app-id-1");
prepareMediaSource(mockSource2, mockSelector2, "source-id-2", "app-id-1");
mProvider.startObservingMediaSinks("source-id-1");
mProvider.startObservingMediaSinks("source-id-2");
ShadowLooper.idleMainLooper();
// Empty devices are published while the callbacks are constructed.
verify(mManager).onSinksReceived(eq("source-id-1"), eq(mProvider), eq(NO_SINKS));
verify(mManager).onSinksReceived(eq("source-id-2"), eq(mProvider), eq(NO_SINKS));
verify(mMediaRouterHelper.getShadowImpl())
.addCallback(eq(mockSelector1), any(MediaRouter.Callback.class),
eq(MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY));
assertEquals(mProvider.mDiscoveryCallbacks.size(), 1);
assertTrue(mProvider.mDiscoveryCallbacks.containsKey("app-id-1"));
// Add one route for source 1.
MediaRouter.RouteInfo routeInfo = mock(MediaRouter.RouteInfo.class);
doReturn(true).when(routeInfo).matchesSelector(any(MediaRouteSelector.class));
mProvider.mDiscoveryCallbacks.get("app-id-1").onRouteAdded(mMediaRouter, routeInfo);
ArgumentCaptor<List<MediaSink>> sinksCaptor = ArgumentCaptor.forClass(List.class);
verify(mManager, times(2))
.onSinksReceived(eq("source-id-1"), eq(mProvider), sinksCaptor.capture());
assertEquals(sinksCaptor.getAllValues().get(1).size(), 1);
sinksCaptor = ArgumentCaptor.forClass(List.class);
verify(mManager, times(2))
.onSinksReceived(eq("source-id-2"), eq(mProvider), sinksCaptor.capture());
assertEquals(sinksCaptor.getAllValues().get(1).size(), 1);
}
@Test
@SuppressWarnings("unchecked")
public void testStartObservingMediaSinks_hasMatchingRouteOnStart() {
doReturn(true)
.when(mMediaRouterHelper.getCastRoute())
.matchesSelector(any(MediaRouteSelector.class));
MediaSource mockSource = mock(MediaSource.class);
MediaRouteSelector mockSelector = mock(MediaRouteSelector.class);
prepareMediaSource(mockSource, mockSelector, "source-id", "app-id");
mProvider.startObservingMediaSinks("source-id");
ShadowLooper.idleMainLooper();
// Existing devices that match the selector should be published upon start observing.
ArgumentCaptor<List<MediaSink>> sinksCaptor = ArgumentCaptor.forClass(List.class);
verify(mManager).onSinksReceived(eq("source-id"), eq(mProvider), sinksCaptor.capture());
assertEquals(sinksCaptor.getValue().size(), 1);
}
@Test
public void testStopObservingMediaSinks() {
MediaSource mockSource1 = mock(MediaSource.class);
MediaSource mockSource2 = mock(MediaSource.class);
MediaRouteSelector mockSelector1 = mock(MediaRouteSelector.class);
MediaRouteSelector mockSelector2 = mock(MediaRouteSelector.class);
prepareMediaSource(mockSource1, mockSelector1, "source-id-1", "app-id-1");
prepareMediaSource(mockSource2, mockSelector2, "source-id-2", "app-id-1");
mProvider.startObservingMediaSinks("source-id-1");
mProvider.startObservingMediaSinks("source-id-2");
mProvider.stopObservingMediaSinks("source-id-1");
verify(mMediaRouterHelper.getShadowImpl(), never())
.removeCallback(any(MediaRouter.Callback.class));
assertEquals(mProvider.mDiscoveryCallbacks.size(), 1);
mProvider.stopObservingMediaSinks("source-id-2");
verify(mMediaRouterHelper.getShadowImpl()).removeCallback(any(MediaRouter.Callback.class));
assertTrue(mProvider.mDiscoveryCallbacks.isEmpty());
}
@Test
public void testCreateRoute() {
InOrder inOrder = inOrder(mSessionManager, mSessionController, mManager);
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId("source-id");
// Normal case.
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
inOrder.verify(mSessionManager).addSessionManagerListener(mProvider, CastSession.class);
inOrder.verify(mSessionController).requestSessionLaunch();
CreateRouteRequestInfo pendingCreateRouteRequestInfo =
mProvider.getPendingCreateRouteRequestInfo();
assertEquals(pendingCreateRouteRequestInfo.source, mockSource);
assertEquals(pendingCreateRouteRequestInfo.sink.getId(), "cast-route");
assertEquals(pendingCreateRouteRequestInfo.presentationId, "presentation-id");
assertEquals(pendingCreateRouteRequestInfo.origin, "origin");
assertEquals(pendingCreateRouteRequestInfo.tabId, 1);
assertEquals(pendingCreateRouteRequestInfo.isIncognito, false);
assertEquals(pendingCreateRouteRequestInfo.nativeRequestId, 1);
assertEquals(pendingCreateRouteRequestInfo.routeInfo, mMediaRouterHelper.getCastRoute());
// Second request cancels the first request.
mProvider.createRoute(
"source-id", "other-cast-route", "presentation-id-2", "origin-2", 2, true, 2);
inOrder.verify(mManager).onRouteRequestError(eq("Request replaced"), eq(1));
inOrder.verify(mSessionManager).addSessionManagerListener(mProvider, CastSession.class);
inOrder.verify(mSessionController).requestSessionLaunch();
pendingCreateRouteRequestInfo = mProvider.getPendingCreateRouteRequestInfo();
assertEquals(pendingCreateRouteRequestInfo.source, mockSource);
assertEquals(pendingCreateRouteRequestInfo.sink.getId(), "other-cast-route");
assertEquals(pendingCreateRouteRequestInfo.presentationId, "presentation-id-2");
assertEquals(pendingCreateRouteRequestInfo.origin, "origin-2");
assertEquals(pendingCreateRouteRequestInfo.tabId, 2);
assertEquals(pendingCreateRouteRequestInfo.isIncognito, true);
assertEquals(pendingCreateRouteRequestInfo.nativeRequestId, 2);
assertEquals(
pendingCreateRouteRequestInfo.routeInfo, mMediaRouterHelper.getOtherCastRoute());
// A new request ends the current session if there's any.
doReturn(true).when(mSessionController).isConnected();
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
inOrder.verify(mSessionController).endSession();
inOrder.verify(mSessionManager).addSessionManagerListener(mProvider, CastSession.class);
inOrder.verify(mSessionController).requestSessionLaunch();
}
@Test
public void testCreateRoute_invalidRequest() {
InOrder inOrder = inOrder(mSessionManager, mSessionController, mManager);
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId("source-id");
// Invalid sink.
mProvider.createRoute(
"source-id", "invalid-route", "presentation-id", "origin", 1, false, 1);
inOrder.verify(mManager).onRouteRequestError("No sink", 1);
// Invalid source.
doReturn(null).when(mProvider).getSourceFromId(anyString());
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
inOrder.verify(mManager).onRouteRequestError("Unsupported source URL", 1);
}
@Test
public void testCloseRoute() {
InOrder inOrder = inOrder(mSessionController);
MediaRoute route = new MediaRoute("sink-id", "source-id", "presentation-id");
// Normal case.
mProvider.addRoute(route, "origin", 1, 1, false);
doReturn(true).when(mSessionController).isConnected();
mProvider.closeRoute(route.id);
inOrder.verify(mSessionController).endSession();
assertContainsRoutes(route);
// Route doesn't exist.
mProvider.closeRoute("other-route");
inOrder.verify(mSessionController, never()).endSession();
assertContainsRoutes(route);
// No session.
doReturn(false).when(mSessionController).isConnected();
mProvider.closeRoute(route.id);
inOrder.verify(mSessionController, never()).endSession();
assertContainsRoutes(/* no route */);
}
@Test
public void testDetachRoute() {
InOrder inOrder = inOrder(mSessionController);
MediaRoute route = new MediaRoute("sink-id", "source-id", "presentation-id");
mProvider.addRoute(route, "origin", 1, 1, false);
mProvider.detachRoute(route.id);
assertContainsRoutes(/* no route */);
}
@Test
public void testOnSessionStartFailed() {
InOrder inOrder = inOrder(mProvider, mManager);
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId("source-id");
// Request to create a session.
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
inOrder.verify(mManager, never()).onRouteRequestError(anyString(), anyInt());
// Session start failed.
mProvider.onSessionStartFailed(mCastSession, 1);
inOrder.verify(mProvider).removeAllRoutes("Launch error");
inOrder.verify(mManager).onRouteRequestError("Launch error", 1);
}
@Test
public void testOnSessionStarted() {
InOrder inOrder = inOrder(mSessionController);
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId("source-id");
doReturn("source-id").when(mockSource).getSourceId();
// Request to create a session.
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
// Session started.
mProvider.onSessionStarted(mCastSession, "session-id");
inOrder.verify(mSessionController).attachToCastSession(mCastSession);
inOrder.verify(mSessionController).onSessionStarted();
assertEquals(mProvider.mRoutes.size(), 1);
MediaRoute route = (MediaRoute) (mProvider.mRoutes.values().toArray()[0]);
assertEquals(route.sinkId, "cast-route");
assertEquals(route.sourceId, "source-id");
assertEquals(route.presentationId, "presentation-id");
assertNull(mProvider.getPendingCreateRouteRequestInfo());
}
@Test
public void testOnSessionResumed() {
mProvider.onSessionResumed(mCastSession, true);
verify(mSessionController).attachToCastSession(mCastSession);
}
@Test
public void testOnSessionEnding() {
InOrder inOrder = inOrder(
mSessionController, mProvider, mSessionManager, mMediaRouterHelper.getShadowImpl());
mProvider.onSessionEnding(mCastSession);
verifySessionEnd(inOrder);
}
@Test
public void testOnSessionEnding_hasPendingRequest() {
// If there's a pending request, then the session ending event comes from ending the
// previous session.
InOrder inOrder = inOrder(
mSessionController, mProvider, mSessionManager, mMediaRouterHelper.getShadowImpl());
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId("source-id");
doReturn("source-id").when(mockSource).getSourceId();
// Request to create a session.
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
// Simulate a session is ending.
mProvider.onSessionEnding(mCastSession);
verifySessionNeverEnd(inOrder);
}
@Test
public void testOnSessionEnded() {
InOrder inOrder = inOrder(
mSessionController, mProvider, mSessionManager, mMediaRouterHelper.getShadowImpl());
mProvider.onSessionEnded(mCastSession, 0);
verifySessionEnd(inOrder);
}
@Test
public void testOnSessionEnded_hasPendingRequest() {
// If there's a pending request, then the session ending event comes from ending the
// previous session.
InOrder inOrder = inOrder(
mSessionController, mProvider, mSessionManager, mMediaRouterHelper.getShadowImpl());
MediaSource mockSource = mock(MediaSource.class);
doReturn(mockSource).when(mProvider).getSourceFromId("source-id");
doReturn("source-id").when(mockSource).getSourceId();
// Request to create a session.
mProvider.createRoute("source-id", "cast-route", "presentation-id", "origin", 1, false, 1);
// Simulate a session has ended.
mProvider.onSessionEnded(mCastSession, 0);
verifySessionNeverEnd(inOrder);
}
@Test
public void testOnSessionSuspended() {
mProvider.onSessionSuspended(mCastSession, 0);
verify(mSessionController).detachFromCastSession();
}
@Test
public void testAddRoute() {
InOrder inOrder = inOrder(mManager);
MediaRoute route1 = new MediaRoute("sink-id-1", "source-id-1", "presentation-id-1");
MediaRoute route2 = new MediaRoute("sink-id-2", "source-id-2", "presentation-id-2");
// Add the first route.
mProvider.addRoute(route1, "origin-1", 1, 1, false);
assertContainsRoutes(route1);
inOrder.verify(mManager).onRouteCreated(route1.id, "sink-id-1", 1, mProvider, false);
// Add the second route.
mProvider.addRoute(route2, "origin-2", 2, 2, true);
assertContainsRoutes(route1, route2);
inOrder.verify(mManager).onRouteCreated(route2.id, "sink-id-2", 2, mProvider, true);
// Add a duplicate route. This should never happen but the manager should be notified just
// to be safe.
mProvider.addRoute(route1, "origin-1", 3, 3, false);
assertContainsRoutes(route1, route2);
inOrder.verify(mManager).onRouteCreated(route1.id, "sink-id-1", 3, mProvider, false);
}
@Test
public void testRemoveRoute() {
InOrder inOrder = inOrder(mManager);
MediaRoute route1 = new MediaRoute("sink-id-1", "source-id-1", "presentation-id-1");
MediaRoute route2 = new MediaRoute("sink-id-2", "source-id-2", "presentation-id-2");
mProvider.addRoute(route1, "origin-1", 1, 1, false);
mProvider.addRoute(route2, "origin-2", 2, 2, true);
// Remove the first route.
mProvider.removeRoute(route1.id, "error 1");
assertContainsRoutes(route2);
inOrder.verify(mManager).onRouteClosed(route1.id, "error 1");
// Remove the second route.
mProvider.removeRoute(route2.id, "error 2");
assertContainsRoutes(/* no route */);
inOrder.verify(mManager).onRouteClosed(route2.id, "error 2");
// Remove a duplicate route. This should never happen but the manager should be notified
// just to be safe.
mProvider.removeRoute(route1.id, "error 3");
assertContainsRoutes(/* no route */);
inOrder.verify(mManager).onRouteClosed(route1.id, "error 3");
}
@Test
public void testRemoveAllRoutes() {
MediaRoute route1 = new MediaRoute("sink-id-1", "source-id-1", "presentation-id-1");
MediaRoute route2 = new MediaRoute("sink-id-2", "source-id-2", "presentation-id-2");
mProvider.addRoute(route1, "origin-1", 1, 1, false);
mProvider.addRoute(route2, "origin-2", 2, 2, true);
mProvider.removeAllRoutes("error");
assertContainsRoutes(/* no route */);
verify(mManager).onRouteClosed(route1.id, "error");
verify(mManager).onRouteClosed(route2.id, "error");
}
@Test
public void testTerminateAllRoutes() {
MediaRoute route1 = new MediaRoute("sink-id-1", "source-id-1", "presentation-id-1");
MediaRoute route2 = new MediaRoute("sink-id-2", "source-id-2", "presentation-id-2");
mProvider.addRoute(route1, "origin-1", 1, 1, false);
mProvider.addRoute(route2, "origin-2", 2, 2, true);
mProvider.terminateAllRoutes();
assertContainsRoutes(/* no route */);
verify(mManager).onRouteTerminated(route1.id);
verify(mManager).onRouteTerminated(route2.id);
verify(mManager, never()).onRouteClosed(eq(route1.id), anyString());
}
private void prepareMediaSource(
MediaSource source, MediaRouteSelector selector, String sourceId, String appId) {
doReturn(source).when(mProvider).getSourceFromId(sourceId);
doReturn(appId).when(source).getApplicationId();
doReturn(selector).when(source).buildRouteSelector();
}
private void verifySessionEnd(InOrder inOrder) {
inOrder.verify(mSessionController).onSessionEnded();
inOrder.verify(mSessionController).detachFromCastSession();
inOrder.verify(mMediaRouterHelper.getShadowImpl())
.selectRoute(mMediaRouterHelper.getDefaultRoute());
inOrder.verify(mProvider).terminateAllRoutes();
inOrder.verify(mSessionManager).removeSessionManagerListener(mProvider, CastSession.class);
}
private void verifySessionNeverEnd(InOrder inOrder) {
inOrder.verify(mSessionController, never()).onSessionEnded();
inOrder.verify(mSessionController, never()).detachFromCastSession();
inOrder.verify(mMediaRouterHelper.getShadowImpl(), never())
.selectRoute(mMediaRouterHelper.getDefaultRoute());
inOrder.verify(mProvider, never()).terminateAllRoutes();
inOrder.verify(mSessionManager, never())
.removeSessionManagerListener(mProvider, CastSession.class);
}
private void assertContainsRoutes(MediaRoute... routes) {
assertEquals(mProvider.mRoutes.size(), routes.length);
for (MediaRoute route : routes) {
assertEquals(mProvider.mRoutes.get(route.id), route);
}
}
private static class TestMRP extends CafBaseMediaRouteProvider {
public TestMRP(MediaRouter androidMediaRouter, MediaRouteManager manager) {
super(androidMediaRouter, manager);
}
@Override
public MediaSource getSourceFromId(@NonNull String sourceId) {
return null;
}
@Override
public BaseSessionController sessionController() {
return null;
}
@Override
public void sendStringMessage(String routeId, String message) {}
@Override
public void joinRoute(String routeId, String presentationId, String origin, int tabId,
int nativeRequestId) {}
}
}