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

weblayer: adds NewTabCallback.CloseTab()

This is called when a tab opened by way of window.open() is asked to
close (window.close()).

BUG=none
TEST=covered by test

Change-Id: I0d97069faed7a77edfef2e2932328e271d5d6db1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1913601
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715086}
parent 22a820c1
......@@ -20,6 +20,11 @@ public class NewTabCallbackImpl extends NewTabCallback {
tab.getBrowser().setActiveTab(tab);
}
@Override
public void onCloseTab() {
assert false;
}
public void waitForNewTab() {
try {
// waitForFirst() only handles a single call. If you need more convert from
......
......@@ -12,7 +12,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.weblayer.NewTabCallback;
import org.chromium.weblayer.Tab;
import org.chromium.weblayer.shell.InstrumentationActivity;
......@@ -27,6 +29,28 @@ public class NewTabCallbackTest {
private InstrumentationActivity mActivity;
private static final class CloseTabNewTabCallbackImpl extends NewTabCallback {
private final CallbackHelper mCallbackHelper = new CallbackHelper();
@Override
public void onNewTab(Tab tab, int mode) {}
@Override
public void onCloseTab() {
mCallbackHelper.notifyCalled();
}
public void waitForCloseTab() {
try {
// waitForFirst() only handles a single call. If you need more convert from
// waitForFirst().
mCallbackHelper.waitForFirst();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Test
@SmallTest
public void testNewBrowser() {
......@@ -48,4 +72,35 @@ public class NewTabCallbackTest {
Assert.assertNotSame(firstTab, secondTab);
});
}
@Test
@SmallTest
public void testCloseTab() {
String url = mActivityTestRule.getTestDataURL("new_tab_then_close.html");
mActivity = mActivityTestRule.launchShellWithUrl(url);
Assert.assertNotNull(mActivity);
NewTabCallbackImpl callback = new NewTabCallbackImpl();
Tab firstTab = TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
Tab tab = mActivity.getBrowser().getActiveTab();
tab.setNewTabCallback(callback);
return tab;
});
// Click on the tab to trigger creating a new tab.
EventUtils.simulateTouchCenterOfView(mActivity.getWindow().getDecorView());
callback.waitForNewTab();
CloseTabNewTabCallbackImpl closeTabImpl = new CloseTabNewTabCallbackImpl();
TestThreadUtils.runOnUiThreadBlocking(() -> {
Assert.assertEquals(2, mActivity.getBrowser().getTabs().size());
Tab secondTab = mActivity.getBrowser().getActiveTab();
Assert.assertNotSame(firstTab, secondTab);
secondTab.setNewTabCallback(closeTabImpl);
// Switch to the first tab so clicking closes |secondTab|.
secondTab.getBrowser().setActiveTab(firstTab);
});
// Clicking on the tab again to callback to close the tab.
EventUtils.simulateTouchCenterOfView(mActivity.getWindow().getDecorView());
closeTabImpl.waitForCloseTab();
}
}
......@@ -57,6 +57,11 @@ public final class NewTabCallbackProxy {
mTab.getClient().onNewTab(tab.getId(), mode);
}
@CalledByNative
private void onCloseTab() throws RemoteException {
mTab.getClient().onCloseTab();
}
@NativeMethods
interface Natives {
long createNewTabCallbackProxy(NewTabCallbackProxy proxy, long tab);
......
......@@ -14,4 +14,6 @@ interface ITabClient {
void onNewTab(in int tabId, in int mode) = 1;
void onRenderProcessGone() = 2;
void onCloseTab() = 3;
}
......@@ -33,6 +33,10 @@ void NewTabCallbackProxy::OnNewTab(std::unique_ptr<Tab> tab, NewTabType type) {
static_cast<int>(type));
}
void NewTabCallbackProxy::CloseTab() {
Java_NewTabCallbackProxy_onCloseTab(AttachCurrentThread(), java_impl_);
}
static jlong JNI_NewTabCallbackProxy_CreateNewTabCallbackProxy(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& proxy,
......
......@@ -24,6 +24,7 @@ class NewTabCallbackProxy : public NewTabDelegate {
// NewTabDelegate:
void OnNewTab(std::unique_ptr<Tab> tab, NewTabType type) override;
void CloseTab() override;
private:
TabImpl* tab_;
......
......@@ -345,6 +345,11 @@ void TabImpl::AddNewContents(content::WebContents* source,
NewTabTypeFromWindowDisposition(disposition));
}
void TabImpl::CloseContents(content::WebContents* source) {
if (new_tab_delegate_)
new_tab_delegate_->CloseTab();
}
void TabImpl::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
#if defined(OS_ANDROID)
......@@ -363,9 +368,8 @@ void TabImpl::DidFinishNavigation(
}
void TabImpl::RenderProcessGone(base::TerminationStatus status) {
for (auto& observer : observers_) {
for (auto& observer : observers_)
observer.OnRenderProcessGone();
}
}
void TabImpl::OnExitFullscreen() {
......
......@@ -121,6 +121,7 @@ class TabImpl : public Tab,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) override;
void CloseContents(content::WebContents* source) override;
// content::WebContentsObserver:
void DidFinishNavigation(
......
......@@ -11,5 +11,19 @@ import androidx.annotation.NonNull;
* set, popups are disabled.
*/
public abstract class NewTabCallback {
/**
* Called when a new tab has been created.
*
* @param tab The new tab.
* @param type How the tab should be shown.
*/
public abstract void onNewTab(@NonNull Tab tab, @NewTabType int type);
/**
* Called when a tab previously opened via onNewTab() was asked to close. Generally this should
* destroy the Tab and/or Browser.
*
* @see Browser#destroyTab
*/
public abstract void onCloseTab();
}
......@@ -225,6 +225,14 @@ public final class Tab {
mNewTabCallback.onNewTab(tab, mode);
}
@Override
public void onCloseTab() {
// This should only be hit if setNewTabCallback() has been called with a non-null
// value.
assert mNewTabCallback != null;
mNewTabCallback.onCloseTab();
}
@Override
public void onRenderProcessGone() {
for (TabCallback callback : mCallbacks) {
......
......@@ -35,6 +35,11 @@ class NewTabDelegate {
public:
virtual void OnNewTab(std::unique_ptr<Tab> new_tab, NewTabType type) = 0;
// The page has requested a tab that was created by way of OnNewTab() to be
// closed. This is sent to the NewTabDelegate set on the page created by way
// of OnNewTab().
virtual void CloseTab() = 0;
protected:
virtual ~NewTabDelegate() {}
};
......
<html>
<body>
<p>some content</p>
</body>
<script>
var openedWindow = null;
function openNewWindowOrClose() {
if (openedWindow == null) {
openedWindow = window.open('about:blank', '');
} else {
openedWindow.close();
openedWindow = null;
}
}
document.addEventListener('touchend',
function(e) { openNewWindowOrClose(); }, false);
</script>
</html>
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