Commit 47bd294d authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

weblayer: adds fullscreen support

BUG=none
TEST=none

Change-Id: Id93a18c55d148eb9cf4f7fea9a53f2c4add63d6f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1861514
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706635}
parent ea3e8b05
......@@ -60,6 +60,7 @@ jumbo_static_library("weblayer_lib") {
"common/content_client_impl.h",
"public/browser_controller.h",
"public/browser_observer.h",
"public/fullscreen_delegate.h",
"public/main.h",
"public/navigation.h",
"public/navigation_controller.h",
......@@ -153,6 +154,8 @@ jumbo_static_library("weblayer_lib") {
"browser/browser_observer_proxy.h",
"browser/content_view_render_view.cc",
"browser/content_view_render_view.h",
"browser/fullscreen_delegate_proxy.cc",
"browser/fullscreen_delegate_proxy.h",
"browser/top_controls_container_view.cc",
"browser/top_controls_container_view.h",
]
......
......@@ -4,13 +4,16 @@
#include "weblayer/browser/browser_controller_impl.h"
#include "base/auto_reset.h"
#include "base/logging.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/browser_controls_state.h"
#include "weblayer/browser/navigation_controller_impl.h"
#include "weblayer/browser/profile_impl.h"
#include "weblayer/public/browser_observer.h"
#include "weblayer/public/fullscreen_delegate.h"
#if !defined(OS_ANDROID)
#include "ui/views/controls/webview/webview.h"
......@@ -26,6 +29,14 @@ namespace weblayer {
namespace {
// Pointer value of this is used as a key in base::SupportsUserData for
// WebContents. Value of the key is an instance of |UserData|.
constexpr int kWebContentsUserDataKey = 0;
struct UserData : public base::SupportsUserData::Data {
BrowserControllerImpl* controller = nullptr;
};
#if defined(OS_ANDROID)
BrowserController* g_last_browser_controller;
#endif
......@@ -40,6 +51,9 @@ BrowserControllerImpl::BrowserControllerImpl(ProfileImpl* profile)
content::WebContents::CreateParams create_params(
profile_->GetBrowserContext());
web_contents_ = content::WebContents::Create(create_params);
std::unique_ptr<UserData> user_data = std::make_unique<UserData>();
user_data->controller = this;
web_contents_->SetUserData(&kWebContentsUserDataKey, std::move(user_data));
web_contents_->SetDelegate(this);
Observe(web_contents_.get());
......@@ -53,6 +67,36 @@ BrowserControllerImpl::~BrowserControllerImpl() {
web_contents_.reset();
}
// static
BrowserControllerImpl* BrowserControllerImpl::FromWebContents(
content::WebContents* web_contents) {
return reinterpret_cast<UserData*>(
web_contents->GetUserData(&kWebContentsUserDataKey))
->controller;
}
void BrowserControllerImpl::SetFullscreenDelegate(
FullscreenDelegate* delegate) {
if (delegate == fullscreen_delegate_)
return;
const bool had_delegate = (fullscreen_delegate_ != nullptr);
const bool has_delegate = (delegate != nullptr);
// If currently fullscreen, and the delegate is being set to null, force an
// exit now (otherwise the delegate can't take us out of fullscreen).
if (is_fullscreen_ && fullscreen_delegate_ && had_delegate != has_delegate)
OnExitFullscreen();
fullscreen_delegate_ = delegate;
// Whether fullscreen is enabled depends upon whether there is a delegate. If
// having a delegate changed, then update the renderer (which is where
// fullscreen enabled is tracked).
content::RenderViewHost* host = web_contents_->GetRenderViewHost();
if (had_delegate != has_delegate && host)
host->OnWebkitPreferencesChanged();
}
void BrowserControllerImpl::AddObserver(BrowserObserver* observer) {
observers_.AddObserver(observer);
}
......@@ -134,6 +178,39 @@ bool BrowserControllerImpl::DoBrowserControlsShrinkRendererSize(
return true;
}
bool BrowserControllerImpl::EmbedsFullscreenWidget() {
return true;
}
void BrowserControllerImpl::EnterFullscreenModeForTab(
content::WebContents* web_contents,
const GURL& origin,
const blink::mojom::FullscreenOptions& options) {
// TODO: support |options|.
is_fullscreen_ = true;
auto exit_fullscreen_closure = base::BindOnce(
&BrowserControllerImpl::OnExitFullscreen, weak_ptr_factory_.GetWeakPtr());
base::AutoReset<bool> reset(&processing_enter_fullscreen_, true);
fullscreen_delegate_->EnterFullscreen(std::move(exit_fullscreen_closure));
}
void BrowserControllerImpl::ExitFullscreenModeForTab(
content::WebContents* web_contents) {
is_fullscreen_ = false;
fullscreen_delegate_->ExitFullscreen();
}
bool BrowserControllerImpl::IsFullscreenForTabOrPending(
const content::WebContents* web_contents) {
return is_fullscreen_;
}
blink::mojom::DisplayMode BrowserControllerImpl::GetDisplayMode(
const content::WebContents* web_contents) {
return is_fullscreen_ ? blink::mojom::DisplayMode::kFullscreen
: blink::mojom::DisplayMode::kBrowser;
}
void BrowserControllerImpl::DidFirstVisuallyNonEmptyPaint() {
for (auto& observer : observers_)
observer.FirstContentfulPaint();
......@@ -156,6 +233,15 @@ void BrowserControllerImpl::DidFinishNavigation(
#endif
}
void BrowserControllerImpl::OnExitFullscreen() {
// If |processing_enter_fullscreen_| is true, it means the callback is being
// called while processing EnterFullscreenModeForTab(). WebContents doesn't
// deal well with this. FATAL as Android generally doesn't run with DCHECKs.
LOG_IF(FATAL, !processing_enter_fullscreen_)
<< "exiting fullscreen while entering fullscreen is not supported";
web_contents_->ExitFullscreen(/* will_cause_resize */ false);
}
std::unique_ptr<BrowserController> BrowserController::Create(Profile* profile) {
return std::make_unique<BrowserControllerImpl>(
static_cast<ProfileImpl*>(profile));
......
......@@ -5,7 +5,10 @@
#ifndef WEBLAYER_BROWSER_BROWSER_CONTROLLER_IMPL_H_
#define WEBLAYER_BROWSER_BROWSER_CONTROLLER_IMPL_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "build/build_config.h"
#include "content/public/browser/web_contents_delegate.h"
......@@ -21,6 +24,7 @@ class WebContents;
}
namespace weblayer {
class FullscreenDelegate;
class NavigationControllerImpl;
class ProfileImpl;
......@@ -35,6 +39,11 @@ class BrowserControllerImpl : public BrowserController,
explicit BrowserControllerImpl(ProfileImpl* profile);
~BrowserControllerImpl() override;
// Returns the BrowserControllerImpl from the specified WebContents, or null
// if BrowserControllerImpl was not created by a BrowserControllerImpl.
static BrowserControllerImpl* FromWebContents(
content::WebContents* web_contents);
content::WebContents* web_contents() const { return web_contents_.get(); }
#if defined(OS_ANDROID)
......@@ -47,8 +56,11 @@ class BrowserControllerImpl : public BrowserController,
jlong native_top_controls_container_view);
#endif
FullscreenDelegate* fullscreen_delegate() { return fullscreen_delegate_; }
private:
// BrowserController implementation:
void SetFullscreenDelegate(FullscreenDelegate* delegate) override;
void AddObserver(BrowserObserver* observer) override;
void RemoveObserver(BrowserObserver* observer) override;
NavigationController* GetNavigationController() override;
......@@ -66,12 +78,26 @@ class BrowserControllerImpl : public BrowserController,
int GetTopControlsHeight() override;
bool DoBrowserControlsShrinkRendererSize(
const content::WebContents* web_contents) override;
bool EmbedsFullscreenWidget() override;
void EnterFullscreenModeForTab(
content::WebContents* web_contents,
const GURL& origin,
const blink::mojom::FullscreenOptions& options) override;
void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
bool IsFullscreenForTabOrPending(
const content::WebContents* web_contents) override;
blink::mojom::DisplayMode GetDisplayMode(
const content::WebContents* web_contents) override;
// content::WebContentsObserver implementation:
void DidFirstVisuallyNonEmptyPaint() override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
// Called from closure supplied to delegate to exit fullscreen.
void OnExitFullscreen();
FullscreenDelegate* fullscreen_delegate_ = nullptr;
ProfileImpl* profile_;
std::unique_ptr<content::WebContents> web_contents_;
std::unique_ptr<NavigationControllerImpl> navigation_controller_;
......@@ -80,6 +106,12 @@ class BrowserControllerImpl : public BrowserController,
TopControlsContainerView* top_controls_container_view_ = nullptr;
#endif
bool is_fullscreen_ = false;
// Set to true doing EnterFullscreenModeForTab().
bool processing_enter_fullscreen_ = false;
base::WeakPtrFactory<BrowserControllerImpl> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(BrowserControllerImpl);
};
......
......@@ -17,14 +17,17 @@
#include "content/public/browser/network_service_instance.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/common/user_agent.h"
#include "content/public/common/web_preferences.h"
#include "services/network/network_service.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
#include "url/gurl.h"
#include "url/origin.h"
#include "weblayer/browser/browser_controller_impl.h"
#include "weblayer/browser/browser_main_parts_impl.h"
#include "weblayer/browser/weblayer_content_browser_overlay_manifest.h"
#include "weblayer/public/fullscreen_delegate.h"
#include "weblayer/public/main.h"
#if defined(OS_ANDROID)
......@@ -99,6 +102,19 @@ blink::UserAgentMetadata ContentBrowserClientImpl::GetUserAgentMetadata() {
return metadata;
}
void ContentBrowserClientImpl::OverrideWebkitPrefs(
content::RenderViewHost* render_view_host,
content::WebPreferences* prefs) {
content::WebContents* web_contents =
content::WebContents::FromRenderViewHost(render_view_host);
if (!web_contents)
return;
BrowserControllerImpl* browser_controller =
BrowserControllerImpl::FromWebContents(web_contents);
prefs->fullscreen_supported =
browser_controller && browser_controller->fullscreen_delegate();
}
mojo::Remote<network::mojom::NetworkContext>
ContentBrowserClientImpl::CreateNetworkContext(
content::BrowserContext* context,
......
......@@ -35,6 +35,8 @@ class ContentBrowserClientImpl : public content::ContentBrowserClient {
base::StringPiece name) override;
std::string GetUserAgent() override;
blink::UserAgentMetadata GetUserAgentMetadata() override;
void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
content::WebPreferences* prefs) override;
mojo::Remote<network::mojom::NetworkContext> CreateNetworkContext(
content::BrowserContext* context,
bool in_memory,
......
// Copyright 2019 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.
#include "weblayer/browser/fullscreen_delegate_proxy.h"
#include "base/android/jni_string.h"
#include "url/gurl.h"
#include "weblayer/browser/browser_controller_impl.h"
#include "weblayer/browser/java/jni/FullscreenDelegateProxy_jni.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;
namespace weblayer {
FullscreenDelegateProxy::FullscreenDelegateProxy(
JNIEnv* env,
jobject obj,
BrowserController* browser_controller)
: browser_controller_(browser_controller), java_observer_(env, obj) {
browser_controller_->SetFullscreenDelegate(this);
}
FullscreenDelegateProxy::~FullscreenDelegateProxy() {
browser_controller_->SetFullscreenDelegate(nullptr);
}
void FullscreenDelegateProxy::EnterFullscreen(base::OnceClosure exit_closure) {
exit_fullscreen_closure_ = std::move(exit_closure);
Java_FullscreenDelegateProxy_enterFullscreen(AttachCurrentThread(),
java_observer_);
}
void FullscreenDelegateProxy::ExitFullscreen() {
Java_FullscreenDelegateProxy_exitFullscreen(AttachCurrentThread(),
java_observer_);
}
void FullscreenDelegateProxy::DoExitFullscreen(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller) {
if (exit_fullscreen_closure_)
std::move(exit_fullscreen_closure_).Run();
}
static jlong JNI_FullscreenDelegateProxy_CreateFullscreenDelegateProxy(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& proxy,
jlong browser_controller) {
return reinterpret_cast<jlong>(new FullscreenDelegateProxy(
env, proxy,
reinterpret_cast<BrowserControllerImpl*>(browser_controller)));
}
static void JNI_FullscreenDelegateProxy_DeleteFullscreenDelegateProxy(
JNIEnv* env,
jlong proxy) {
delete reinterpret_cast<FullscreenDelegateProxy*>(proxy);
}
} // namespace weblayer
// Copyright 2019 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.
#ifndef WEBLAYER_BROWSER_FULLSCREEN_DELEGATE_PROXY_H_
#define WEBLAYER_BROWSER_FULLSCREEN_DELEGATE_PROXY_H_
#include <jni.h>
#include "base/android/scoped_java_ref.h"
#include "base/callback.h"
#include "base/macros.h"
#include "weblayer/public/fullscreen_delegate.h"
namespace weblayer {
class BrowserController;
// FullscreenDelegateProxy forwards all FullscreenDelegate functions to the
// Java side. There is at most one FullscreenDelegateProxy per
// BrowserController.
class FullscreenDelegateProxy : public FullscreenDelegate {
public:
FullscreenDelegateProxy(JNIEnv* env,
jobject obj,
BrowserController* browser_controller);
~FullscreenDelegateProxy() override;
// FullscreenDelegate:
void EnterFullscreen(base::OnceClosure exit_closure) override;
void ExitFullscreen() override;
// Called from the Java side to exit fullscreen.
void DoExitFullscreen(JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller);
private:
BrowserController* browser_controller_;
base::android::ScopedJavaGlobalRef<jobject> java_observer_;
base::OnceClosure exit_fullscreen_closure_;
DISALLOW_COPY_AND_ASSIGN(FullscreenDelegateProxy);
};
} // namespace weblayer
#endif // WEBLAYER_BROWSER_FULLSCREEN_DELEGATE_PROXY_H_
......@@ -18,6 +18,7 @@ android_library("java") {
"org/chromium/weblayer_private/BrowserObserverProxy.java",
"org/chromium/weblayer_private/ContentView.java",
"org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/FullscreenDelegateProxy.java",
"org/chromium/weblayer_private/NavigationControllerImpl.java",
"org/chromium/weblayer_private/NavigationImpl.java",
"org/chromium/weblayer_private/ProfileImpl.java",
......@@ -44,6 +45,7 @@ generate_jni("jni") {
"org/chromium/weblayer_private/BrowserControllerImpl.java",
"org/chromium/weblayer_private/BrowserObserverProxy.java",
"org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/FullscreenDelegateProxy.java",
"org/chromium/weblayer_private/NavigationControllerImpl.java",
"org/chromium/weblayer_private/NavigationImpl.java",
"org/chromium/weblayer_private/ProfileImpl.java",
......@@ -71,6 +73,7 @@ android_aidl("aidl") {
"org/chromium/weblayer_private/aidl/IBrowserFragmentController.aidl",
"org/chromium/weblayer_private/aidl/IChildProcessService.aidl",
"org/chromium/weblayer_private/aidl/IClientNavigation.aidl",
"org/chromium/weblayer_private/aidl/IFullscreenDelegateClient.aidl",
"org/chromium/weblayer_private/aidl/INavigation.aidl",
"org/chromium/weblayer_private/aidl/INavigationController.aidl",
"org/chromium/weblayer_private/aidl/INavigationControllerClient.aidl",
......
......@@ -21,6 +21,7 @@ import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.weblayer_private.aidl.IBrowserController;
import org.chromium.weblayer_private.aidl.IBrowserControllerClient;
import org.chromium.weblayer_private.aidl.IFullscreenDelegateClient;
import org.chromium.weblayer_private.aidl.INavigationControllerClient;
import org.chromium.weblayer_private.aidl.IObjectWrapper;
import org.chromium.weblayer_private.aidl.ObjectWrapper;
......@@ -42,6 +43,7 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
private WebContents mWebContents;
private BrowserObserverProxy mBrowserObserverProxy;
private NavigationControllerImpl mNavigationController;
private FullscreenDelegateProxy mFullscreenDelegateProxy;
private static class InternalAccessDelegateImpl
implements ViewEventSink.InternalAccessDelegate {
......@@ -127,13 +129,34 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
mBrowserObserverProxy = new BrowserObserverProxy(mNativeBrowserController, client);
}
@Override
public void setFullscreenDelegateClient(IFullscreenDelegateClient client) {
if (client != null) {
if (mFullscreenDelegateProxy == null) {
mFullscreenDelegateProxy =
new FullscreenDelegateProxy(mNativeBrowserController, client);
} else {
mFullscreenDelegateProxy.setClient(client);
}
} else if (mFullscreenDelegateProxy != null) {
mFullscreenDelegateProxy.destroy();
mFullscreenDelegateProxy = null;
}
}
public void destroy() {
BrowserControllerImplJni.get().setTopControlsContainerView(
mNativeBrowserController, BrowserControllerImpl.this, 0);
mTopControlsContainerView.destroy();
mContentViewRenderView.destroy();
if (mBrowserObserverProxy != null) mBrowserObserverProxy.destroy();
mBrowserObserverProxy = null;
if (mBrowserObserverProxy != null) {
mBrowserObserverProxy.destroy();
mBrowserObserverProxy = null;
}
if (mFullscreenDelegateProxy != null) {
mFullscreenDelegateProxy.destroy();
mFullscreenDelegateProxy = null;
}
mNavigationController = null;
BrowserControllerImplJni.get().deleteBrowserController(mNativeBrowserController);
mNativeBrowserController = 0;
......
// Copyright 2019 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;
import android.os.RemoteException;
import android.webkit.ValueCallback;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.weblayer_private.aidl.APICallException;
import org.chromium.weblayer_private.aidl.IFullscreenDelegateClient;
import org.chromium.weblayer_private.aidl.ObjectWrapper;
/**
* Owns the c++ FullscreenDelegateProxy class, which is responsible for forwarding all
* FullscreenDelegate delegate calls to this class, which in turn forwards to the
* FullscreenDelegateClient.
*/
@JNINamespace("weblayer")
public final class FullscreenDelegateProxy {
private long mNativeFullscreenDelegateProxy;
private IFullscreenDelegateClient mClient;
FullscreenDelegateProxy(long browserController, IFullscreenDelegateClient client) {
assert client != null;
mClient = client;
mNativeFullscreenDelegateProxy =
FullscreenDelegateProxyJni.get().createFullscreenDelegateProxy(
this, browserController);
}
public void setClient(IFullscreenDelegateClient client) {
assert client != null;
mClient = client;
}
public void destroy() {
FullscreenDelegateProxyJni.get().deleteFullscreenDelegateProxy(
mNativeFullscreenDelegateProxy);
mNativeFullscreenDelegateProxy = 0;
}
@CalledByNative
private void enterFullscreen() {
try {
ValueCallback<Void> exitFullscreenCallback = new ValueCallback<Void>() {
@Override
public void onReceiveValue(Void result) {
if (mNativeFullscreenDelegateProxy == 0) {
throw new IllegalStateException("Called after destroy()");
}
FullscreenDelegateProxyJni.get().doExitFullscreen(
mNativeFullscreenDelegateProxy, FullscreenDelegateProxy.this);
}
};
mClient.enterFullscreen(ObjectWrapper.wrap(exitFullscreenCallback));
} catch (RemoteException e) {
throw new APICallException(e);
}
}
@CalledByNative
private void exitFullscreen() {
try {
mClient.exitFullscreen();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
@NativeMethods
interface Natives {
long createFullscreenDelegateProxy(FullscreenDelegateProxy proxy, long browserController);
void deleteFullscreenDelegateProxy(long proxy);
void doExitFullscreen(long nativeFullscreenDelegateProxy, FullscreenDelegateProxy proxy);
}
}
......@@ -12,6 +12,7 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
import android.widget.FrameLayout;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.WebContents;
......@@ -31,6 +32,8 @@ class TopControlsContainerView extends FrameLayout {
// ID used with ViewResourceAdapter.
private static final int TOP_CONTROLS_ID = 1001;
private static final long SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS = 500;
private long mNativeTopControlsContainerView;
private ViewResourceAdapter mViewResourceAdapter;
......@@ -50,6 +53,11 @@ class TopControlsContainerView extends FrameLayout {
// True if scrolling.
private boolean mInTopControlsScroll;
private boolean mIsFullscreen;
// Used to delay processing fullscreen requests.
private Runnable mSystemUiFullscreenResizeRunnable;
// Used to delay updating the image for the layer.
private final Runnable mRefreshResourceIdRunnable = () -> {
if (mView == null) return;
......@@ -76,7 +84,7 @@ class TopControlsContainerView extends FrameLayout {
});
mNativeTopControlsContainerView =
TopControlsContainerViewJni.get().createTopControlsContainerView(
webContents, contentViewRenderView.getNativeHandle());
this, webContents, contentViewRenderView.getNativeHandle());
}
public void destroy() {
......@@ -117,6 +125,7 @@ class TopControlsContainerView extends FrameLayout {
view.layout(0, 0, getWidth(), getHeight());
createAdapterAndLayer();
}
if (mIsFullscreen) hideTopControls();
}
public View getView() {
......@@ -128,6 +137,7 @@ class TopControlsContainerView extends FrameLayout {
*/
public void onTopControlsChanged(int topControlsOffsetY, int topContentOffsetY) {
if (mView == null) return;
if (mIsFullscreen) return;
if (topContentOffsetY == getHeight()) {
finishTopControlsScroll(topContentOffsetY);
return;
......@@ -225,10 +235,35 @@ class TopControlsContainerView extends FrameLayout {
if (mView != null) mView.setVisibility(View.VISIBLE);
}
@CalledByNative
private void didToggleFullscreenModeForTab(final boolean isFullscreen) {
// Delay hiding until after the animation. This comes from Chrome code.
if (mSystemUiFullscreenResizeRunnable != null) {
getHandler().removeCallbacks(mSystemUiFullscreenResizeRunnable);
}
mSystemUiFullscreenResizeRunnable = () -> processFullscreenChanged(isFullscreen);
long delay = isFullscreen ? SYSTEM_UI_VIEWPORT_UPDATE_DELAY_MS : 0;
postDelayed(mSystemUiFullscreenResizeRunnable, delay);
}
private void processFullscreenChanged(boolean isFullscreen) {
mSystemUiFullscreenResizeRunnable = null;
if (mIsFullscreen == isFullscreen) return;
mIsFullscreen = isFullscreen;
if (mView == null) return;
if (mIsFullscreen) {
hideTopControls();
setTopControlsOffset(-mLastHeight, 0);
} else {
showTopControls();
setTopControlsOffset(0, mLastHeight);
}
}
@NativeMethods
interface Natives {
long createTopControlsContainerView(
WebContents webContents, long nativeContentViewRenderView);
long createTopControlsContainerView(TopControlsContainerView view, WebContents webContents,
long nativeContentViewRenderView);
void deleteTopControlsContainerView(
long nativeTopControlsContainerView, TopControlsContainerView caller);
void createTopControlsLayer(
......
......@@ -5,6 +5,7 @@
package org.chromium.weblayer_private.aidl;
import org.chromium.weblayer_private.aidl.IBrowserControllerClient;
import org.chromium.weblayer_private.aidl.IFullscreenDelegateClient;
import org.chromium.weblayer_private.aidl.INavigationController;
import org.chromium.weblayer_private.aidl.INavigationControllerClient;
......@@ -12,4 +13,6 @@ interface IBrowserController {
void setClient(in IBrowserControllerClient client) = 0;
INavigationController createNavigationController(in INavigationControllerClient client) = 1;
void setFullscreenDelegateClient(in IFullscreenDelegateClient client) = 2;
}
// Copyright 2019 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.aidl;
import org.chromium.weblayer_private.aidl.IObjectWrapper;
/**
* Used to forward FullscreenDelegate calls to the client.
*/
interface IFullscreenDelegateClient {
// exitFullscreenWrapper is a ValueCallback<Void> that when run exits
// fullscreen.
void enterFullscreen(in IObjectWrapper exitFullscreenWrapper) = 0;
void exitFullscreen() = 1;
}
......@@ -20,12 +20,15 @@ using base::android::AttachCurrentThread;
namespace weblayer {
TopControlsContainerView::TopControlsContainerView(
const base::android::JavaParamRef<jobject>&
java_top_controls_container_view,
content::WebContents* web_contents,
ContentViewRenderView* content_view_render_view)
: content_view_render_view_(content_view_render_view),
web_contents_(web_contents) {
: java_top_controls_container_view_(java_top_controls_container_view),
content_view_render_view_(content_view_render_view) {
DCHECK(content_view_render_view_);
DCHECK(web_contents_);
DCHECK(web_contents);
Observe(web_contents);
}
TopControlsContainerView::~TopControlsContainerView() = default;
......@@ -70,7 +73,7 @@ void TopControlsContainerView::SetTopControlsOffset(
int top_content_offset_y) {
DCHECK(top_controls_layer_);
top_controls_layer_->SetPosition(gfx::PointF(0, top_controls_offset_y));
web_contents_->GetNativeView()->GetLayer()->SetPosition(
web_contents()->GetNativeView()->GetLayer()->SetPosition(
gfx::PointF(0, top_content_offset_y));
}
......@@ -96,11 +99,22 @@ void TopControlsContainerView::UpdateTopControlsResource(
top_controls_resource->ui_resource()->id());
}
void TopControlsContainerView::DidToggleFullscreenModeForTab(
bool entered_fullscreen,
bool will_cause_resize) {
Java_TopControlsContainerView_didToggleFullscreenModeForTab(
AttachCurrentThread(), java_top_controls_container_view_,
entered_fullscreen);
}
static jlong JNI_TopControlsContainerView_CreateTopControlsContainerView(
JNIEnv* env,
const base::android::JavaParamRef<jobject>&
java_top_controls_container_view,
const base::android::JavaParamRef<jobject>& web_contents,
jlong native_content_view_render_view) {
return reinterpret_cast<jlong>(new TopControlsContainerView(
java_top_controls_container_view,
content::WebContents::FromJavaWebContents(web_contents),
reinterpret_cast<ContentViewRenderView*>(
native_content_view_render_view)));
......
......@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "content/public/browser/web_contents_observer.h"
namespace cc {
class UIResourceLayer;
......@@ -25,11 +26,13 @@ class ContentViewRenderView;
// Native side of TopControlsContainerView. Responsible for creating and
// positioning the cc::Layer that contains an image of the contents of the
// top-control.
class TopControlsContainerView {
class TopControlsContainerView : public content::WebContentsObserver {
public:
TopControlsContainerView(content::WebContents* web_contents,
TopControlsContainerView(const base::android::JavaParamRef<jobject>&
java_top_controls_container_view,
content::WebContents* web_contents,
ContentViewRenderView* content_view_render_view);
~TopControlsContainerView();
~TopControlsContainerView() override;
// Height needed to display the top-control.
int GetTopControlsHeight();
......@@ -69,8 +72,12 @@ class TopControlsContainerView {
const base::android::JavaParamRef<jobject>& caller);
private:
// WebContentsObserver:
void DidToggleFullscreenModeForTab(bool entered_fullscreen,
bool will_cause_resize) override;
base::android::ScopedJavaGlobalRef<jobject> java_top_controls_container_view_;
ContentViewRenderView* content_view_render_view_;
content::WebContents* web_contents_;
int top_controls_resource_id_ = -1;
// Layer containing showing the image for the top-controls. This is a sibling
......
......@@ -17,6 +17,7 @@ class WebView;
namespace weblayer {
class BrowserObserver;
class FullscreenDelegate;
class Profile;
class NavigationController;
......@@ -31,6 +32,10 @@ class BrowserController {
virtual ~BrowserController() {}
// Sets the FullscreenDelegate. Setting a non-null value implicitly enables
// fullscreen.
virtual void SetFullscreenDelegate(FullscreenDelegate* delegate) = 0;
virtual void AddObserver(BrowserObserver* observer) = 0;
virtual void RemoveObserver(BrowserObserver* observer) = 0;
......
// Copyright 2019 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.
#ifndef WEBLAYER_PUBLIC_FULLSCREEN_DELEGATE_H_
#define WEBLAYER_PUBLIC_FULLSCREEN_DELEGATE_H_
#include "base/callback_forward.h"
namespace weblayer {
class FullscreenDelegate {
public:
// Called when the page has requested to go fullscreen.
virtual void EnterFullscreen(base::OnceClosure exit_closure) = 0;
// Informs the delegate the page has exited fullscreen.
virtual void ExitFullscreen() = 0;
protected:
virtual ~FullscreenDelegate() {}
};
} // namespace weblayer
#endif // WEBLAYER_PUBLIC_FULLSCREEN_DELEGATE_H_
......@@ -27,6 +27,7 @@ template("weblayer_java") {
"org/chromium/weblayer/BrowserFragmentController.java",
"org/chromium/weblayer/BrowserObserver.java",
"org/chromium/weblayer/Callback.java",
"org/chromium/weblayer/FullscreenDelegate.java",
"org/chromium/weblayer/ListenableFuture.java",
"org/chromium/weblayer/ListenableResult.java",
"org/chromium/weblayer/Navigation.java",
......
......@@ -6,13 +6,18 @@ package org.chromium.weblayer;
import android.net.Uri;
import android.os.RemoteException;
import android.webkit.ValueCallback;
import org.chromium.weblayer_private.aidl.APICallException;
import org.chromium.weblayer_private.aidl.IBrowserController;
import org.chromium.weblayer_private.aidl.IBrowserControllerClient;
import org.chromium.weblayer_private.aidl.IFullscreenDelegateClient;
import org.chromium.weblayer_private.aidl.IObjectWrapper;
import org.chromium.weblayer_private.aidl.ObjectWrapper;
public final class BrowserController {
private final IBrowserController mImpl;
private FullscreenDelegateClientImpl mFullscreenDelegateClient;
private final NavigationController mNavigationController;
private final ObserverList<BrowserObserver> mObservers;
......@@ -28,6 +33,23 @@ public final class BrowserController {
mNavigationController = NavigationController.create(mImpl);
}
public void setFullscreenDelegate(FullscreenDelegate delegate) {
try {
if (delegate != null) {
mFullscreenDelegateClient = new FullscreenDelegateClientImpl(delegate);
mImpl.setFullscreenDelegateClient(mFullscreenDelegateClient);
} else {
mImpl.setFullscreenDelegateClient(null);
}
} catch (RemoteException e) {
throw new APICallException(e);
}
}
public FullscreenDelegate getFullscreenDelegate() {
return mFullscreenDelegateClient != null ? mFullscreenDelegateClient.getDelegate() : null;
}
@Override
protected void finalize() {
// TODO(sky): figure out right assertion here if mProfile is non-null.
......@@ -72,4 +94,28 @@ public final class BrowserController {
}
}
}
private final class FullscreenDelegateClientImpl extends IFullscreenDelegateClient.Stub {
private FullscreenDelegate mDelegate;
/* package */ FullscreenDelegateClientImpl(FullscreenDelegate delegate) {
mDelegate = delegate;
}
public FullscreenDelegate getDelegate() {
return mDelegate;
}
@Override
public void enterFullscreen(IObjectWrapper exitFullscreenWrapper) {
ValueCallback<Void> exitFullscreenCallback = (ValueCallback<Void>) ObjectWrapper.unwrap(
exitFullscreenWrapper, ValueCallback.class);
mDelegate.enterFullscreen(() -> exitFullscreenCallback.onReceiveValue(null));
}
@Override
public void exitFullscreen() {
mDelegate.exitFullscreen();
}
}
}
// Copyright 2019 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;
/**
* Used to configure fullscreen related state. HTML fullscreen support is only enabled if a
* FullscreenDelegate is set.
*/
public abstract class FullscreenDelegate {
/**
* Called when the page has requested to go fullscreen. The delegate is responsible for
* putting the system into fullscreen mode. The delegate can exit out of fullscreen by
* running the supplied Runnable (calling exitFullscreenRunner.Run() results in calling
* exitFullscreen()).
*
* NOTE: the Runnable must not be used synchronously.
*/
public abstract void enterFullscreen(Runnable exitFullscreenRunner);
/**
* The page has exited fullscreen mode and the system should be moved out of fullscreen mode.
*/
public abstract void exitFullscreen();
}
......@@ -13,7 +13,8 @@
<activity android:name="WebLayerShellActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Holo.Light.NoActionBar"
android:windowSoftInputMode="adjustPan|stateUnspecified">
android:windowSoftInputMode="adjustPan|stateUnspecified"
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
......
......@@ -17,6 +17,7 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.LinearLayout;
......@@ -29,6 +30,7 @@ import org.chromium.weblayer.BrowserController;
import org.chromium.weblayer.BrowserFragment;
import org.chromium.weblayer.BrowserFragmentController;
import org.chromium.weblayer.BrowserObserver;
import org.chromium.weblayer.FullscreenDelegate;
import org.chromium.weblayer.NavigationController;
import org.chromium.weblayer.Profile;
import org.chromium.weblayer.UnsupportedVersionException;
......@@ -130,6 +132,43 @@ public class WebLayerShellActivity extends FragmentActivity {
mFragment = getOrCreateBrowserFragment(savedInstanceState);
mBrowserFragmentController = mFragment.getController();
mBrowserFragmentController.getBrowserController().setFullscreenDelegate(
new FullscreenDelegate() {
private int mSystemVisibilityToRestore;
@Override
public void enterFullscreen(Runnable exitFullscreenRunnable) {
// This comes from Chrome code to avoid an extra resize.
final WindowManager.LayoutParams attrs = getWindow().getAttributes();
attrs.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
getWindow().setAttributes(attrs);
View decorView = getWindow().getDecorView();
// Caching the system ui visibility is ok for shell, but likely not ok for
// real code.
mSystemVisibilityToRestore = decorView.getSystemUiVisibility();
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
@Override
public void exitFullscreen() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(mSystemVisibilityToRestore);
final WindowManager.LayoutParams attrs = getWindow().getAttributes();
if ((attrs.flags & WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
!= 0) {
attrs.flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
getWindow().setAttributes(attrs);
}
}
});
mProfile = mBrowserFragmentController.getProfile();
mBrowserFragmentController.setTopView(mTopContentsContainer);
......
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