Commit 8a996217 authored by avayvod's avatar avayvod Committed by Commit bot

[Android,Cast] Report correctly when devices are not available.

The ChromeMediaRouterDialogController now reports when the source URN is
not supported so that the native side can reject the PresentationRequest
correctly.
CastMediaRouteProvider now reports no sinks available if the source URN
is not supported or if Android MediaRouter's API are not present (like
on JB MR1). For the latter, we now do create ChromeMRP when MediaRouter
is null and check if it's null before using (was already checked
everywhere, except for one spot changed in this CL).

BUG=706882
TEST=manual at https://googlechrome.github.io/samples/presentation-api/

Review-Url: https://codereview.chromium.org/2783363002
Cr-Commit-Position: refs/heads/master@{#462887}
parent d6dbbe9a
...@@ -43,6 +43,14 @@ public class ChromeMediaRouter implements MediaRouteManager { ...@@ -43,6 +43,14 @@ public class ChromeMediaRouter implements MediaRouteManager {
new HashMap<String, Map<MediaRouteProvider, List<MediaSink>>>(); new HashMap<String, Map<MediaRouteProvider, List<MediaSink>>>();
private final Map<String, List<MediaSink>> mSinksPerSource = private final Map<String, List<MediaSink>> mSinksPerSource =
new HashMap<String, List<MediaSink>>(); new HashMap<String, List<MediaSink>>();
private static boolean sAndroidMediaRouterSetForTest = false;
private static MediaRouter sAndroidMediaRouterForTest = null;
@VisibleForTesting
public static void setAndroidMediaRouterForTest(MediaRouter router) {
sAndroidMediaRouterSetForTest = true;
sAndroidMediaRouterForTest = router;
}
@VisibleForTesting @VisibleForTesting
public static void setRouteProviderBuilderForTest(MediaRouteProvider.Builder builder) { public static void setRouteProviderBuilderForTest(MediaRouteProvider.Builder builder) {
...@@ -76,6 +84,7 @@ public class ChromeMediaRouter implements MediaRouteManager { ...@@ -76,6 +84,7 @@ public class ChromeMediaRouter implements MediaRouteManager {
*/ */
@Nullable @Nullable
public static MediaRouter getAndroidMediaRouter() { public static MediaRouter getAndroidMediaRouter() {
if (sAndroidMediaRouterSetForTest) return sAndroidMediaRouterForTest;
try { try {
// Pre-MR1 versions of JB do not have the complete MediaRouter APIs, // Pre-MR1 versions of JB do not have the complete MediaRouter APIs,
// so getting the MediaRouter instance will throw an exception. // so getting the MediaRouter instance will throw an exception.
......
...@@ -44,7 +44,10 @@ public class ChromeMediaRouterDialogController implements MediaRouteDialogDelega ...@@ -44,7 +44,10 @@ public class ChromeMediaRouterDialogController implements MediaRouteDialogDelega
if (isShowingDialog()) return; if (isShowingDialog()) return;
MediaSource source = MediaSource.from(sourceUrn); MediaSource source = MediaSource.from(sourceUrn);
if (source == null) return; if (source == null) {
nativeOnMediaSourceNotSupported(mNativeDialogController);
return;
}
mDialogManager = new MediaRouteChooserDialogManager(source, this); mDialogManager = new MediaRouteChooserDialogManager(source, this);
mDialogManager.openDialog(); mDialogManager.openDialog();
...@@ -60,7 +63,10 @@ public class ChromeMediaRouterDialogController implements MediaRouteDialogDelega ...@@ -60,7 +63,10 @@ public class ChromeMediaRouterDialogController implements MediaRouteDialogDelega
if (isShowingDialog()) return; if (isShowingDialog()) return;
MediaSource source = MediaSource.from(sourceUrn); MediaSource source = MediaSource.from(sourceUrn);
if (source == null) return; if (source == null) {
nativeOnMediaSourceNotSupported(mNativeDialogController);
return;
}
mDialogManager = new MediaRouteControllerDialogManager(source, mediaRouteId, this); mDialogManager = new MediaRouteControllerDialogManager(source, mediaRouteId, this);
mDialogManager.openDialog(); mDialogManager.openDialog();
...@@ -117,4 +123,5 @@ public class ChromeMediaRouterDialogController implements MediaRouteDialogDelega ...@@ -117,4 +123,5 @@ public class ChromeMediaRouterDialogController implements MediaRouteDialogDelega
native void nativeOnSinkSelected( native void nativeOnSinkSelected(
long nativeMediaRouterDialogControllerAndroid, String sinkId); long nativeMediaRouterDialogControllerAndroid, String sinkId);
native void nativeOnRouteClosed(long nativeMediaRouterDialogControllerAndroid, String routeId); native void nativeOnRouteClosed(long nativeMediaRouterDialogControllerAndroid, String routeId);
native void nativeOnMediaSourceNotSupported(long nativeMediaRouterDialogControllerAndroid);
} }
...@@ -91,7 +91,6 @@ public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDele ...@@ -91,7 +91,6 @@ public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDele
@Nullable @Nullable
public static CastMediaRouteProvider create(MediaRouteManager manager) { public static CastMediaRouteProvider create(MediaRouteManager manager) {
MediaRouter androidMediaRouter = ChromeMediaRouter.getAndroidMediaRouter(); MediaRouter androidMediaRouter = ChromeMediaRouter.getAndroidMediaRouter();
if (androidMediaRouter == null) return null;
return new CastMediaRouteProvider(androidMediaRouter, manager); return new CastMediaRouteProvider(androidMediaRouter, manager);
} }
...@@ -182,10 +181,19 @@ public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDele ...@@ -182,10 +181,19 @@ public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDele
@Override @Override
public void startObservingMediaSinks(String sourceId) { public void startObservingMediaSinks(String sourceId) {
if (mAndroidMediaRouter == null) return; if (mAndroidMediaRouter == null) {
// If the MediaRouter API is not available, report no devices so the page doesn't even
// try to cast.
onSinksReceived(sourceId, new ArrayList<MediaSink>());
return;
}
MediaSource source = MediaSource.from(sourceId); MediaSource source = MediaSource.from(sourceId);
if (source == null) return; if (source == null) {
// If the source is invalid, report no devices available.
onSinksReceived(sourceId, new ArrayList<MediaSink>());
return;
}
MediaRouteSelector routeSelector = source.buildRouteSelector(); MediaRouteSelector routeSelector = source.buildRouteSelector();
if (routeSelector == null) { if (routeSelector == null) {
...@@ -322,7 +330,7 @@ public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDele ...@@ -322,7 +330,7 @@ public class CastMediaRouteProvider implements MediaRouteProvider, DiscoveryDele
} }
ClientRecord client = getClientRecordByRouteId(routeId); ClientRecord client = getClientRecordByRouteId(routeId);
if (client != null) { if (client != null && mAndroidMediaRouter != null) {
MediaSink sink = MediaSink.fromSinkId(mSession.getSinkId(), mAndroidMediaRouter); MediaSink sink = MediaSink.fromSinkId(mSession.getSinkId(), mAndroidMediaRouter);
if (sink != null) sendReceiverAction(routeId, sink, client.clientId, "stop"); if (sink != null) sendReceiverAction(routeId, sink, client.clientId, "stop");
} }
......
...@@ -1618,6 +1618,7 @@ chrome_junit_test_java_sources = [ ...@@ -1618,6 +1618,7 @@ chrome_junit_test_java_sources = [
"junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterRouteTest.java", "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterRouteTest.java",
"junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterSinkObservationTest.java", "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterSinkObservationTest.java",
"junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterTestBase.java", "junit/src/org/chromium/chrome/browser/media/router/ChromeMediaRouterTestBase.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProviderTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java", "junit/src/org/chromium/chrome/browser/media/router/cast/CastMessageHandlerTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/DiscoveryCallbackTest.java", "junit/src/org/chromium/chrome/browser/media/router/cast/DiscoveryCallbackTest.java",
"junit/src/org/chromium/chrome/browser/media/router/cast/JSONTestUtils.java", "junit/src/org/chromium/chrome/browser/media/router/cast/JSONTestUtils.java",
......
// Copyright 2017 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.cast;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.support.v7.media.MediaRouter;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.media.router.ChromeMediaRouter;
import org.chromium.chrome.browser.media.router.MediaRouteManager;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.util.ArrayList;
/**
* Robolectric tests for {@link CastMediaRouteProvider}.
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class CastMediaRouteProviderTest {
private static final String SUPPORTED_SOURCE =
"https://google.com/cast/#__castAppId__=DEADBEEF";
private static final String UNSUPPORTED_SOURCE = "https://example.com";
@Test
@Feature({"MediaRouter"})
public void testStartObservingMediaSinksNoMediaRouter() {
ChromeMediaRouter.setAndroidMediaRouterForTest(null);
MediaRouteManager mockManager = mock(MediaRouteManager.class);
CastMediaRouteProvider provider = CastMediaRouteProvider.create(mockManager);
provider.startObservingMediaSinks(SUPPORTED_SOURCE);
verify(mockManager, timeout(100))
.onSinksReceived(
eq(SUPPORTED_SOURCE), same(provider), eq(new ArrayList<MediaSink>()));
}
@Test
@Feature({"MediaRouter"})
public void testStartObservingMediaSinksUnsupportedSource() {
ChromeMediaRouter.setAndroidMediaRouterForTest(mock(MediaRouter.class));
MediaRouteManager mockManager = mock(MediaRouteManager.class);
CastMediaRouteProvider provider = CastMediaRouteProvider.create(mockManager);
provider.startObservingMediaSinks(UNSUPPORTED_SOURCE);
verify(mockManager, timeout(100))
.onSinksReceived(
eq(UNSUPPORTED_SOURCE), same(provider), eq(new ArrayList<MediaSink>()));
}
}
...@@ -87,6 +87,18 @@ void MediaRouterDialogControllerAndroid::OnDialogCancelled( ...@@ -87,6 +87,18 @@ void MediaRouterDialogControllerAndroid::OnDialogCancelled(
CancelPresentationRequest(); CancelPresentationRequest();
} }
void MediaRouterDialogControllerAndroid::OnMediaSourceNotSupported(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
std::unique_ptr<CreatePresentationConnectionRequest> request =
TakeCreateConnectionRequest();
if (!request)
return;
request->InvokeErrorCallback(content::PresentationError(
content::PRESENTATION_ERROR_NO_AVAILABLE_SCREENS, "No screens found."));
}
void MediaRouterDialogControllerAndroid::CancelPresentationRequest() { void MediaRouterDialogControllerAndroid::CancelPresentationRequest() {
std::unique_ptr<CreatePresentationConnectionRequest> request = std::unique_ptr<CreatePresentationConnectionRequest> request =
TakeCreateConnectionRequest(); TakeCreateConnectionRequest();
......
...@@ -43,6 +43,11 @@ class MediaRouterDialogControllerAndroid ...@@ -43,6 +43,11 @@ class MediaRouterDialogControllerAndroid
// taking any action (e.g. closing the route or selecting a sink). // taking any action (e.g. closing the route or selecting a sink).
void OnDialogCancelled(JNIEnv* env, void OnDialogCancelled(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj); const base::android::JavaParamRef<jobject>& obj);
// Notifies the controller the media source URN is not supported so it could
// properly reject the request.
void OnMediaSourceNotSupported(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
private: private:
friend class content::WebContentsUserData<MediaRouterDialogControllerAndroid>; friend class content::WebContentsUserData<MediaRouterDialogControllerAndroid>;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment