Commit b64dfd77 authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

weblayer: adds BrowserFragmentViewController

And adds support for BrowserFragmentControllerImpl containing multiple
BrowserControllers. This patch doesn't contain support for creating
more than one BrowserController in a BrowserFragment. That will come
next.

The reason I'm seperating the Views is to support multiple browsers,
and it seems as though we should support deleting the view, which
is easier with a self contained class.

BUG=none
TEST=none

Change-Id: Idc4a6b2405350b5f9f84d1c046c6d8f839a87ac6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1894749
Auto-Submit: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Commit-Queue: Bo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712115}
parent 349f218f
......@@ -25,6 +25,7 @@ android_library("java") {
java_files = [
"org/chromium/weblayer_private/BrowserControllerImpl.java",
"org/chromium/weblayer_private/BrowserFragmentControllerImpl.java",
"org/chromium/weblayer_private/BrowserFragmentViewController.java",
"org/chromium/weblayer_private/BrowserFragmentImpl.java",
"org/chromium/weblayer_private/BrowserCallbackProxy.java",
"org/chromium/weblayer_private/ChildProcessServiceImpl.java",
......
......@@ -8,27 +8,47 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.ValueCallback;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.weblayer_private.aidl.IBrowserController;
import org.chromium.weblayer_private.aidl.IBrowserFragmentController;
import org.chromium.weblayer_private.aidl.IObjectWrapper;
import org.chromium.weblayer_private.aidl.IProfile;
import org.chromium.weblayer_private.aidl.ObjectWrapper;
import java.util.ArrayList;
/**
* Implementation of {@link IBrowserFragmentController}.
*/
public class BrowserFragmentControllerImpl extends IBrowserFragmentController.Stub {
private final ProfileImpl mProfile;
private BrowserControllerImpl mTabController;
private BrowserFragmentViewController mViewController;
private FragmentWindowAndroid mWindowAndroid;
private ArrayList<BrowserControllerImpl> mBrowsers = new ArrayList<BrowserControllerImpl>();
public BrowserFragmentControllerImpl(ProfileImpl profile, Bundle savedInstanceState) {
mProfile = profile;
// Restore tabs etc from savedInstanceState here.
}
public WindowAndroid getWindowAndroid() {
return mWindowAndroid;
}
public ViewGroup getViewAndroidDelegateContainerView() {
return mViewController.getContentView();
}
public void onFragmentAttached(Context context, FragmentWindowAndroid windowAndroid) {
mTabController = new BrowserControllerImpl(context, mProfile, windowAndroid);
mWindowAndroid = windowAndroid;
mViewController = new BrowserFragmentViewController(context, windowAndroid);
BrowserControllerImpl browser = new BrowserControllerImpl(mProfile, windowAndroid);
attachBrowserController(browser);
boolean set_active_result = setActiveBrowserController(browser);
assert set_active_result;
}
public void onFragmentDetached() {
......@@ -49,22 +69,27 @@ public class BrowserFragmentControllerImpl extends IBrowserFragmentController.St
}
@Override
public void setTopView(IObjectWrapper view) {
getBrowserController().setTopView(view);
public void setTopView(IObjectWrapper viewWrapper) {
getViewController().setTopView(ObjectWrapper.unwrap(viewWrapper, View.class));
}
@Override
public void setSupportsEmbedding(boolean enable, IObjectWrapper valueCallback) {
getBrowserController().setSupportsEmbedding(enable, valueCallback);
getViewController().setSupportsEmbedding(enable,
(ValueCallback<Boolean>) ObjectWrapper.unwrap(valueCallback, ValueCallback.class));
}
@Override
public BrowserControllerImpl getBrowserController() {
if (mTabController == null) {
return getViewController().getBrowserController();
}
public BrowserFragmentViewController getViewController() {
if (mViewController == null) {
throw new RuntimeException("Currently BrowserController requires Activity context, so "
+ "it exists only while BrowserFragment is attached to an Activity");
}
return mTabController;
return mViewController;
}
@Override
......@@ -72,15 +97,53 @@ public class BrowserFragmentControllerImpl extends IBrowserFragmentController.St
return mProfile;
}
public void attachBrowserController(IBrowserController iBrowserController) {
BrowserControllerImpl browserController = (BrowserControllerImpl) iBrowserController;
if (browserController.getFragment() == this) return;
attachBrowserControllerImpl(browserController);
}
private void attachBrowserControllerImpl(BrowserControllerImpl browser) {
// Null case is only during initial creation.
if (browser.getFragment() != this && browser.getFragment() != null) {
browser.getFragment().detachBrowserController(browser);
}
mBrowsers.add(browser);
browser.attachToFragment(this);
}
public void detachBrowserController(IBrowserController controller) {
BrowserControllerImpl browser = (BrowserControllerImpl) controller;
if (browser.getFragment() != this) return;
if (getActiveBrowserController() == browser) setActiveBrowserController(null);
mBrowsers.remove(browser);
// This doesn't reset state on BrowserControllerImpl as |browser| is either about to be
// destroyed, or switching to a different fragment.
}
public boolean setActiveBrowserController(BrowserControllerImpl browser) {
if (browser.getFragment() != this) return false;
mViewController.setActiveBrowserController(browser);
return true;
}
public BrowserControllerImpl getActiveBrowserController() {
return mViewController.getBrowserController();
}
public View getFragmentView() {
return mTabController.getView();
return getViewController().getView();
}
public void destroy() {
if (mTabController != null) {
mTabController.destroy();
mTabController = null;
if (mViewController != null) {
mViewController.destroy();
for (BrowserControllerImpl browser : mBrowsers) {
browser.destroy();
}
mViewController = null;
}
mWindowAndroid = null;
mViewController = null;
}
}
// 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.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.webkit.ValueCallback;
import android.widget.FrameLayout;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ViewAndroidDelegate;
import org.chromium.ui.base.WindowAndroid;
/**
* BrowserFragmentViewController controls the set of Views needed to show the
* WebContents.
*/
@JNINamespace("weblayer")
public final class BrowserFragmentViewController
implements TopControlsContainerView.Listener,
WebContentsGestureStateTracker.OnGestureStateChangedListener {
private final ContentViewRenderView mContentViewRenderView;
private final ContentView mContentView;
// Child of mContentViewRenderView, holds top-view from client.
private final TopControlsContainerView mTopControlsContainerView;
private BrowserControllerImpl mBrowserController;
private WebContentsGestureStateTracker mGestureStateTracker;
/**
* The value of mCachedDoBrowserControlsShrinkRendererSize is set when
* WebContentsGestureStateTracker begins a gesture. This is necessary as the values should only
* change once a gesture is no longer under way.
*/
private boolean mCachedDoBrowserControlsShrinkRendererSize;
public BrowserFragmentViewController(Context context, WindowAndroid windowAndroid) {
mContentViewRenderView = new ContentViewRenderView(context);
mContentViewRenderView.onNativeLibraryLoaded(
windowAndroid, ContentViewRenderView.MODE_SURFACE_VIEW);
mTopControlsContainerView =
new TopControlsContainerView(context, mContentViewRenderView, this);
mContentView = ContentView.createContentView(
context, mTopControlsContainerView.getEventOffsetHandler());
ViewAndroidDelegate viewAndroidDelegate = new ViewAndroidDelegate(mContentView) {
@Override
public void onTopControlsChanged(int topControlsOffsetY, int topContentOffsetY) {
mTopControlsContainerView.onTopControlsChanged(
topControlsOffsetY, topContentOffsetY);
}
};
mContentViewRenderView.addView(mContentView,
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.UNSPECIFIED_GRAVITY));
mContentView.addView(mTopControlsContainerView,
new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT,
Gravity.FILL_HORIZONTAL | Gravity.TOP));
}
public void destroy() {
setActiveBrowserController(null);
mTopControlsContainerView.destroy();
mContentViewRenderView.destroy();
}
/** Returns top-level View this Controller works with */
public View getView() {
return mContentViewRenderView;
}
public ViewGroup getContentView() {
return mContentView;
}
public void setActiveBrowserController(BrowserControllerImpl browserController) {
if (browserController == mBrowserController) return;
if (mBrowserController != null) {
mBrowserController.onDidLoseActive();
// WebContentsGestureStateTracker is relatively cheap, easier to destroy rather than
// update WebContents.
mGestureStateTracker.destroy();
mGestureStateTracker = null;
}
mBrowserController = browserController;
WebContents webContents =
mBrowserController != null ? mBrowserController.getWebContents() : null;
mContentView.setWebContents(webContents);
mContentViewRenderView.setWebContents(webContents);
mTopControlsContainerView.setWebContents(webContents);
if (mBrowserController != null) {
mGestureStateTracker =
new WebContentsGestureStateTracker(mContentView, webContents, this);
mBrowserController.onDidGainActive(mTopControlsContainerView.getNativeHandle());
mContentView.requestFocus();
}
}
public BrowserControllerImpl getBrowserController() {
return mBrowserController;
}
public void setTopView(View view) {
mTopControlsContainerView.setView(view);
}
@Override
public void onTopControlsCompletelyShownOrHidden() {
adjustWebContentsHeightIfNecessary();
}
@Override
public void onGestureStateChanged() {
if (mGestureStateTracker.isInGestureOrScroll()) {
mCachedDoBrowserControlsShrinkRendererSize =
mTopControlsContainerView.isTopControlVisible();
}
adjustWebContentsHeightIfNecessary();
}
private void adjustWebContentsHeightIfNecessary() {
if (mGestureStateTracker.isInGestureOrScroll()
|| !mTopControlsContainerView.isTopControlsCompletelyShownOrHidden()) {
return;
}
mContentViewRenderView.setWebContentsHeightDelta(
mTopControlsContainerView.getTopContentOffset());
}
public void setSupportsEmbedding(boolean enable, ValueCallback<Boolean> callback) {
mContentViewRenderView.requestMode(enable ? ContentViewRenderView.MODE_TEXTURE_VIEW
: ContentViewRenderView.MODE_SURFACE_VIEW,
callback);
}
public void onTopControlsChanged(int topControlsOffsetY, int topContentOffsetY) {
mTopControlsContainerView.onTopControlsChanged(topControlsOffsetY, topContentOffsetY);
}
public boolean doBrowserControlsShrinkRendererSize() {
return (mGestureStateTracker.isInGestureOrScroll())
? mCachedDoBrowserControlsShrinkRendererSize
: mTopControlsContainerView.isTopControlVisible();
}
}
......@@ -47,13 +47,11 @@ public class ContentView extends FrameLayout
public static final int DEFAULT_MEASURE_SPEC =
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
private final WebContents mWebContents;
private WebContents mWebContents;
private final ObserverList<OnHierarchyChangeListener> mHierarchyChangeListeners =
new ObserverList<>();
private final ObserverList<OnSystemUiVisibilityChangeListener> mSystemUiChangeListeners =
new ObserverList<>();
private ViewEventSink mViewEventSink;
private EventForwarder mEventForwarder;
/**
* The desired size of this view in {@link MeasureSpec}. Set by the host
......@@ -72,11 +70,11 @@ public class ContentView extends FrameLayout
* @return an instance of a ContentView.
*/
public static ContentView createContentView(
Context context, WebContents webContents, EventOffsetHandler eventOffsetHandler) {
Context context, EventOffsetHandler eventOffsetHandler) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return new ContentViewApi23(context, webContents, eventOffsetHandler);
return new ContentViewApi23(context, eventOffsetHandler);
}
return new ContentView(context, webContents, eventOffsetHandler);
return new ContentView(context, eventOffsetHandler);
}
/**
......@@ -85,7 +83,7 @@ public class ContentView extends FrameLayout
* access the current theme, resources, etc.
* @param webContents A pointer to the WebContents managing this content view.
*/
ContentView(Context context, WebContents webContents, EventOffsetHandler eventOffsetHandler) {
ContentView(Context context, EventOffsetHandler eventOffsetHandler) {
super(context, null, android.R.attr.webViewStyle);
if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) {
......@@ -93,7 +91,6 @@ public class ContentView extends FrameLayout
setVerticalScrollBarEnabled(false);
}
mWebContents = webContents;
mEventOffsetHandler = eventOffsetHandler;
setFocusable(true);
......@@ -108,8 +105,13 @@ public class ContentView extends FrameLayout
}
protected WebContentsAccessibility getWebContentsAccessibility() {
return !mWebContents.isDestroyed() ? WebContentsAccessibility.fromWebContents(mWebContents)
: null;
return mWebContents != null && !mWebContents.isDestroyed()
? WebContentsAccessibility.fromWebContents(mWebContents)
: null;
}
public void setWebContents(WebContents webContents) {
mWebContents = webContents;
}
@Override
......@@ -228,13 +230,13 @@ public class ContentView extends FrameLayout
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
// Calls may come while/after WebContents is destroyed. See https://crbug.com/821750#c8.
if (mWebContents.isDestroyed()) return null;
if (mWebContents != null && mWebContents.isDestroyed()) return null;
return ImeAdapter.fromWebContents(mWebContents).onCreateInputConnection(outAttrs);
}
@Override
public boolean onCheckIsTextEditor() {
if (mWebContents.isDestroyed()) return false;
if (mWebContents != null && mWebContents.isDestroyed()) return false;
return ImeAdapter.fromWebContents(mWebContents).onCheckIsTextEditor();
}
......@@ -319,15 +321,11 @@ public class ContentView extends FrameLayout
}
private EventForwarder getEventForwarder() {
if (mEventForwarder == null) {
mEventForwarder = mWebContents.getEventForwarder();
}
return mEventForwarder;
return mWebContents != null ? mWebContents.getEventForwarder() : null;
}
private ViewEventSink getViewEventSink() {
if (mViewEventSink == null) mViewEventSink = ViewEventSink.from(mWebContents);
return mViewEventSink;
return mWebContents != null ? ViewEventSink.from(mWebContents) : null;
}
@Override
......@@ -359,40 +357,44 @@ public class ContentView extends FrameLayout
@Override
protected int computeHorizontalScrollExtent() {
RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents);
RenderCoordinates rc = getRenderCoordinates();
return rc != null ? rc.getLastFrameViewportWidthPixInt() : 0;
}
@Override
protected int computeHorizontalScrollOffset() {
RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents);
RenderCoordinates rc = getRenderCoordinates();
return rc != null ? rc.getScrollXPixInt() : 0;
}
@Override
protected int computeHorizontalScrollRange() {
RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents);
RenderCoordinates rc = getRenderCoordinates();
return rc != null ? rc.getContentWidthPixInt() : 0;
}
@Override
protected int computeVerticalScrollExtent() {
RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents);
RenderCoordinates rc = getRenderCoordinates();
return rc != null ? rc.getLastFrameViewportHeightPixInt() : 0;
}
@Override
protected int computeVerticalScrollOffset() {
RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents);
RenderCoordinates rc = getRenderCoordinates();
return rc != null ? rc.getScrollYPixInt() : 0;
}
@Override
protected int computeVerticalScrollRange() {
RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents);
RenderCoordinates rc = getRenderCoordinates();
return rc != null ? rc.getContentHeightPixInt() : 0;
}
private RenderCoordinates getRenderCoordinates() {
return mWebContents != null ? RenderCoordinates.fromWebContents(mWebContents) : null;
}
// End FrameLayout overrides.
@Override
......@@ -419,13 +421,17 @@ public class ContentView extends FrameLayout
// Implements SmartClipProvider
@Override
public void extractSmartClipData(int x, int y, int width, int height) {
mWebContents.requestSmartClipExtract(x, y, width, height);
if (mWebContents != null) {
mWebContents.requestSmartClipExtract(x, y, width, height);
}
}
// Implements SmartClipProvider
@Override
public void setSmartClipResultHandler(final Handler resultHandler) {
mWebContents.setSmartClipResultHandler(resultHandler);
if (mWebContents != null) {
mWebContents.setSmartClipResultHandler(resultHandler);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
......@@ -452,9 +458,8 @@ public class ContentView extends FrameLayout
///////////////////////////////////////////////////////////////////////////////////////////////
private static class ContentViewApi23 extends ContentView {
public ContentViewApi23(
Context context, WebContents webContents, EventOffsetHandler eventOffsetHandler) {
super(context, webContents, eventOffsetHandler);
public ContentViewApi23(Context context, EventOffsetHandler eventOffsetHandler) {
super(context, eventOffsetHandler);
}
@Override
......
......@@ -592,7 +592,7 @@ public class ContentViewRenderView extends FrameLayout {
mNativeContentViewRenderView = 0;
}
public void setCurrentWebContents(WebContents webContents) {
public void setWebContents(WebContents webContents) {
assert mNativeContentViewRenderView != 0;
mWebContents = webContents;
......
......@@ -100,11 +100,10 @@ class TopControlsContainerView extends FrameLayout {
mNativeTopControlsContainerView, TopControlsContainerView.this);
};
TopControlsContainerView(Context context, WebContents webContents,
ContentViewRenderView contentViewRenderView, Listener listener) {
TopControlsContainerView(
Context context, ContentViewRenderView contentViewRenderView, Listener listener) {
super(context);
mContentViewRenderView = contentViewRenderView;
mWebContents = webContents;
mEventOffsetHandler =
new EventOffsetHandler(new EventOffsetHandler.EventOffsetHandlerDelegate() {
@Override
......@@ -114,15 +113,23 @@ class TopControlsContainerView extends FrameLayout {
@Override
public void setCurrentTouchEventOffsets(float top) {
mWebContents.getEventForwarder().setCurrentTouchEventOffsets(0, top);
if (mWebContents != null) {
mWebContents.getEventForwarder().setCurrentTouchEventOffsets(0, top);
}
}
});
mNativeTopControlsContainerView =
TopControlsContainerViewJni.get().createTopControlsContainerView(
this, webContents, contentViewRenderView.getNativeHandle());
this, contentViewRenderView.getNativeHandle());
mListener = listener;
}
public void setWebContents(WebContents webContents) {
mWebContents = webContents;
TopControlsContainerViewJni.get().setWebContents(
mNativeTopControlsContainerView, TopControlsContainerView.this, webContents);
}
public void destroy() {
setView(null);
TopControlsContainerViewJni.get().deleteTopControlsContainerView(
......@@ -324,8 +331,8 @@ class TopControlsContainerView extends FrameLayout {
@NativeMethods
interface Natives {
long createTopControlsContainerView(TopControlsContainerView view, WebContents webContents,
long nativeContentViewRenderView);
long createTopControlsContainerView(
TopControlsContainerView view, long nativeContentViewRenderView);
void deleteTopControlsContainerView(
long nativeTopControlsContainerView, TopControlsContainerView caller);
void createTopControlsLayer(
......@@ -338,5 +345,7 @@ class TopControlsContainerView extends FrameLayout {
TopControlsContainerView caller, int width, int height);
void updateTopControlsResource(
long nativeTopControlsContainerView, TopControlsContainerView caller);
void setWebContents(long nativeTopControlsContainerView, TopControlsContainerView caller,
WebContents webContents);
}
}
......@@ -22,13 +22,10 @@ namespace weblayer {
TopControlsContainerView::TopControlsContainerView(
const base::android::JavaParamRef<jobject>&
java_top_controls_container_view,
content::WebContents* web_contents,
ContentViewRenderView* content_view_render_view)
: 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);
Observe(web_contents);
}
TopControlsContainerView::~TopControlsContainerView() = default;
......@@ -75,8 +72,10 @@ void TopControlsContainerView::SetTopControlsOffset(
// height.
if (top_controls_layer_)
top_controls_layer_->SetPosition(gfx::PointF(0, top_controls_offset_y));
web_contents()->GetNativeView()->GetLayer()->SetPosition(
gfx::PointF(0, top_content_offset_y));
if (web_contents()) {
web_contents()->GetNativeView()->GetLayer()->SetPosition(
gfx::PointF(0, top_content_offset_y));
}
}
void TopControlsContainerView::SetTopControlsSize(
......@@ -101,6 +100,13 @@ void TopControlsContainerView::UpdateTopControlsResource(
top_controls_resource->ui_resource()->id());
}
void TopControlsContainerView::SetWebContents(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller,
const base::android::JavaParamRef<jobject>& web_contents) {
Observe(content::WebContents::FromJavaWebContents(web_contents));
}
void TopControlsContainerView::DidToggleFullscreenModeForTab(
bool entered_fullscreen,
bool will_cause_resize) {
......@@ -113,11 +119,9 @@ 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)));
}
......
......@@ -30,7 +30,6 @@ class TopControlsContainerView : public content::WebContentsObserver {
public:
TopControlsContainerView(const base::android::JavaParamRef<jobject>&
java_top_controls_container_view,
content::WebContents* web_contents,
ContentViewRenderView* content_view_render_view);
~TopControlsContainerView() override;
......@@ -71,6 +70,10 @@ class TopControlsContainerView : public content::WebContentsObserver {
JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller);
void SetWebContents(JNIEnv* env,
const base::android::JavaParamRef<jobject>& caller,
const base::android::JavaParamRef<jobject>& web_contents);
private:
// WebContentsObserver:
void DidToggleFullscreenModeForTab(bool entered_fullscreen,
......
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