Commit f6389814 authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

weblayer: Mark tab as hidden for detached view

If the view of the fragment of a tab is detached from the window (or not
created yet), then mark the WebContents of the tab as hidden. This is to
provide a somewhat reasonable way for the embedder to manipulate the web
hidden state.

Also change newly created TabImpl to be hidden on creation to avoid
unnecessary state flips. This is purely for efficiency, not for
correctness. Left restored tabs alone.

Bug: 1096063
Change-Id: Ie8b5da3bef040536b976435c0507462f7f796c9d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2291691Reviewed-by: default avatarClark DuVall <cduvall@chromium.org>
Commit-Queue: Bo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#787750}
parent ce9136e3
......@@ -6,7 +6,10 @@ package org.chromium.weblayer.test;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.test.filters.SmallTest;
import org.junit.Assert;
......@@ -241,4 +244,24 @@ public class TabTest {
mActivityTestRule.navigateAndWait(
tab, mActivityTestRule.getTestDataURL("simple_page.html"), false);
}
@Test
@SmallTest
@MinWebLayerVersion(86) // New behavior added in 86
public void testViewDetachedTabIsInvisible() throws Exception {
mActivity = mActivityTestRule.launchShellWithUrl("about:blank");
boolean hidden = mActivityTestRule.executeScriptAndExtractBoolean("document.hidden;");
Assert.assertFalse(hidden);
Fragment fragment = mActivityTestRule.getFragment();
TestThreadUtils.runOnUiThreadBlocking(() -> {
View fragmentView = fragment.getView();
ViewGroup parent = (ViewGroup) fragmentView.getParent();
parent.removeView(fragmentView);
});
hidden = mActivityTestRule.executeScriptAndExtractBoolean("document.hidden;");
Assert.assertTrue(hidden);
}
}
......@@ -13,6 +13,7 @@
#include "base/stl_util.h"
#include "components/base32/base32.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/web_preferences.h"
#include "weblayer/browser/browser_list.h"
#include "weblayer/browser/feature_list_creator.h"
......@@ -114,6 +115,11 @@ BrowserImpl::~BrowserImpl() {
TabImpl* BrowserImpl::CreateTabForSessionRestore(
std::unique_ptr<content::WebContents> web_contents,
const std::string& guid) {
if (!web_contents) {
content::WebContents::CreateParams create_params(
profile_->GetBrowserContext());
web_contents = content::WebContents::Create(create_params);
}
std::unique_ptr<TabImpl> tab =
std::make_unique<TabImpl>(profile_, std::move(web_contents), guid);
#if defined(OS_ANDROID)
......
......@@ -36,7 +36,7 @@ import java.util.List;
* Implementation of {@link IBrowser}.
*/
@JNINamespace("weblayer")
public class BrowserImpl extends IBrowser.Stub {
public class BrowserImpl extends IBrowser.Stub implements View.OnAttachStateChangeListener {
private final ObserverList<VisibleSecurityStateObserver> mVisibleSecurityStateObservers =
new ObserverList<VisibleSecurityStateObserver>();
......@@ -68,6 +68,7 @@ public class BrowserImpl extends IBrowser.Stub {
private Boolean mPasswordEchoEnabled;
private Boolean mDarkThemeEnabled;
private Float mFontScale;
private boolean mViewAttachedToWindow;
// Created in the constructor from saved state and used in setClient().
private PersistenceInfo mPersistenceInfo;
......@@ -135,7 +136,7 @@ public class BrowserImpl extends IBrowser.Stub {
assert mEmbedderActivityContext == null;
mWindowAndroid = windowAndroid;
mEmbedderActivityContext = embedderAppContext;
mViewController = new BrowserViewController(windowAndroid);
mViewController = new BrowserViewController(windowAndroid, this);
mLocaleReceiver = new LocaleChangedBroadcastReceiver(windowAndroid.getContext().get());
mPasswordEchoEnabled = null;
}
......@@ -488,6 +489,30 @@ public class BrowserImpl extends IBrowser.Stub {
return mFragmentStoppedForConfigurationChange;
}
public boolean isViewAttachedToWindow() {
return mViewAttachedToWindow;
}
@Override
public void onViewAttachedToWindow(View v) {
mViewAttachedToWindow = true;
updateAllTabsViewAttachedState();
}
@Override
public void onViewDetachedFromWindow(View v) {
// Note this separate state is needed because v.isAttachedToWindow()
// still returns true inside this call.
mViewAttachedToWindow = false;
updateAllTabsViewAttachedState();
}
private void updateAllTabsViewAttachedState() {
for (Object tab : getTabs()) {
((TabImpl) tab).updateViewAttachedStateFromBrowser();
}
}
private void destroyAttachmentState() {
if (mLocaleReceiver != null) {
mLocaleReceiver.destroy();
......@@ -496,6 +521,8 @@ public class BrowserImpl extends IBrowser.Stub {
if (mViewController != null) {
mViewController.destroy();
mViewController = null;
mViewAttachedToWindow = false;
updateAllTabsViewAttachedState();
}
if (mWindowAndroid != null) {
mWindowAndroid.destroy();
......
......@@ -53,6 +53,7 @@ public final class BrowserViewController
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
private final FragmentWindowAndroid mWindowAndroid;
private final View.OnAttachStateChangeListener mOnAttachedStateChangeListener;
private final ModalDialogManager mModalDialogManager;
private TabImpl mTab;
......@@ -66,10 +67,13 @@ public final class BrowserViewController
*/
private boolean mCachedDoBrowserControlsShrinkRendererSize;
public BrowserViewController(FragmentWindowAndroid windowAndroid) {
public BrowserViewController(
FragmentWindowAndroid windowAndroid, View.OnAttachStateChangeListener listener) {
mWindowAndroid = windowAndroid;
mOnAttachedStateChangeListener = listener;
Context context = mWindowAndroid.getContext().get();
mContentViewRenderView = new ContentViewRenderView(context);
mContentViewRenderView.addOnAttachStateChangeListener(listener);
mContentViewRenderView.onNativeLibraryLoaded(
mWindowAndroid, ContentViewRenderView.MODE_SURFACE_VIEW);
......@@ -116,6 +120,7 @@ public final class BrowserViewController
public void destroy() {
mWindowAndroid.setModalDialogManager(null);
setActiveTab(null);
mContentViewRenderView.removeOnAttachStateChangeListener(mOnAttachedStateChangeListener);
mTopControlsContainerView.destroy();
mBottomControlsContainerView.destroy();
mContentViewRenderView.destroy();
......
......@@ -311,7 +311,7 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
mWebContents.setTopLevelNativeWindow(mBrowser.getWindowAndroid());
mViewAndroidDelegate.setContainerView(mBrowser.getViewAndroidDelegateContainerView());
doInitAfterSettingContainerView();
updateWebContentsVisibility();
updateViewAttachedStateFromBrowser();
boolean attached = (mBrowser.getContext() != null);
mInterceptNavigationDelegateClient.onActivityAttachmentChanged(attached);
......@@ -343,6 +343,10 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
}
}
public void updateViewAttachedStateFromBrowser() {
updateWebContentsVisibility();
}
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
if (mAutofillProvider == null) return;
mAutofillProvider.onProvideAutoFillVirtualStructure(structure, flags);
......@@ -411,8 +415,9 @@ public final class TabImpl extends ITab.Stub implements LoginPrompt.Observer {
* Returns whether this Tab is visible.
*/
public boolean isVisible() {
return (mBrowser.getActiveTab() == this
&& (mBrowser.isStarted() || mBrowser.isFragmentStoppedForConfigurationChange()));
return mBrowser.getActiveTab() == this
&& (mBrowser.isStarted() || mBrowser.isFragmentStoppedForConfigurationChange())
&& mBrowser.isViewAttachedToWindow();
}
private void updateWebContentsVisibility() {
......
......@@ -240,8 +240,10 @@ static ScopedJavaLocalRef<jobject> JNI_TabImpl_FromWebContents(
return nullptr;
}
TabImpl::TabImpl(ProfileImpl* profile, const JavaParamRef<jobject>& java_impl)
: TabImpl(profile) {
TabImpl::TabImpl(ProfileImpl* profile,
const JavaParamRef<jobject>& java_impl,
std::unique_ptr<content::WebContents> web_contents)
: TabImpl(profile, std::move(web_contents)) {
java_impl_ = java_impl;
}
#endif
......@@ -253,16 +255,10 @@ TabImpl::TabImpl(ProfileImpl* profile,
web_contents_(std::move(web_contents)),
guid_(guid.empty() ? base::GenerateGUID() : guid) {
GetTabs().insert(this);
if (web_contents_) {
// This code path is hit when the page requests a new tab, which should
// only be possible from the same profile.
DCHECK_EQ(profile_->GetBrowserContext(),
web_contents_->GetBrowserContext());
} else {
content::WebContents::CreateParams create_params(
profile_->GetBrowserContext());
web_contents_ = content::WebContents::Create(create_params);
}
DCHECK(web_contents_);
// This code path is hit when the page requests a new tab, which should
// only be possible from the same profile.
DCHECK_EQ(profile_->GetBrowserContext(), web_contents_->GetBrowserContext());
// By default renderer initiated navigations inherit the user-agent override
// of the current NavigationEntry. For WebLayer, the user-agent override is
......@@ -542,8 +538,12 @@ void TabImpl::DisableAutofillSystemIntegrationForTesting() {
static jlong JNI_TabImpl_CreateTab(JNIEnv* env,
jlong profile,
const JavaParamRef<jobject>& java_impl) {
return reinterpret_cast<intptr_t>(
new TabImpl(reinterpret_cast<ProfileImpl*>(profile), java_impl));
ProfileImpl* profile_impl = reinterpret_cast<ProfileImpl*>(profile);
content::WebContents::CreateParams create_params(
profile_impl->GetBrowserContext());
create_params.initially_hidden = true;
return reinterpret_cast<intptr_t>(new TabImpl(
profile_impl, java_impl, content::WebContents::Create(create_params)));
}
static void JNI_TabImpl_DeleteTab(JNIEnv* env, jlong tab) {
......
......@@ -99,10 +99,11 @@ class TabImpl : public Tab,
// TODO(sky): investigate a better way to not have so many ifdefs.
#if defined(OS_ANDROID)
TabImpl(ProfileImpl* profile,
const base::android::JavaParamRef<jobject>& java_impl);
const base::android::JavaParamRef<jobject>& java_impl,
std::unique_ptr<content::WebContents> web_contents);
#endif
explicit TabImpl(ProfileImpl* profile,
std::unique_ptr<content::WebContents> = nullptr,
std::unique_ptr<content::WebContents> web_contents,
const std::string& guid = std::string());
~TabImpl() override;
......
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