summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikhail Naganov <mnaganov@chromium.org>2015-03-05 10:28:35 +0000
committerMikhail Naganov <mnaganov@chromium.org>2015-03-05 10:30:07 +0000
commit519e57cb02f6daad52215babe2b2aba9956ae1de (patch)
tree16a45f16671c57797769b7f65f82e56e0fade5e3
parenta4a2c2e6cd74b4438882920d879bd5e99891d38d (diff)
downloadchromium_src-519e57cb02f6daad52215babe2b2aba9956ae1de.zip
chromium_src-519e57cb02f6daad52215babe2b2aba9956ae1de.tar.gz
chromium_src-519e57cb02f6daad52215babe2b2aba9956ae1de.tar.bz2
[Android WebView] Synthesize a fake page loading event on page source modification (Re-land)
When a script modifies page source of a non-committed page, we need to notify clients, so they can update the URL bar to avoid confusion. New logic since the last attempt (https://codereview.chromium.org/924833003/): distinguish between a "vanilla" WebView state (basically, a newly created WebView, where no loading attempts have been made) and an "attempted to navigate" state. In the "vanilla" state, don't fire synthesized page loading events to avoid confusing clients. This is safe, as WebView is guaranteed to be on a blank page. Implementation note: we detect navigation attempts using didStartProvisionalLoadForFrame WebContentsObserver event on the Java side. As for popups AwWebContentsObserver gets re-attached from the original popup WebView to the one provided by the client, notifications issued inbetween can be missed on the Java side. To work around this, we assume that WebViews opened as popups can never be in "vanilla" state (as they are anyway opened as a result of navigation). BUG=458569,462213 TBR=davidben@chromium.org,tedchoc@chromium.org Review URL: https://codereview.chromium.org/970883002 Cr-Commit-Position: refs/heads/master@{#319061} (manually cherry picked from commit b2803fd408c3709889645061fad42d3371024b93) Excluded changes to: android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java because in trunk PopupWindowTest got a heavy refactoring, and the change can't be applied as is (and the changes in AwTestBase are exclusively for the changes in PopupWindowTest). But we don't run these tests on release branches anyway. Review URL: https://codereview.chromium.org/969943005 Cr-Commit-Position: refs/branch-heads/2311@{#148} Cr-Branched-From: 09b7de5dd7254947cd4306de907274fa63373d48-refs/heads/master@{#317474}
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java32
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java4
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java18
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java16
-rw-r--r--android_webview/java_library_common.mk1
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java80
-rw-r--r--android_webview/libwebviewchromium.gypi1
-rw-r--r--android_webview/native/aw_web_contents_delegate.cc12
-rw-r--r--android_webview/native/aw_web_contents_delegate.h2
-rw-r--r--chrome/android/java/src/org/chromium/chrome/browser/Tab.java5
-rw-r--r--components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java13
-rw-r--r--content/browser/web_contents/web_contents_android.cc15
-rw-r--r--content/browser/web_contents/web_contents_android.h4
-rw-r--r--content/content.gyp9
-rw-r--r--content/public/android/BUILD.gn2
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java13
-rw-r--r--content/public/android/java/src/org/chromium/content_public/browser/WebContents.java16
-rw-r--r--content/public/browser/invalidate_type.h5
-rw-r--r--net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java26
19 files changed, 258 insertions, 16 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 8d0d278..4559992 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -49,7 +49,6 @@ import org.chromium.content.browser.ContentViewClient;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.ContentViewStatics;
import org.chromium.content.browser.SmartClipProvider;
-import org.chromium.content.browser.WebContentsObserver;
import org.chromium.content.common.CleanupReference;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.content_public.browser.JavaScriptCallback;
@@ -204,7 +203,7 @@ public class AwContents implements SmartClipProvider,
private NavigationController mNavigationController;
private final AwContentsClient mContentsClient;
private final AwContentViewClient mContentViewClient;
- private WebContentsObserver mWebContentsObserver;
+ private AwWebContentsObserver mWebContentsObserver;
private final AwContentsClientBridge mContentsClientBridge;
private final AwWebContentsDelegateAdapter mWebContentsDelegate;
private final AwContentsIoThreadClient mIoThreadClient;
@@ -227,6 +226,8 @@ public class AwContents implements SmartClipProvider,
private boolean mHasRequestedVisitedHistoryFromClient;
// TODO(boliu): This should be in a global context, not per webview.
private final double mDIPScale;
+ // Whether the WebView has attempted to do any load (including uncommitted loads).
+ private boolean mDidAttemptLoad = false;
// The base background color, i.e. not accounting for any CSS body from the current page.
private int mBaseBackgroundColor = Color.WHITE;
@@ -908,6 +909,9 @@ public class AwContents implements SmartClipProvider,
if (wasWindowFocused) onWindowFocusChanged(wasWindowFocused);
if (wasFocused) onFocusChanged(true, 0, null);
+ // Popups are always assumed as having made a load attempt.
+ mDidAttemptLoad = true;
+
// Restore injected JavaScript interfaces.
for (Map.Entry<String, Pair<Object, Class>> entry : javascriptInterfaces.entrySet()) {
@SuppressWarnings("unchecked")
@@ -1239,6 +1243,19 @@ public class AwContents implements SmartClipProvider,
return url;
}
+ /**
+ * Gets the last committed URL. It represents the current page that is
+ * displayed in WebContents. It represents the current security context.
+ *
+ * @return The URL of the current page or null if it's empty.
+ */
+ public String getLastCommittedUrl() {
+ if (isDestroyed()) return null;
+ String url = mWebContents.getLastCommittedUrl();
+ if (url == null || url.trim().isEmpty()) return null;
+ return url;
+ }
+
public void requestFocus() {
mAwViewMethods.requestFocus();
}
@@ -1831,6 +1848,11 @@ public class AwContents implements SmartClipProvider,
return ports;
}
+ public boolean hasAccessedInitialDocument() {
+ if (isDestroyed()) return false;
+ return mWebContents.hasAccessedInitialDocument();
+ }
+
//--------------------------------------------------------------------------------------------
// View and ViewGroup method implementations
//--------------------------------------------------------------------------------------------
@@ -2065,6 +2087,12 @@ public class AwContents implements SmartClipProvider,
nativeInsertVisualStateCallback(mNativeAwContents, requestId, callback);
}
+ public boolean getDidAttemptLoad() {
+ if (mDidAttemptLoad) return mDidAttemptLoad;
+ mDidAttemptLoad = mWebContentsObserver.hasStartedAnyProvisionalLoad();
+ return mDidAttemptLoad;
+ }
+
//--------------------------------------------------------------------------------------------
// Methods called from native via JNI
//--------------------------------------------------------------------------------------------
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
index a0003e6..bf5af89 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegate.java
@@ -37,4 +37,8 @@ public abstract class AwWebContentsDelegate extends WebContentsDelegateAndroid {
// Call in response to a prior runFileChooser call.
protected static native void nativeFilesSelectedInChooser(int processId, int renderId,
int modeFlags, String[] filePath, String[] displayName);
+
+ @Override
+ @CalledByNative
+ public abstract void navigationStateChanged(int flags);
}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
index 3f2c707..5e37d99 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsDelegateAdapter.java
@@ -11,6 +11,7 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
+import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -19,6 +20,7 @@ import android.webkit.ValueCallback;
import org.chromium.base.ContentUriUtils;
import org.chromium.base.ThreadUtils;
+import org.chromium.content_public.browser.InvalidateTypes;
/**
* Adapts the AwWebContentsDelegate interface to the AwContentsClient interface.
@@ -213,6 +215,22 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
}
@Override
+ public void navigationStateChanged(int flags) {
+ if ((flags & InvalidateTypes.URL) != 0
+ && mAwContents.hasAccessedInitialDocument()
+ && mAwContents.getDidAttemptLoad()) {
+ // Hint the client to show the last committed url, as it may be unsafe to show
+ // the pending entry.
+ String url = mAwContents.getLastCommittedUrl();
+ url = TextUtils.isEmpty(url) ? "about:blank" : url;
+ mContentsClient.onPageStarted(url);
+ mContentsClient.onLoadResource(url);
+ mContentsClient.onProgressChanged(100);
+ mContentsClient.onPageFinished(url);
+ }
+ }
+
+ @Override
public void toggleFullscreenModeForTab(boolean enterFullscreen) {
if (enterFullscreen) {
mContentViewClient.enterFullscreen();
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
index c3c381a..cd45ead 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@@ -13,12 +13,17 @@ import org.chromium.net.NetError;
*/
public class AwWebContentsObserver extends WebContentsObserver {
private final AwContentsClient mAwContentsClient;
+ private boolean mHasStartedAnyProvisionalLoad = false;
public AwWebContentsObserver(WebContents webContents, AwContentsClient awContentsClient) {
super(webContents);
mAwContentsClient = awContentsClient;
}
+ boolean hasStartedAnyProvisionalLoad() {
+ return mHasStartedAnyProvisionalLoad;
+ }
+
@Override
public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
@@ -67,4 +72,15 @@ public class AwWebContentsObserver extends WebContentsObserver {
public void didNavigateAnyFrame(String url, String baseUrl, boolean isReload) {
mAwContentsClient.doUpdateVisitedHistory(url, isReload);
}
+
+ @Override
+ public void didStartProvisionalLoadForFrame(
+ long frameId,
+ long parentFrameId,
+ boolean isMainFrame,
+ String validatedUrl,
+ boolean isErrorPage,
+ boolean isIframeSrcdoc) {
+ mHasStartedAnyProvisionalLoad = true;
+ }
}
diff --git a/android_webview/java_library_common.mk b/android_webview/java_library_common.mk
index 9353cb4..0b29e70 100644
--- a/android_webview/java_library_common.mk
+++ b/android_webview/java_library_common.mk
@@ -55,6 +55,7 @@ $(call intermediates-dir-for,GYP,shared)/enums/console_message_level_java/org/ch
$(call intermediates-dir-for,GYP,shared)/enums/content_gamepad_mapping/org/chromium/content/browser/input/CanonicalAxisIndex.java \
$(call intermediates-dir-for,GYP,shared)/enums/content_gamepad_mapping/org/chromium/content/browser/input/CanonicalButtonIndex.java \
$(call intermediates-dir-for,GYP,shared)/enums/gesture_event_type_java/org/chromium/content/browser/GestureEventType.java \
+$(call intermediates-dir-for,GYP,shared)/enums/invalidate_types_java/org/chromium/content_public/browser/InvalidateTypes.java \
$(call intermediates-dir-for,GYP,shared)/enums/navigation_controller_java/org/chromium/content_public/browser/navigation_controller/LoadURLType.java \
$(call intermediates-dir-for,GYP,shared)/enums/navigation_controller_java/org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java \
$(call intermediates-dir-for,GYP,shared)/enums/popup_item_type_java/org/chromium/content/browser/input/PopupItemType.java \
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
index edb6c7a..d363c5c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
@@ -279,4 +279,84 @@ public class ClientOnPageFinishedTest extends AwTestBase {
webServer.shutdown();
}
}
+
+ @MediumTest
+ @Feature({"AndroidWebView"})
+ public void testOnPageFinishedNotCalledOnDomModificationForBlankWebView() throws Throwable {
+ TestWebServer webServer = TestWebServer.start();
+ try {
+ doTestOnPageFinishedNotCalledOnDomMutation(webServer);
+ } finally {
+ webServer.shutdown();
+ }
+ }
+
+ @MediumTest
+ @Feature({"AndroidWebView"})
+ public void testOnPageFinishedCalledOnDomModificationAfterNonCommittedLoad() throws Throwable {
+ enableJavaScriptOnUiThread(mAwContents);
+ TestWebServer webServer = TestWebServer.start();
+ try {
+ final String noContentUrl = webServer.setResponseWithNoContentStatus("/nocontent.html");
+ TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
+ mContentsClient.getOnPageFinishedHelper();
+ final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount();
+ loadUrlAsync(mAwContents, noContentUrl);
+ // Mutate DOM.
+ executeJavaScriptAndWaitForResult(mAwContents, mContentsClient,
+ "document.body.innerHTML='Hello, World!'");
+ onPageFinishedHelper.waitForCallback(onPageFinishedCallCount);
+ assertEquals("about:blank", onPageFinishedHelper.getUrl());
+ } finally {
+ webServer.shutdown();
+ }
+ }
+
+ @MediumTest
+ @Feature({"AndroidWebView"})
+ public void testOnPageFinishedNotCalledOnDomModificationAfterLoadUrl() throws Throwable {
+ TestWebServer webServer = TestWebServer.start();
+ try {
+ final String testUrl =
+ webServer.setResponse("/test.html", CommonResources.ABOUT_HTML, null);
+ loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), testUrl);
+ doTestOnPageFinishedNotCalledOnDomMutation(webServer);
+ } finally {
+ webServer.shutdown();
+ }
+ }
+
+ @MediumTest
+ @Feature({"AndroidWebView"})
+ public void testOnPageFinishedNotCalledOnDomModificationAfterLoadData()
+ throws Throwable {
+ TestWebServer webServer = TestWebServer.start();
+ try {
+ loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ CommonResources.ABOUT_HTML, "text/html", false);
+ doTestOnPageFinishedNotCalledOnDomMutation(webServer);
+ } finally {
+ webServer.shutdown();
+ }
+ }
+
+ private void doTestOnPageFinishedNotCalledOnDomMutation(TestWebServer webServer)
+ throws Throwable {
+ enableJavaScriptOnUiThread(mAwContents);
+ TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
+ mContentsClient.getOnPageFinishedHelper();
+ final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount();
+ // Mutate DOM.
+ executeJavaScriptAndWaitForResult(mAwContents, mContentsClient,
+ "document.body.innerHTML='Hello, World!'");
+ // Rather than wait a fixed time to see that an onPageFinished callback isn't issued
+ // we load another valid page. Since callbacks arrive sequentially if the next callback
+ // we get is for the synchronizationUrl we know that DOM mutation did not schedule
+ // a callback for the iframe.
+ final String syncUrl = webServer.setResponse("/sync.html", "", null);
+ loadUrlAsync(mAwContents, syncUrl);
+ onPageFinishedHelper.waitForCallback(onPageFinishedCallCount);
+ assertEquals(syncUrl, onPageFinishedHelper.getUrl());
+ assertEquals(onPageFinishedCallCount + 1, onPageFinishedHelper.getCallCount());
+ }
}
diff --git a/android_webview/libwebviewchromium.gypi b/android_webview/libwebviewchromium.gypi
index feff124..691b1db 100644
--- a/android_webview/libwebviewchromium.gypi
+++ b/android_webview/libwebviewchromium.gypi
@@ -23,6 +23,7 @@
'../content/content.gyp:console_message_level_java',
'../content/content.gyp:content_gamepad_mapping',
'../content/content.gyp:gesture_event_type_java',
+ '../content/content.gyp:invalidate_types_java',
'../content/content.gyp:navigation_controller_java',
'../content/content.gyp:popup_item_type_java',
'../content/content.gyp:result_codes_java',
diff --git a/android_webview/native/aw_web_contents_delegate.cc b/android_webview/native/aw_web_contents_delegate.cc
index acece1b..d2a71e6 100644
--- a/android_webview/native/aw_web_contents_delegate.cc
+++ b/android_webview/native/aw_web_contents_delegate.cc
@@ -163,6 +163,18 @@ void AwWebContentsDelegate::AddNewContents(WebContents* source,
}
}
+void AwWebContentsDelegate::NavigationStateChanged(
+ content::WebContents* source,
+ content::InvalidateTypes changed_flags) {
+ JNIEnv* env = AttachCurrentThread();
+
+ ScopedJavaLocalRef<jobject> java_delegate = GetJavaDelegate(env);
+ if (java_delegate.obj()) {
+ Java_AwWebContentsDelegate_navigationStateChanged(env, java_delegate.obj(),
+ changed_flags);
+ }
+}
+
// Notifies the delegate about the creation of a new WebContents. This
// typically happens when popups are created.
void AwWebContentsDelegate::WebContentsCreated(
diff --git a/android_webview/native/aw_web_contents_delegate.h b/android_webview/native/aw_web_contents_delegate.h
index 96cd325..afc881b 100644
--- a/android_webview/native/aw_web_contents_delegate.h
+++ b/android_webview/native/aw_web_contents_delegate.h
@@ -40,6 +40,8 @@ class AwWebContentsDelegate
bool user_gesture,
bool* was_blocked) override;
+ void NavigationStateChanged(content::WebContents* source,
+ content::InvalidateTypes changed_flags) override;
void WebContentsCreated(content::WebContents* source_contents,
int opener_render_frame_id,
const base::string16& frame_name,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
index a07fdaf..2d1dcfc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/Tab.java
@@ -49,6 +49,7 @@ import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.ContentViewClient;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.WebContentsObserver;
+import org.chromium.content_public.browser.InvalidateTypes;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.Referrer;
@@ -387,10 +388,10 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener,
@Override
public void navigationStateChanged(int flags) {
- if ((flags & INVALIDATE_TYPE_TITLE) != 0) {
+ if ((flags & InvalidateTypes.TITLE) != 0) {
for (TabObserver observer : mObservers) observer.onTitleUpdated(Tab.this);
}
- if ((flags & INVALIDATE_TYPE_URL) != 0) {
+ if ((flags & InvalidateTypes.URL) != 0) {
for (TabObserver observer : mObservers) observer.onUrlUpdated(Tab.this);
}
}
diff --git a/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java b/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
index d04e16a..6b1026e 100644
--- a/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
+++ b/components/web_contents_delegate_android/android/java/src/org/chromium/components/web_contents_delegate_android/WebContentsDelegateAndroid.java
@@ -8,6 +8,7 @@ import android.view.KeyEvent;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+import org.chromium.content_public.browser.InvalidateTypes;
import org.chromium.content_public.browser.WebContents;
/**
@@ -25,16 +26,8 @@ public class WebContentsDelegateAndroid {
// Equivalent of WebCore::WebConsoleMessage::LevelError.
public static final int LOG_LEVEL_ERROR = 3;
- // Flags passed to the WebContentsDelegateAndroid.navigationStateChanged to tell it
- // what has changed. Should match the values in invalidate_type.h.
- // Equivalent of InvalidateTypes::INVALIDATE_TYPE_URL.
- public static final int INVALIDATE_TYPE_URL = 1 << 0;
- // Equivalent of InvalidateTypes::INVALIDATE_TYPE_TAB.
- public static final int INVALIDATE_TYPE_TAB = 1 << 1;
- // Equivalent of InvalidateTypes::INVALIDATE_TYPE_LOAD.
- public static final int INVALIDATE_TYPE_LOAD = 1 << 2;
- // Equivalent of InvalidateTypes::INVALIDATE_TYPE_TITLE.
- public static final int INVALIDATE_TYPE_TITLE = 1 << 3;
+ // TODO(mnaganov): Remove after getting rid of downstream usages.
+ public static final int INVALIDATE_TYPE_TAB = InvalidateTypes.TAB;
// The most recent load progress callback received from WebContents, as a percentage.
// Initialize to 100 to indicate that we're not in a loading state.
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 5e2b128..5a89df6 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -170,6 +170,14 @@ ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec());
}
+ScopedJavaLocalRef<jstring> WebContentsAndroid::GetLastCommittedURL(
+ JNIEnv* env,
+ jobject) const {
+ return ConvertUTF8ToJavaString(env,
+ web_contents_->GetLastCommittedURL().spec());
+}
+
+
jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
return web_contents_->GetBrowserContext()->IsOffTheRecord();
}
@@ -480,4 +488,11 @@ void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv* env,
ConvertJavaStringToUTF8(env, message)));
}
+jboolean WebContentsAndroid::HasAccessedInitialDocument(
+ JNIEnv* env,
+ jobject jobj) {
+ return static_cast<content::WebContentsImpl*>(web_contents_)->
+ HasAccessedInitialDocument();
+}
+
} // namespace content
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index 4379e3d..7f259ef 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -50,6 +50,8 @@ class CONTENT_EXPORT WebContentsAndroid
void Stop(JNIEnv* env, jobject obj);
jint GetBackgroundColor(JNIEnv* env, jobject obj);
base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const;
+ base::android::ScopedJavaLocalRef<jstring> GetLastCommittedURL(JNIEnv* env,
+ jobject) const;
jboolean IsIncognito(JNIEnv* env, jobject obj);
void ResumeResponseDeferredAtStart(JNIEnv* env, jobject obj);
@@ -109,6 +111,8 @@ class CONTENT_EXPORT WebContentsAndroid
jint level,
jstring message);
+ jboolean HasAccessedInitialDocument(JNIEnv* env, jobject jobj);
+
private:
RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
diff --git a/content/content.gyp b/content/content.gyp
index 7bc40bf..01bd90a 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -443,6 +443,7 @@
'content_strings_grd',
'content_gamepad_mapping',
'gesture_event_type_java',
+ 'invalidate_types_java',
'navigation_controller_java',
'popup_item_type_java',
'result_codes_java',
@@ -495,6 +496,14 @@
'includes': [ '../build/android/java_cpp_enum.gypi' ],
},
{
+ 'target_name': 'invalidate_types_java',
+ 'type': 'none',
+ 'variables': {
+ 'source_file': 'public/browser/invalidate_type.h',
+ },
+ 'includes': [ '../build/android/java_cpp_enum.gypi' ],
+ },
+ {
'target_name': 'navigation_controller_java',
'type': 'none',
'variables': {
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 9dc5007..6edd00f 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -110,6 +110,7 @@ java_cpp_enum("content_public_android_java_enums_srcjar") {
"//content/browser/android/content_view_core_impl.cc",
"//content/browser/android/gesture_event_type.h",
"//content/browser/gamepad/gamepad_standard_mappings.h",
+ "//content/public/browser/invalidate_type.h",
"//content/public/browser/navigation_controller.h",
"//content/public/common/console_message_level.h",
"//content/public/common/result_codes.h",
@@ -122,6 +123,7 @@ java_cpp_enum("content_public_android_java_enums_srcjar") {
"org/chromium/content/browser/input/CanonicalAxisIndex.java",
"org/chromium/content/browser/input/CanonicalButtonIndex.java",
"org/chromium/content/browser/input/PopupItemType.java",
+ "org/chromium/content_public/browser/InvalidateTypes.java",
"org/chromium/content_public/browser/navigation_controller/LoadURLType.java",
"org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java",
"org/chromium/content_public/common/ConsoleMessageLevel.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 9e647ee..c3a155e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -166,6 +166,11 @@ import org.chromium.content_public.browser.WebContents;
}
@Override
+ public String getLastCommittedUrl() {
+ return nativeGetLastCommittedURL(mNativeWebContentsAndroid);
+ }
+
+ @Override
public boolean isIncognito() {
return nativeIsIncognito(mNativeWebContentsAndroid);
}
@@ -294,6 +299,11 @@ import org.chromium.content_public.browser.WebContents;
nativeAddMessageToDevToolsConsole(mNativeWebContentsAndroid, level, message);
}
+ @Override
+ public boolean hasAccessedInitialDocument() {
+ return nativeHasAccessedInitialDocument(mNativeWebContentsAndroid);
+ }
+
@CalledByNative
private static void onEvaluateJavaScriptResult(
String jsonResult, JavaScriptCallback callback) {
@@ -326,6 +336,7 @@ import org.chromium.content_public.browser.WebContents;
private native void nativeScrollFocusedEditableNodeIntoView(long nativeWebContentsAndroid);
private native void nativeSelectWordAroundCaret(long nativeWebContentsAndroid);
private native String nativeGetURL(long nativeWebContentsAndroid);
+ private native String nativeGetLastCommittedURL(long nativeWebContentsAndroid);
private native boolean nativeIsIncognito(long nativeWebContentsAndroid);
private native void nativeResumeResponseDeferredAtStart(long nativeWebContentsAndroid);
private native void nativeSetHasPendingNavigationTransitionForTesting(
@@ -345,4 +356,6 @@ import org.chromium.content_public.browser.WebContents;
String script, JavaScriptCallback callback);
private native void nativeAddMessageToDevToolsConsole(
long nativeWebContentsAndroid, int level, String message);
+ private native boolean nativeHasAccessedInitialDocument(
+ long nativeWebContentsAndroid);
}
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index 1902161..19b00b2 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -139,6 +139,14 @@ public interface WebContents {
public String getUrl();
/**
+ * Gets the last committed URL. It represents the current page that is
+ * displayed in this WebContents. It represents the current security context.
+ *
+ * @return The last committed URL.
+ */
+ public String getLastCommittedUrl();
+
+ /**
* Get the InCognito state of WebContents.
*
* @return whether this WebContents is in InCognito mode or not
@@ -213,4 +221,12 @@ public interface WebContents {
* org.chromium.content_public.common.ConsoleMessageLevel.
*/
public void addMessageToDevToolsConsole(int level, String message);
+
+ /**
+ * Returns whether the initial empty page has been accessed by a script from another
+ * page. Always false after the first commit.
+ *
+ * @return Whether the initial empty page has been accessed by a script.
+ */
+ public boolean hasAccessedInitialDocument();
}
diff --git a/content/public/browser/invalidate_type.h b/content/public/browser/invalidate_type.h
index 975bb30..f85ec3d 100644
--- a/content/public/browser/invalidate_type.h
+++ b/content/public/browser/invalidate_type.h
@@ -9,6 +9,11 @@ namespace content {
// Flags passed to the WebContentsDelegate.NavigationStateChanged to tell it
// what has changed. Combine them to update more than one thing.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.content_public.browser)
+// GENERATED_JAVA_PREFIX_TO_STRIP: INVALIDATE_TYPE_
enum InvalidateTypes {
INVALIDATE_TYPE_URL = 1 << 0, // The URL has changed.
INVALIDATE_TYPE_TAB = 1 << 1, // The favicon, app icon, or crashed
diff --git a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
index dd40220..48c257e 100644
--- a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
+++ b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
@@ -80,11 +80,14 @@ public class TestWebServer {
final boolean mIsRedirect;
final Runnable mResponseAction;
final boolean mIsNotFound;
+ final boolean mIsNoContent;
Response(byte[] responseData, List<Pair<String, String>> responseHeaders,
- boolean isRedirect, boolean isNotFound, Runnable responseAction) {
+ boolean isRedirect, boolean isNotFound, boolean isNoContent,
+ Runnable responseAction) {
mIsRedirect = isRedirect;
mIsNotFound = isNotFound;
+ mIsNoContent = isNoContent;
mResponseData = responseData;
mResponseHeaders = responseHeaders == null
? new ArrayList<Pair<String, String>>() : responseHeaders;
@@ -208,6 +211,7 @@ public class TestWebServer {
private static final int RESPONSE_STATUS_NORMAL = 0;
private static final int RESPONSE_STATUS_MOVED_TEMPORARILY = 1;
private static final int RESPONSE_STATUS_NOT_FOUND = 2;
+ private static final int RESPONSE_STATUS_NO_CONTENT = 3;
private String setResponseInternal(
String requestPath, byte[] responseData,
@@ -215,10 +219,12 @@ public class TestWebServer {
int status) {
final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY);
final boolean isNotFound = (status == RESPONSE_STATUS_NOT_FOUND);
+ final boolean isNoContent = (status == RESPONSE_STATUS_NO_CONTENT);
synchronized (mLock) {
mResponseMap.put(requestPath, new Response(
- responseData, responseHeaders, isRedirect, isNotFound, responseAction));
+ responseData, responseHeaders, isRedirect, isNotFound, isNoContent,
+ responseAction));
mResponseCountMap.put(requestPath, Integer.valueOf(0));
mLastRequestMap.put(requestPath, null);
}
@@ -251,6 +257,18 @@ public class TestWebServer {
}
/**
+ * Sets a 204 (no content) response to be returned when a particular request path is passed in.
+ *
+ * @param requestPath The path to respond to.
+ * @return The full URL including the path that should be requested to get the expected
+ * response.
+ */
+ public String setResponseWithNoContentStatus(String requestPath) {
+ return setResponseInternal(
+ requestPath, "".getBytes(), null, null, RESPONSE_STATUS_NO_CONTENT);
+ }
+
+ /**
* Sets a response to be returned when a particular request path is passed
* in (with the option to specify additional headers).
*
@@ -451,6 +469,10 @@ public class TestWebServer {
} else if (response.mIsNotFound) {
httpResponse = createResponse(HttpStatus.SC_NOT_FOUND);
servedResponseFor(path, request);
+ } else if (response.mIsNoContent) {
+ httpResponse = createResponse(HttpStatus.SC_NO_CONTENT);
+ httpResponse.setHeader("Content-Length", "0");
+ servedResponseFor(path, request);
} else if (response.mIsRedirect) {
httpResponse = createResponse(HttpStatus.SC_MOVED_TEMPORARILY);
for (Pair<String, String> header : response.mResponseHeaders) {