Commit 7de6b4bd authored by Evan Stade's avatar Evan Stade Committed by Commit Bot

WebLayer: add support for MediaRoute{Controller,Chooser}Dialog

These dialogs are shown when starting to cast or controlling the cast
session. Since they are DialogFragments, a client-side RemoteFragment
is needed to represent them. The implementation is modeled after
SiteSettingsFragmentImpl, although one key difference is that there
is no new Activity. PassthroughFragmentActivity is not refactored for
reuse because it should go away soon, as per crbug.com/1123216

After this change, casting still doesn't work, but the initial
route chooser dialog at least appears.

Bug: 1057100
Change-Id: I9930c6124ff5162a296dcc74637a8489dbb0d96d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2432319
Commit-Queue: Evan Stade <estade@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarRobbie McElrath <rmcelrath@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812524}
parent 71c10e67
...@@ -35,7 +35,6 @@ public abstract class MediaRouterClient { ...@@ -35,7 +35,6 @@ public abstract class MediaRouterClient {
* @param webContents a {@link WebContents} in a tab. * @param webContents a {@link WebContents} in a tab.
* @return a unique integer identifier for the associated tab. * @return a unique integer identifier for the associated tab.
*/ */
public abstract int getTabId(WebContents webContents); public abstract int getTabId(WebContents webContents);
/** /**
......
...@@ -131,6 +131,7 @@ ...@@ -131,6 +131,7 @@
#include "weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h" #include "weblayer/browser/safe_browsing/real_time_url_lookup_service_factory.h"
#include "weblayer/browser/safe_browsing/safe_browsing_service.h" #include "weblayer/browser/safe_browsing/safe_browsing_service.h"
#include "weblayer/browser/tts_environment_android_impl.h" #include "weblayer/browser/tts_environment_android_impl.h"
#include "weblayer/browser/weblayer_factory_impl_android.h"
#endif #endif
#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
...@@ -637,6 +638,9 @@ content::ControllerPresentationServiceDelegate* ...@@ -637,6 +638,9 @@ content::ControllerPresentationServiceDelegate*
ContentBrowserClientImpl::GetControllerPresentationServiceDelegate( ContentBrowserClientImpl::GetControllerPresentationServiceDelegate(
content::WebContents* web_contents) { content::WebContents* web_contents) {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
if (WebLayerFactoryImplAndroid::GetClientMajorVersion() < 87)
return nullptr;
if (base::FeatureList::IsEnabled(features::kMediaRouter)) { if (base::FeatureList::IsEnabled(features::kMediaRouter)) {
MediaRouterFactory::DoPlatformInitIfNeeded(); MediaRouterFactory::DoPlatformInitIfNeeded();
return media_router::PresentationServiceDelegateImpl:: return media_router::PresentationServiceDelegateImpl::
......
...@@ -138,6 +138,7 @@ android_library("java") { ...@@ -138,6 +138,7 @@ android_library("java") {
"org/chromium/weblayer_private/WebLayerTabModalPresenter.java", "org/chromium/weblayer_private/WebLayerTabModalPresenter.java",
"org/chromium/weblayer_private/WebMessageReplyProxyImpl.java", "org/chromium/weblayer_private/WebMessageReplyProxyImpl.java",
"org/chromium/weblayer_private/WebShareServiceFactory.java", "org/chromium/weblayer_private/WebShareServiceFactory.java",
"org/chromium/weblayer_private/media/MediaRouteDialogFragmentImpl.java",
"org/chromium/weblayer_private/media/MediaRouterClientImpl.java", "org/chromium/weblayer_private/media/MediaRouterClientImpl.java",
"org/chromium/weblayer_private/media/MediaSessionManager.java", "org/chromium/weblayer_private/media/MediaSessionManager.java",
"org/chromium/weblayer_private/media/MediaStreamManager.java", "org/chromium/weblayer_private/media/MediaStreamManager.java",
...@@ -412,6 +413,7 @@ android_aidl("aidl") { ...@@ -412,6 +413,7 @@ android_aidl("aidl") {
"org/chromium/weblayer_private/interfaces/IFullscreenCallbackClient.aidl", "org/chromium/weblayer_private/interfaces/IFullscreenCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl", "org/chromium/weblayer_private/interfaces/IGoogleAccountsCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IMediaCaptureCallbackClient.aidl", "org/chromium/weblayer_private/interfaces/IMediaCaptureCallbackClient.aidl",
"org/chromium/weblayer_private/interfaces/IMediaRouteDialogFragment.aidl",
"org/chromium/weblayer_private/interfaces/INavigation.aidl", "org/chromium/weblayer_private/interfaces/INavigation.aidl",
"org/chromium/weblayer_private/interfaces/INavigationController.aidl", "org/chromium/weblayer_private/interfaces/INavigationController.aidl",
"org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl", "org/chromium/weblayer_private/interfaces/INavigationControllerClient.aidl",
......
...@@ -32,6 +32,7 @@ import org.chromium.weblayer_private.interfaces.ITab; ...@@ -32,6 +32,7 @@ import org.chromium.weblayer_private.interfaces.ITab;
import org.chromium.weblayer_private.interfaces.IUrlBarController; import org.chromium.weblayer_private.interfaces.IUrlBarController;
import org.chromium.weblayer_private.interfaces.ObjectWrapper; import org.chromium.weblayer_private.interfaces.ObjectWrapper;
import org.chromium.weblayer_private.interfaces.StrictModeWorkaround; import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
import org.chromium.weblayer_private.media.MediaRouteDialogFragmentImpl;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
...@@ -548,6 +549,15 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan ...@@ -548,6 +549,15 @@ public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChan
updateAllTabsViewAttachedState(); updateAllTabsViewAttachedState();
} }
public MediaRouteDialogFragmentImpl createMediaRouteDialogFragment() {
try {
return MediaRouteDialogFragmentImpl.fromRemoteFragment(
mClient.createMediaRouteDialogFragment());
} catch (RemoteException e) {
throw new APICallException(e);
}
}
private void updateAllTabsViewAttachedState() { private void updateAllTabsViewAttachedState() {
for (Object tab : getTabs()) { for (Object tab : getTabs()) {
((TabImpl) tab).updateViewAttachedStateFromBrowser(); ((TabImpl) tab).updateViewAttachedStateFromBrowser();
......
...@@ -60,6 +60,17 @@ public abstract class RemoteFragmentImpl extends IRemoteFragment.Stub { ...@@ -60,6 +60,17 @@ public abstract class RemoteFragmentImpl extends IRemoteFragment.Stub {
} }
} }
public void removeFragmentFromFragmentManager() {
if (WebLayerFactoryImpl.getClientMajorVersion() < 87) {
return;
}
try {
mClient.removeFragmentFromFragmentManager();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
// TODO(pshmakov): add dependency to androidx.annotation and put @CallSuper here. // TODO(pshmakov): add dependency to androidx.annotation and put @CallSuper here.
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
try { try {
......
...@@ -68,6 +68,7 @@ import org.chromium.ui.base.WindowAndroid; ...@@ -68,6 +68,7 @@ import org.chromium.ui.base.WindowAndroid;
import org.chromium.weblayer_private.interfaces.APICallException; import org.chromium.weblayer_private.interfaces.APICallException;
import org.chromium.weblayer_private.interfaces.IBrowserFragment; import org.chromium.weblayer_private.interfaces.IBrowserFragment;
import org.chromium.weblayer_private.interfaces.ICrashReporterController; import org.chromium.weblayer_private.interfaces.ICrashReporterController;
import org.chromium.weblayer_private.interfaces.IMediaRouteDialogFragment;
import org.chromium.weblayer_private.interfaces.IObjectWrapper; import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.IProfile; import org.chromium.weblayer_private.interfaces.IProfile;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient; import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
...@@ -76,6 +77,7 @@ import org.chromium.weblayer_private.interfaces.IWebLayer; ...@@ -76,6 +77,7 @@ import org.chromium.weblayer_private.interfaces.IWebLayer;
import org.chromium.weblayer_private.interfaces.IWebLayerClient; import org.chromium.weblayer_private.interfaces.IWebLayerClient;
import org.chromium.weblayer_private.interfaces.ObjectWrapper; import org.chromium.weblayer_private.interfaces.ObjectWrapper;
import org.chromium.weblayer_private.interfaces.StrictModeWorkaround; import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
import org.chromium.weblayer_private.media.MediaRouteDialogFragmentImpl;
import org.chromium.weblayer_private.media.MediaSessionManager; import org.chromium.weblayer_private.media.MediaSessionManager;
import org.chromium.weblayer_private.media.MediaStreamManager; import org.chromium.weblayer_private.media.MediaStreamManager;
import org.chromium.weblayer_private.metrics.MetricsServiceClient; import org.chromium.weblayer_private.metrics.MetricsServiceClient;
...@@ -336,6 +338,15 @@ public final class WebLayerImpl extends IWebLayer.Stub { ...@@ -336,6 +338,15 @@ public final class WebLayerImpl extends IWebLayer.Stub {
return fragment.asISiteSettingsFragment(); return fragment.asISiteSettingsFragment();
} }
@Override
public IMediaRouteDialogFragment createMediaRouteDialogFragmentImpl(
IRemoteFragmentClient remoteFragmentClient) {
StrictModeWorkaround.apply();
MediaRouteDialogFragmentImpl fragment =
new MediaRouteDialogFragmentImpl(remoteFragmentClient);
return fragment.asIMediaRouteDialogFragment();
}
@Override @Override
public IProfile getProfile(String profileName) { public IProfile getProfile(String profileName) {
StrictModeWorkaround.apply(); StrictModeWorkaround.apply();
......
...@@ -4,10 +4,14 @@ ...@@ -4,10 +4,14 @@
package org.chromium.weblayer_private.interfaces; package org.chromium.weblayer_private.interfaces;
import org.chromium.weblayer_private.interfaces.IRemoteFragment;
import org.chromium.weblayer_private.interfaces.ITab; import org.chromium.weblayer_private.interfaces.ITab;
interface IBrowserClient { interface IBrowserClient {
void onActiveTabChanged(in int activeTabId) = 0; void onActiveTabChanged(in int activeTabId) = 0;
void onTabAdded(in ITab tab) = 1; void onTabAdded(in ITab tab) = 1;
void onTabRemoved(in int tabId) = 2; void onTabRemoved(in int tabId) = 2;
// Added in 87.
IRemoteFragment createMediaRouteDialogFragment() = 3;
} }
// Copyright 2020 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.weblayer_private.interfaces;
import org.chromium.weblayer_private.interfaces.IRemoteFragment;
interface IMediaRouteDialogFragment {
IRemoteFragment asRemoteFragment() = 0;
}
...@@ -34,4 +34,6 @@ interface IRemoteFragmentClient { ...@@ -34,4 +34,6 @@ interface IRemoteFragmentClient {
void requestPermissions(in String[] permissions, int requestCode) = 15; void requestPermissions(in String[] permissions, int requestCode) = 15;
// Since 84 // Since 84
IObjectWrapper /* View */ getView() = 16; IObjectWrapper /* View */ getView() = 16;
// Since 87
void removeFragmentFromFragmentManager() = 17;
} }
...@@ -12,6 +12,7 @@ import org.chromium.weblayer_private.interfaces.ICrashReporterController; ...@@ -12,6 +12,7 @@ import org.chromium.weblayer_private.interfaces.ICrashReporterController;
import org.chromium.weblayer_private.interfaces.IObjectWrapper; import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.IProfile; import org.chromium.weblayer_private.interfaces.IProfile;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient; import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
import org.chromium.weblayer_private.interfaces.IMediaRouteDialogFragment;
import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment; import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment;
import org.chromium.weblayer_private.interfaces.IWebLayerClient; import org.chromium.weblayer_private.interfaces.IWebLayerClient;
...@@ -101,4 +102,6 @@ interface IWebLayer { ...@@ -101,4 +102,6 @@ interface IWebLayer {
// Added in Version 87. // Added in Version 87.
IObjectWrapper getApplicationContext() = 20; IObjectWrapper getApplicationContext() = 20;
IMediaRouteDialogFragment createMediaRouteDialogFragmentImpl(
in IRemoteFragmentClient remoteFragmentClient) = 21;
} }
...@@ -39,7 +39,10 @@ public class MediaRouterClientImpl extends MediaRouterClient { ...@@ -39,7 +39,10 @@ public class MediaRouterClientImpl extends MediaRouterClient {
@Override @Override
public FragmentManager getSupportFragmentManager(WebContents initiator) { public FragmentManager getSupportFragmentManager(WebContents initiator) {
return null; return TabImpl.fromWebContents(initiator)
.getBrowser()
.createMediaRouteDialogFragment()
.getSupportFragmentManager();
} }
@CalledByNative @CalledByNative
......
...@@ -66,6 +66,7 @@ android_library("java") { ...@@ -66,6 +66,7 @@ android_library("java") {
"org/chromium/weblayer/LoadError.java", "org/chromium/weblayer/LoadError.java",
"org/chromium/weblayer/MediaCaptureCallback.java", "org/chromium/weblayer/MediaCaptureCallback.java",
"org/chromium/weblayer/MediaCaptureController.java", "org/chromium/weblayer/MediaCaptureController.java",
"org/chromium/weblayer/MediaRouteDialogFragment.java",
"org/chromium/weblayer/MediaSessionService.java", "org/chromium/weblayer/MediaSessionService.java",
"org/chromium/weblayer/NavigateParams.java", "org/chromium/weblayer/NavigateParams.java",
"org/chromium/weblayer/Navigation.java", "org/chromium/weblayer/Navigation.java",
......
...@@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment; ...@@ -15,6 +15,7 @@ import androidx.fragment.app.Fragment;
import org.chromium.weblayer_private.interfaces.APICallException; import org.chromium.weblayer_private.interfaces.APICallException;
import org.chromium.weblayer_private.interfaces.IBrowser; import org.chromium.weblayer_private.interfaces.IBrowser;
import org.chromium.weblayer_private.interfaces.IBrowserClient; import org.chromium.weblayer_private.interfaces.IBrowserClient;
import org.chromium.weblayer_private.interfaces.IRemoteFragment;
import org.chromium.weblayer_private.interfaces.ITab; import org.chromium.weblayer_private.interfaces.ITab;
import org.chromium.weblayer_private.interfaces.ObjectWrapper; import org.chromium.weblayer_private.interfaces.ObjectWrapper;
import org.chromium.weblayer_private.interfaces.StrictModeWorkaround; import org.chromium.weblayer_private.interfaces.StrictModeWorkaround;
...@@ -30,6 +31,7 @@ import java.util.Set; ...@@ -30,6 +31,7 @@ import java.util.Set;
public class Browser { public class Browser {
// Set to null once destroyed (or for tests). // Set to null once destroyed (or for tests).
private IBrowser mImpl; private IBrowser mImpl;
private BrowserFragment mFragment;
private final ObserverList<TabListCallback> mTabListCallbacks; private final ObserverList<TabListCallback> mTabListCallbacks;
private final UrlBarController mUrlBarController; private final UrlBarController mUrlBarController;
...@@ -40,8 +42,9 @@ public class Browser { ...@@ -40,8 +42,9 @@ public class Browser {
mUrlBarController = null; mUrlBarController = null;
} }
Browser(IBrowser impl) { Browser(IBrowser impl, BrowserFragment fragment) {
mImpl = impl; mImpl = impl;
mFragment = fragment;
mTabListCallbacks = new ObserverList<TabListCallback>(); mTabListCallbacks = new ObserverList<TabListCallback>();
try { try {
...@@ -72,6 +75,7 @@ public class Browser { ...@@ -72,6 +75,7 @@ public class Browser {
// Called prior to notifying IBrowser of destroy(). // Called prior to notifying IBrowser of destroy().
void prepareForDestroy() { void prepareForDestroy() {
mFragment = null;
for (TabListCallback callback : mTabListCallbacks) { for (TabListCallback callback : mTabListCallbacks) {
callback.onWillDestroyBrowserAndAllTabs(); callback.onWillDestroyBrowserAndAllTabs();
} }
...@@ -385,5 +389,11 @@ public class Browser { ...@@ -385,5 +389,11 @@ public class Browser {
callback.onTabRemoved(tab); callback.onTabRemoved(tab);
} }
} }
@Override
public IRemoteFragment createMediaRouteDialogFragment() {
StrictModeWorkaround.apply();
return MediaRouteDialogFragment.create(mFragment);
}
} }
} }
...@@ -84,7 +84,7 @@ public final class BrowserFragment extends RemoteFragment { ...@@ -84,7 +84,7 @@ public final class BrowserFragment extends RemoteFragment {
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
try { try {
mBrowser = new Browser(mImpl.getBrowser()); mBrowser = new Browser(mImpl.getBrowser(), this);
} catch (RemoteException e) { } catch (RemoteException e) {
throw new APICallException(e); throw new APICallException(e);
} }
......
// Copyright 2020 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.weblayer;
import android.content.Context;
import org.chromium.weblayer_private.interfaces.IRemoteFragment;
/**
* The client-side implementation of MediaRouteDialogFragment.
*
* This class hosts dialog fragments for casting, such as a {@link MediaRouteChooserDialogFragment}
* or a {@link MediaRouteControllerDialogFragment}.
*
* @since 87
*/
class MediaRouteDialogFragment extends RemoteFragment {
private static final String FRAGMENT_TAG = "WebLayerMediaRouteDialogFragment";
static IRemoteFragment create(BrowserFragment browserFragment) {
MediaRouteDialogFragment fragment = new MediaRouteDialogFragment();
browserFragment.getParentFragmentManager()
.beginTransaction()
.add(0, fragment, FRAGMENT_TAG)
.commitNow();
return fragment.getRemoteFragment();
}
@Override
protected IRemoteFragment createRemoteFragment(Context appContext) {
try {
return WebLayer.loadSync(appContext)
.connectMediaRouteDialogFragment(getRemoteFragmentClient())
.asRemoteFragment();
} catch (Exception e) {
throw new RuntimeException("Failed to initialize WebLayer", e);
}
}
}
...@@ -150,6 +150,14 @@ abstract class RemoteFragment extends Fragment { ...@@ -150,6 +150,14 @@ abstract class RemoteFragment extends Fragment {
StrictModeWorkaround.apply(); StrictModeWorkaround.apply();
RemoteFragment.this.requestPermissions(permissions, requestCode); RemoteFragment.this.requestPermissions(permissions, requestCode);
} }
@Override
public void removeFragmentFromFragmentManager() {
StrictModeWorkaround.apply();
Fragment fragment = RemoteFragment.this;
if (fragment.getParentFragmentManager() == null) return;
fragment.getParentFragmentManager().beginTransaction().remove(fragment).commit();
}
}; };
// Nonnull after first onAttach(). // Nonnull after first onAttach().
...@@ -336,4 +344,8 @@ abstract class RemoteFragment extends Fragment { ...@@ -336,4 +344,8 @@ abstract class RemoteFragment extends Fragment {
throw new APICallException(e); throw new APICallException(e);
} }
} }
protected IRemoteFragment getRemoteFragment() {
return mRemoteFragment;
}
} }
...@@ -26,6 +26,7 @@ import androidx.fragment.app.Fragment; ...@@ -26,6 +26,7 @@ import androidx.fragment.app.Fragment;
import org.chromium.weblayer_private.interfaces.APICallException; import org.chromium.weblayer_private.interfaces.APICallException;
import org.chromium.weblayer_private.interfaces.BrowserFragmentArgs; import org.chromium.weblayer_private.interfaces.BrowserFragmentArgs;
import org.chromium.weblayer_private.interfaces.IBrowserFragment; import org.chromium.weblayer_private.interfaces.IBrowserFragment;
import org.chromium.weblayer_private.interfaces.IMediaRouteDialogFragment;
import org.chromium.weblayer_private.interfaces.IProfile; import org.chromium.weblayer_private.interfaces.IProfile;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient; import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment; import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment;
...@@ -559,6 +560,21 @@ public class WebLayer { ...@@ -559,6 +560,21 @@ public class WebLayer {
} }
} }
/**
* Returns the remote counterpart of MediaRouteDialogFragment.
*/
/* package */ IMediaRouteDialogFragment connectMediaRouteDialogFragment(
IRemoteFragmentClient remoteFragmentClient) {
if (getSupportedMajorVersionInternal() < 87) {
throw new UnsupportedOperationException();
}
try {
return mImpl.createMediaRouteDialogFragmentImpl(remoteFragmentClient);
} catch (RemoteException e) {
throw new APICallException(e);
}
}
/* package */ static IWebLayer getIWebLayer(Context context) { /* package */ static IWebLayer getIWebLayer(Context context) {
return getWebLayerLoader(context).getIWebLayer(); return getWebLayerLoader(context).getIWebLayer();
} }
......
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