Commit 74e258c6 authored by Zhiqiang Zhang's avatar Zhiqiang Zhang Committed by Commit Bot

Revert "[Android MR] Postpone route selection until session launch"

This reverts commit 7c453583.

Reason for revert: This introduces some regression in some cases. The old logic works just fine so it is safe to revert.

Original change's description:
> [Android MR] Postpone route selection until session launch
> 
> Previously, we unselect and re-select the route due to CAF limitation.
> The reason is that we need to set the receiver app ID after the user
> choose a device. However CAF won't be able to know a device was selected
> after the receiver app ID gets changed.
> 
> In this CL, to solve the issue, we intercept the click event in
> MediaRouteChooserDialog (which would select the route automatically).
> The route selection is postponed right before session launch. Therefore
> we are able to set the receiver app ID and select the route to get rid
> of CAF limitation.
> 
> Bug: 711860
> Change-Id: I5b1534d36d540b62199a6fb739c56ad5131c2711
> Reviewed-on: https://chromium-review.googlesource.com/c/1351893
> Reviewed-by: Thomas Guilbert <tguilbert@chromium.org>
> Commit-Queue: Zhiqiang Zhang <zqzhang@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#611437}

TBR=zqzhang@chromium.org,tguilbert@chromium.org

Change-Id: I30322daecf8c866fdda9e846d0cb37d9a319f033
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 711860
Reviewed-on: https://chromium-review.googlesource.com/c/1352973Reviewed-by: default avatarZhiqiang Zhang <zqzhang@chromium.org>
Commit-Queue: Zhiqiang Zhang <zqzhang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611572}
parent aaf987e6
...@@ -13,11 +13,6 @@ import android.support.v4.app.FragmentManager; ...@@ -13,11 +13,6 @@ import android.support.v4.app.FragmentManager;
import android.support.v7.app.MediaRouteChooserDialog; import android.support.v7.app.MediaRouteChooserDialog;
import android.support.v7.app.MediaRouteChooserDialogFragment; import android.support.v7.app.MediaRouteChooserDialogFragment;
import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter;
import android.support.v7.mediarouter.R;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
/** /**
* Manages the dialog responsible for selecting a {@link MediaSink}. * Manages the dialog responsible for selecting a {@link MediaSink}.
...@@ -39,7 +34,7 @@ public class MediaRouteChooserDialogManager extends BaseMediaRouteDialogManager ...@@ -39,7 +34,7 @@ public class MediaRouteChooserDialogManager extends BaseMediaRouteDialogManager
private final Handler mHandler = new Handler(); private final Handler mHandler = new Handler();
private final SystemVisibilitySaver mVisibilitySaver = new SystemVisibilitySaver(); private final SystemVisibilitySaver mVisibilitySaver = new SystemVisibilitySaver();
private BaseMediaRouteDialogManager mManager; private BaseMediaRouteDialogManager mManager;
private boolean mIsSinkSelected; private boolean mCancelled;
public Fragment() { public Fragment() {
mHandler.post(new Runnable() { mHandler.post(new Runnable() {
...@@ -57,7 +52,8 @@ public class MediaRouteChooserDialogManager extends BaseMediaRouteDialogManager ...@@ -57,7 +52,8 @@ public class MediaRouteChooserDialogManager extends BaseMediaRouteDialogManager
@Override @Override
public MediaRouteChooserDialog onCreateChooserDialog( public MediaRouteChooserDialog onCreateChooserDialog(
Context context, Bundle savedInstanceState) { Context context, Bundle savedInstanceState) {
MediaRouteChooserDialog dialog = new DelayedSelectionDialog(context, getTheme()); MediaRouteChooserDialog dialog =
super.onCreateChooserDialog(context, savedInstanceState);
dialog.setCanceledOnTouchOutside(true); dialog.setCanceledOnTouchOutside(true);
return dialog; return dialog;
} }
...@@ -75,45 +71,26 @@ public class MediaRouteChooserDialogManager extends BaseMediaRouteDialogManager ...@@ -75,45 +71,26 @@ public class MediaRouteChooserDialogManager extends BaseMediaRouteDialogManager
} }
@Override @Override
public void onDismiss(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
super.onDismiss(dialog); mCancelled = true;
if (!mIsSinkSelected) mManager.delegate().onDialogCancelled();
}
private class DelayedSelectionDialog extends MediaRouteChooserDialog { mManager.delegate().onDialogCancelled();
public DelayedSelectionDialog(Context context) {
super(context);
}
public DelayedSelectionDialog(Context context, int theme) { super.onCancel(dialog);
super(context, theme);
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onDismiss(DialogInterface dialog) {
super.onCreate(savedInstanceState); super.onDismiss(dialog);
if (mManager == null) return;
ListView listView = (ListView) findViewById(R.id.mr_chooser_list); mManager.mDialogFragment = null;
if (listView != null) {
listView.setOnItemClickListener(Fragment.this::onItemClick);
}
}
}
private void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (mCancelled) return;
MediaRouter.RouteInfo routeInfo =
(MediaRouter.RouteInfo) parent.getItemAtPosition(position);
if (routeInfo != null && routeInfo.isEnabled()) {
MediaSink newSink = MediaSink.fromRoute(routeInfo);
// When a item is clicked, the route is not selected right away. Instead, the route MediaSink newSink =
// selection is postponed to the actual session launch. MediaSink.fromRoute(mManager.androidMediaRouter().getSelectedRoute());
mManager.delegate().onSinkSelected(mManager.sourceId(), newSink); mManager.delegate().onSinkSelected(mManager.sourceId(), newSink);
mIsSinkSelected = true;
dismiss();
}
} }
} }
......
...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.media.router.caf; ...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.media.router.caf;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting; import android.support.annotation.VisibleForTesting;
import android.support.v7.media.MediaRouter;
import com.google.android.gms.cast.CastDevice; import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.framework.CastSession; import com.google.android.gms.cast.framework.CastSession;
...@@ -30,6 +31,7 @@ public class BaseSessionController { ...@@ -30,6 +31,7 @@ public class BaseSessionController {
private CastSession mCastSession; private CastSession mCastSession;
private final CafBaseMediaRouteProvider mProvider; private final CafBaseMediaRouteProvider mProvider;
private final MediaRouter.Callback mMediaRouterCallbackForSessionLaunch;
private CreateRouteRequestInfo mRouteCreationInfo; private CreateRouteRequestInfo mRouteCreationInfo;
@VisibleForTesting @VisibleForTesting
CafNotificationController mNotificationController; CafNotificationController mNotificationController;
...@@ -37,6 +39,7 @@ public class BaseSessionController { ...@@ -37,6 +39,7 @@ public class BaseSessionController {
public BaseSessionController(CafBaseMediaRouteProvider provider) { public BaseSessionController(CafBaseMediaRouteProvider provider) {
mProvider = provider; mProvider = provider;
mMediaRouterCallbackForSessionLaunch = new MediaRouterCallbackForSessionLaunch();
mNotificationController = new CafNotificationController(this); mNotificationController = new CafNotificationController(this);
mRemoteMediaClientCallback = new RemoteMediaClientCallback(); mRemoteMediaClientCallback = new RemoteMediaClientCallback();
} }
...@@ -46,11 +49,22 @@ public class BaseSessionController { ...@@ -46,11 +49,22 @@ public class BaseSessionController {
CastUtils.getCastContext().setReceiverApplicationId( CastUtils.getCastContext().setReceiverApplicationId(
mRouteCreationInfo.source.getApplicationId()); mRouteCreationInfo.source.getApplicationId());
// When the user clicks a route on the MediaRouteChooserDialog, we intercept the click event if (mRouteCreationInfo.routeInfo.isSelected()) {
// and do not select the route. Instead the route selection is postponed to here. This will // If a route has just been selected, CAF might not be ready yet before setting the app
// trigger CAF to launch the session. // ID. So unselect and select the route will let CAF be aware that the route has been
// selected thus it can start the session.
//
// An issue of this workaround is that if a route is unselected and selected in a very
// short time, the selection might be ignored by MediaRouter, so put the reselection in
// a callback.
mProvider.getAndroidMediaRouter().addCallback(
mRouteCreationInfo.source.buildRouteSelector(),
mMediaRouterCallbackForSessionLaunch);
mProvider.getAndroidMediaRouter().unselect(MediaRouter.UNSELECT_REASON_UNKNOWN);
} else {
mRouteCreationInfo.routeInfo.select(); mRouteCreationInfo.routeInfo.select();
} }
}
public MediaSource getSource() { public MediaSource getSource() {
return (mRouteCreationInfo != null) ? mRouteCreationInfo.source : null; return (mRouteCreationInfo != null) ? mRouteCreationInfo.source : null;
...@@ -159,6 +173,20 @@ public class BaseSessionController { ...@@ -159,6 +173,20 @@ public class BaseSessionController {
} }
} }
private class MediaRouterCallbackForSessionLaunch extends MediaRouter.Callback {
@Override
public void onRouteUnselected(MediaRouter mediaRouter, MediaRouter.RouteInfo routeInfo) {
if (mProvider.getPendingCreateRouteRequestInfo() == null) return;
if (routeInfo.getId().equals(
mProvider.getPendingCreateRouteRequestInfo().routeInfo.getId())) {
routeInfo.select();
mProvider.getAndroidMediaRouter().removeCallback(
mMediaRouterCallbackForSessionLaunch);
}
}
}
private class RemoteMediaClientCallback extends RemoteMediaClient.Callback { private class RemoteMediaClientCallback extends RemoteMediaClient.Callback {
@Override @Override
public void onStatusUpdated() { public void onStatusUpdated() {
......
...@@ -173,32 +173,18 @@ public abstract class BaseMediaRouteProvider ...@@ -173,32 +173,18 @@ public abstract class BaseMediaRouteProvider
return; return;
} }
MediaRouter.RouteInfo targetRouteInfo = null; MediaSink sink = MediaSink.fromSinkId(sinkId, mAndroidMediaRouter);
for (MediaRouter.RouteInfo routeInfo : mAndroidMediaRouter.getRoutes()) { if (sink == null) {
if (routeInfo.getId().equals(sinkId)) {
targetRouteInfo = routeInfo;
break;
}
}
if (targetRouteInfo == null) {
mManager.onRouteRequestError("No sink", nativeRequestId); mManager.onRouteRequestError("No sink", nativeRequestId);
return; return;
} }
MediaSink sink = MediaSink.fromRoute(targetRouteInfo);
MediaSource source = getSourceFromId(sourceId); MediaSource source = getSourceFromId(sourceId);
if (source == null) { if (source == null) {
mManager.onRouteRequestError("Unsupported source URL", nativeRequestId); mManager.onRouteRequestError("Unsupported source URL", nativeRequestId);
return; return;
} }
// When the user clicks a route on the MediaRouteChooserDialog, we intercept the click event
// and do not select the route. Instead the route selection is postponed to here. This will
// make sure the MediaRouteControllerDialog show up properly.
targetRouteInfo.select();
ChromeCastSessionManager.CastSessionLaunchRequest request = createSessionLaunchRequest( ChromeCastSessionManager.CastSessionLaunchRequest request = createSessionLaunchRequest(
source, sink, presentationId, origin, tabId, isIncognito, nativeRequestId); source, sink, presentationId, origin, tabId, isIncognito, nativeRequestId);
......
...@@ -13,6 +13,7 @@ import static org.mockito.Mockito.any; ...@@ -13,6 +13,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
...@@ -114,14 +115,51 @@ public class BaseSessionControllerTest { ...@@ -114,14 +115,51 @@ public class BaseSessionControllerTest {
assertNull(mController.getRouteCreationInfo()); assertNull(mController.getRouteCreationInfo());
} }
/**
* Test the case of requesting a session launch while the requested route is not selected. The
* controller should set the receiver app ID and then select the route so CAF will start the
* session once observed the route selection.
*/
@Test @Test
public void testRequestSessionLaunch() { public void testRequestSessionLaunch_routeNotSelected() {
mController.requestSessionLaunch(); mController.requestSessionLaunch();
verify(mCastContext).setReceiverApplicationId(APP_ID); verify(mCastContext).setReceiverApplicationId(APP_ID);
verify(mMediaRouterHelper.getCastRoute()).select(); verify(mMediaRouterHelper.getCastRoute()).select();
assertSame(mRequestInfo, mController.getRouteCreationInfo()); assertSame(mRequestInfo, mController.getRouteCreationInfo());
} }
/**
* Test the case of requesting a session launch while the requested route is already selected.
* The controller should first unselect the route, set the application ID and then select the
* route again to notify CAF to start the session.
*/
@Test
public void testRequestSessionLaunch_routeSelected() {
mMediaRouterHelper.selectRoute(mMediaRouterHelper.getCastRoute());
ArgumentCaptor<MediaRouter.Callback> callbackCaptor =
ArgumentCaptor.forClass(MediaRouter.Callback.class);
mController.requestSessionLaunch();
verify(mCastContext).setReceiverApplicationId(APP_ID);
verify(mMediaRouterHelper.getShadowImpl())
.addCallback(eq(mMediaRouteSelector), callbackCaptor.capture());
assertSame(mRequestInfo, mController.getRouteCreationInfo());
verify(mMediaRouterHelper.getShadowImpl()).unselect(MediaRouter.UNSELECT_REASON_UNKNOWN);
// Simulate another route has been unselected.
callbackCaptor.getValue().onRouteUnselected(
MediaRouter.getInstance(mContext), mMediaRouterHelper.getOtherCastRoute());
assertFalse(mMediaRouterHelper.getCastRoute().isSelected());
// Simulate the cast route has been unselected.
callbackCaptor.getValue().onRouteUnselected(
MediaRouter.getInstance(mContext), mMediaRouterHelper.getCastRoute());
assertTrue(mMediaRouterHelper.getCastRoute().isSelected());
}
@Test @Test
public void testEndSession() { public void testEndSession() {
mController.endSession(); mController.endSession();
......
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