Commit e38bb6cd authored by mnaganov's avatar mnaganov Committed by Commit bot

[Android WebView] Synthesize a fake page loading event on page source modification

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.

BUG=458569

Review URL: https://codereview.chromium.org/924833003

Cr-Commit-Position: refs/heads/master@{#318222}
parent 24c195f8
...@@ -1239,6 +1239,19 @@ public class AwContents implements SmartClipProvider, ...@@ -1239,6 +1239,19 @@ public class AwContents implements SmartClipProvider,
return url; 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() { public void requestFocus() {
mAwViewMethods.requestFocus(); mAwViewMethods.requestFocus();
} }
...@@ -1831,6 +1844,11 @@ public class AwContents implements SmartClipProvider, ...@@ -1831,6 +1844,11 @@ public class AwContents implements SmartClipProvider,
return ports; return ports;
} }
public boolean hasAccessedInitialDocument() {
if (isDestroyed()) return false;
return mWebContents.hasAccessedInitialDocument();
}
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
// View and ViewGroup method implementations // View and ViewGroup method implementations
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
......
...@@ -37,4 +37,8 @@ public abstract class AwWebContentsDelegate extends WebContentsDelegateAndroid { ...@@ -37,4 +37,8 @@ public abstract class AwWebContentsDelegate extends WebContentsDelegateAndroid {
// Call in response to a prior runFileChooser call. // Call in response to a prior runFileChooser call.
protected static native void nativeFilesSelectedInChooser(int processId, int renderId, protected static native void nativeFilesSelectedInChooser(int processId, int renderId,
int modeFlags, String[] filePath, String[] displayName); int modeFlags, String[] filePath, String[] displayName);
@Override
@CalledByNative
public abstract void navigationStateChanged(int flags);
} }
...@@ -11,6 +11,7 @@ import android.os.AsyncTask; ...@@ -11,6 +11,7 @@ import android.os.AsyncTask;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
...@@ -19,6 +20,7 @@ import android.webkit.ValueCallback; ...@@ -19,6 +20,7 @@ import android.webkit.ValueCallback;
import org.chromium.base.ContentUriUtils; import org.chromium.base.ContentUriUtils;
import org.chromium.base.ThreadUtils; import org.chromium.base.ThreadUtils;
import org.chromium.content_public.browser.InvalidateTypes;
/** /**
* Adapts the AwWebContentsDelegate interface to the AwContentsClient interface. * Adapts the AwWebContentsDelegate interface to the AwContentsClient interface.
...@@ -212,6 +214,20 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate { ...@@ -212,6 +214,20 @@ class AwWebContentsDelegateAdapter extends AwWebContentsDelegate {
mContentsClient.onRequestFocus(); mContentsClient.onRequestFocus();
} }
@Override
public void navigationStateChanged(int flags) {
if ((flags & InvalidateTypes.URL) != 0 && mAwContents.hasAccessedInitialDocument()) {
// 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 @Override
public void toggleFullscreenModeForTab(boolean enterFullscreen) { public void toggleFullscreenModeForTab(boolean enterFullscreen) {
if (enterFullscreen) { if (enterFullscreen) {
......
...@@ -55,6 +55,7 @@ $(call intermediates-dir-for,GYP,shared)/enums/console_message_level_java/org/ch ...@@ -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/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/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/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/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/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 \ $(call intermediates-dir-for,GYP,shared)/enums/popup_item_type_java/org/chromium/content/browser/input/PopupItemType.java \
......
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
package org.chromium.android_webview.test; package org.chromium.android_webview.test;
import android.os.Build; import android.os.Build;
import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.MediumTest;
import org.chromium.android_webview.AwContents; import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.test.util.AwTestTouchUtils; import org.chromium.android_webview.test.util.AwTestTouchUtils;
import org.chromium.android_webview.test.util.CommonResources; import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.MinAndroidSdkLevel; import org.chromium.base.test.util.MinAndroidSdkLevel;
import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
import org.chromium.net.test.util.TestWebServer; import org.chromium.net.test.util.TestWebServer;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
...@@ -38,6 +39,9 @@ public class PopupWindowTest extends AwTestBase { ...@@ -38,6 +39,9 @@ public class PopupWindowTest extends AwTestBase {
mParentContentsClient = new TestAwContentsClient(); mParentContentsClient = new TestAwContentsClient();
mParentContainerView = createAwTestContainerViewOnMainSync(mParentContentsClient); mParentContainerView = createAwTestContainerViewOnMainSync(mParentContentsClient);
mParentContents = mParentContainerView.getAwContents(); mParentContents = mParentContainerView.getAwContents();
mPopupContentsClient = new TestAwContentsClient();
mPopupContainerView = createAwTestContainerViewOnMainSync(mPopupContentsClient);
mPopupContents = mPopupContainerView.getAwContents();
mWebServer = TestWebServer.start(); mWebServer = TestWebServer.start();
} }
...@@ -49,7 +53,9 @@ public class PopupWindowTest extends AwTestBase { ...@@ -49,7 +53,9 @@ public class PopupWindowTest extends AwTestBase {
super.tearDown(); super.tearDown();
} }
private void triggerPopup() throws Throwable { // It is expected that the parent page contains a link that opens a popup window,
// and the test server is already pre-loaded with both parent and popup pages.
private void triggerPopup(String parentUrl) throws Throwable {
enableJavaScriptOnUiThread(mParentContents); enableJavaScriptOnUiThread(mParentContents);
getInstrumentation().runOnMainSync(new Runnable() { getInstrumentation().runOnMainSync(new Runnable() {
@Override @Override
...@@ -59,21 +65,6 @@ public class PopupWindowTest extends AwTestBase { ...@@ -59,21 +65,6 @@ public class PopupWindowTest extends AwTestBase {
} }
}); });
final String popupPath = "/popup.html";
final String parentPageHtml = CommonResources.makeHtmlPageFrom("",
"<script>"
+ "function tryOpenWindow() {"
+ " var newWindow = window.open('" + popupPath + "');"
+ "}</script>"
+ "<a class=\"full_view\" onclick=\"tryOpenWindow();\">Click me!</a>");
final String popupPageHtml = CommonResources.makeHtmlPageFrom(
"<title>" + POPUP_TITLE + "</title>",
"This is a popup window");
final String parentUrl = mWebServer.setResponse("/popupParent.html", parentPageHtml, null);
mWebServer.setResponse(popupPath, popupPageHtml, null);
mParentContentsClient.getOnCreateWindowHelper().setReturnValue(true); mParentContentsClient.getOnCreateWindowHelper().setReturnValue(true);
loadUrlSync(mParentContents, loadUrlSync(mParentContents,
mParentContentsClient.getOnPageFinishedHelper(), mParentContentsClient.getOnPageFinishedHelper(),
...@@ -88,10 +79,6 @@ public class PopupWindowTest extends AwTestBase { ...@@ -88,10 +79,6 @@ public class PopupWindowTest extends AwTestBase {
} }
private void connectPendingPopup() throws Exception { private void connectPendingPopup() throws Exception {
mPopupContentsClient = new TestAwContentsClient();
mPopupContainerView = createAwTestContainerViewOnMainSync(mPopupContentsClient);
mPopupContents = mPopupContainerView.getAwContents();
getInstrumentation().runOnMainSync(new Runnable() { getInstrumentation().runOnMainSync(new Runnable() {
@Override @Override
public void run() { public void run() {
...@@ -100,10 +87,22 @@ public class PopupWindowTest extends AwTestBase { ...@@ -100,10 +87,22 @@ public class PopupWindowTest extends AwTestBase {
}); });
} }
@SmallTest @MediumTest
@Feature({"AndroidWebView"}) @Feature({"AndroidWebView"})
public void testPopupWindow() throws Throwable { public void testPopupWindow() throws Throwable {
triggerPopup(); final String popupPath = "/popup.html";
final String parentPageHtml = CommonResources.makeHtmlPageFrom("",
"<script>"
+ "function tryOpenWindow() {"
+ " var newWindow = window.open('" + popupPath + "');"
+ "}</script>"
+ "<a class=\"full_view\" onclick=\"tryOpenWindow();\">Click me!</a>");
final String popupPageHtml = CommonResources.makeHtmlPageFrom(
"<title>" + POPUP_TITLE + "</title>",
"This is a popup window");
final String parentUrl = mWebServer.setResponse("/popupParent.html", parentPageHtml, null);
mWebServer.setResponse(popupPath, popupPageHtml, null);
triggerPopup(parentUrl);
connectPendingPopup(); connectPendingPopup();
poll(new Callable<Boolean>() { poll(new Callable<Boolean>() {
@Override @Override
...@@ -112,4 +111,33 @@ public class PopupWindowTest extends AwTestBase { ...@@ -112,4 +111,33 @@ public class PopupWindowTest extends AwTestBase {
} }
}); });
} }
@MediumTest
@Feature({"AndroidWebView"})
public void testOnPageFinishedCalledAfterModifyingPageSource() throws Throwable {
final String popupPath = "/popup.html";
final String popupUrl = mWebServer.setResponseWithNoContentStatus(popupPath);
final String parentHtml = CommonResources.makeHtmlPageFrom("",
"<script>"
+ "function tryOpenWindow() {"
+ " window.popupWindow = window.open('" + popupPath + "');"
+ "}"
+ "function modifyDomOfPopup() {"
+ " window.popupWindow.document.body.innerHTML = 'Hello from the parent!';"
+ "}</script>"
+ "<a class='full_view' onclick='tryOpenWindow();'>Click me!</a>");
final String parentUrl = mWebServer.setResponse("/parent.html", parentHtml, null);
triggerPopup(parentUrl);
TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
mPopupContentsClient.getOnPageFinishedHelper();
int onPageFinishedCallCount = onPageFinishedHelper.getCallCount();
connectPendingPopup();
onPageFinishedHelper.waitForCallback(onPageFinishedCallCount);
onPageFinishedCallCount = onPageFinishedHelper.getCallCount();
executeJavaScriptAndWaitForResult(mParentContents, mParentContentsClient,
"modifyDomOfPopup()");
onPageFinishedHelper.waitForCallback(onPageFinishedCallCount);
assertEquals("about:blank", onPageFinishedHelper.getUrl());
}
} }
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
'../content/content.gyp:console_message_level_java', '../content/content.gyp:console_message_level_java',
'../content/content.gyp:content_gamepad_mapping', '../content/content.gyp:content_gamepad_mapping',
'../content/content.gyp:gesture_event_type_java', '../content/content.gyp:gesture_event_type_java',
'../content/content.gyp:invalidate_types_java',
'../content/content.gyp:navigation_controller_java', '../content/content.gyp:navigation_controller_java',
'../content/content.gyp:popup_item_type_java', '../content/content.gyp:popup_item_type_java',
'../content/content.gyp:result_codes_java', '../content/content.gyp:result_codes_java',
......
...@@ -163,6 +163,18 @@ void AwWebContentsDelegate::AddNewContents(WebContents* source, ...@@ -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 // Notifies the delegate about the creation of a new WebContents. This
// typically happens when popups are created. // typically happens when popups are created.
void AwWebContentsDelegate::WebContentsCreated( void AwWebContentsDelegate::WebContentsCreated(
......
...@@ -40,6 +40,8 @@ class AwWebContentsDelegate ...@@ -40,6 +40,8 @@ class AwWebContentsDelegate
bool user_gesture, bool user_gesture,
bool* was_blocked) override; bool* was_blocked) override;
void NavigationStateChanged(content::WebContents* source,
content::InvalidateTypes changed_flags) override;
void WebContentsCreated(content::WebContents* source_contents, void WebContentsCreated(content::WebContents* source_contents,
int opener_render_frame_id, int opener_render_frame_id,
const base::string16& frame_name, const base::string16& frame_name,
......
...@@ -49,6 +49,7 @@ import org.chromium.content.browser.ContentView; ...@@ -49,6 +49,7 @@ import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.ContentViewClient; import org.chromium.content.browser.ContentViewClient;
import org.chromium.content.browser.ContentViewCore; import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.WebContentsObserver; 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.LoadUrlParams;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.common.Referrer; import org.chromium.content_public.common.Referrer;
...@@ -387,10 +388,10 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener, ...@@ -387,10 +388,10 @@ public class Tab implements ViewGroup.OnHierarchyChangeListener,
@Override @Override
public void navigationStateChanged(int flags) { public void navigationStateChanged(int flags) {
if ((flags & INVALIDATE_TYPE_TITLE) != 0) { if ((flags & InvalidateTypes.TITLE) != 0) {
for (TabObserver observer : mObservers) observer.onTitleUpdated(Tab.this); 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); for (TabObserver observer : mObservers) observer.onUrlUpdated(Tab.this);
} }
} }
......
...@@ -8,6 +8,7 @@ import android.view.KeyEvent; ...@@ -8,6 +8,7 @@ import android.view.KeyEvent;
import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace; import org.chromium.base.JNINamespace;
import org.chromium.content_public.browser.InvalidateTypes;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** /**
...@@ -25,16 +26,8 @@ public class WebContentsDelegateAndroid { ...@@ -25,16 +26,8 @@ public class WebContentsDelegateAndroid {
// Equivalent of WebCore::WebConsoleMessage::LevelError. // Equivalent of WebCore::WebConsoleMessage::LevelError.
public static final int LOG_LEVEL_ERROR = 3; public static final int LOG_LEVEL_ERROR = 3;
// Flags passed to the WebContentsDelegateAndroid.navigationStateChanged to tell it // TODO(mnaganov): Remove after getting rid of downstream usages.
// what has changed. Should match the values in invalidate_type.h. public static final int INVALIDATE_TYPE_TAB = InvalidateTypes.TAB;
// 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;
// The most recent load progress callback received from WebContents, as a percentage. // 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. // Initialize to 100 to indicate that we're not in a loading state.
......
...@@ -170,6 +170,14 @@ ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env, ...@@ -170,6 +170,14 @@ ScopedJavaLocalRef<jstring> WebContentsAndroid::GetURL(JNIEnv* env,
return ConvertUTF8ToJavaString(env, web_contents_->GetURL().spec()); 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) { jboolean WebContentsAndroid::IsIncognito(JNIEnv* env, jobject obj) {
return web_contents_->GetBrowserContext()->IsOffTheRecord(); return web_contents_->GetBrowserContext()->IsOffTheRecord();
} }
...@@ -480,4 +488,11 @@ void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv* env, ...@@ -480,4 +488,11 @@ void WebContentsAndroid::AddMessageToDevToolsConsole(JNIEnv* env,
ConvertJavaStringToUTF8(env, message))); ConvertJavaStringToUTF8(env, message)));
} }
jboolean WebContentsAndroid::HasAccessedInitialDocument(
JNIEnv* env,
jobject jobj) {
return static_cast<content::WebContentsImpl*>(web_contents_)->
HasAccessedInitialDocument();
}
} // namespace content } // namespace content
...@@ -50,6 +50,8 @@ class CONTENT_EXPORT WebContentsAndroid ...@@ -50,6 +50,8 @@ class CONTENT_EXPORT WebContentsAndroid
void Stop(JNIEnv* env, jobject obj); void Stop(JNIEnv* env, jobject obj);
jint GetBackgroundColor(JNIEnv* env, jobject obj); jint GetBackgroundColor(JNIEnv* env, jobject obj);
base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const; base::android::ScopedJavaLocalRef<jstring> GetURL(JNIEnv* env, jobject) const;
base::android::ScopedJavaLocalRef<jstring> GetLastCommittedURL(JNIEnv* env,
jobject) const;
jboolean IsIncognito(JNIEnv* env, jobject obj); jboolean IsIncognito(JNIEnv* env, jobject obj);
void ResumeResponseDeferredAtStart(JNIEnv* env, jobject obj); void ResumeResponseDeferredAtStart(JNIEnv* env, jobject obj);
...@@ -109,6 +111,8 @@ class CONTENT_EXPORT WebContentsAndroid ...@@ -109,6 +111,8 @@ class CONTENT_EXPORT WebContentsAndroid
jint level, jint level,
jstring message); jstring message);
jboolean HasAccessedInitialDocument(JNIEnv* env, jobject jobj);
private: private:
RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid(); RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
......
...@@ -443,6 +443,7 @@ ...@@ -443,6 +443,7 @@
'content_strings_grd', 'content_strings_grd',
'content_gamepad_mapping', 'content_gamepad_mapping',
'gesture_event_type_java', 'gesture_event_type_java',
'invalidate_types_java',
'navigation_controller_java', 'navigation_controller_java',
'popup_item_type_java', 'popup_item_type_java',
'result_codes_java', 'result_codes_java',
...@@ -494,6 +495,14 @@ ...@@ -494,6 +495,14 @@
}, },
'includes': [ '../build/android/java_cpp_enum.gypi' ], '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', 'target_name': 'navigation_controller_java',
'type': 'none', 'type': 'none',
......
...@@ -110,6 +110,7 @@ java_cpp_enum("content_public_android_java_enums_srcjar") { ...@@ -110,6 +110,7 @@ java_cpp_enum("content_public_android_java_enums_srcjar") {
"//content/browser/android/content_view_core_impl.cc", "//content/browser/android/content_view_core_impl.cc",
"//content/browser/android/gesture_event_type.h", "//content/browser/android/gesture_event_type.h",
"//content/browser/gamepad/gamepad_standard_mappings.h", "//content/browser/gamepad/gamepad_standard_mappings.h",
"//content/public/browser/invalidate_type.h",
"//content/public/browser/navigation_controller.h", "//content/public/browser/navigation_controller.h",
"//content/public/common/console_message_level.h", "//content/public/common/console_message_level.h",
"//content/public/common/result_codes.h", "//content/public/common/result_codes.h",
...@@ -122,6 +123,7 @@ java_cpp_enum("content_public_android_java_enums_srcjar") { ...@@ -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/CanonicalAxisIndex.java",
"org/chromium/content/browser/input/CanonicalButtonIndex.java", "org/chromium/content/browser/input/CanonicalButtonIndex.java",
"org/chromium/content/browser/input/PopupItemType.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/LoadURLType.java",
"org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java", "org/chromium/content_public/browser/navigation_controller/UserAgentOverrideOption.java",
"org/chromium/content_public/common/ConsoleMessageLevel.java", "org/chromium/content_public/common/ConsoleMessageLevel.java",
......
...@@ -165,6 +165,11 @@ import org.chromium.content_public.browser.WebContents; ...@@ -165,6 +165,11 @@ import org.chromium.content_public.browser.WebContents;
return nativeGetURL(mNativeWebContentsAndroid); return nativeGetURL(mNativeWebContentsAndroid);
} }
@Override
public String getLastCommittedUrl() {
return nativeGetLastCommittedURL(mNativeWebContentsAndroid);
}
@Override @Override
public boolean isIncognito() { public boolean isIncognito() {
return nativeIsIncognito(mNativeWebContentsAndroid); return nativeIsIncognito(mNativeWebContentsAndroid);
...@@ -296,6 +301,11 @@ import org.chromium.content_public.browser.WebContents; ...@@ -296,6 +301,11 @@ import org.chromium.content_public.browser.WebContents;
nativeAddMessageToDevToolsConsole(mNativeWebContentsAndroid, level, message); nativeAddMessageToDevToolsConsole(mNativeWebContentsAndroid, level, message);
} }
@Override
public boolean hasAccessedInitialDocument() {
return nativeHasAccessedInitialDocument(mNativeWebContentsAndroid);
}
@CalledByNative @CalledByNative
private static void onEvaluateJavaScriptResult( private static void onEvaluateJavaScriptResult(
String jsonResult, JavaScriptCallback callback) { String jsonResult, JavaScriptCallback callback) {
...@@ -328,6 +338,7 @@ import org.chromium.content_public.browser.WebContents; ...@@ -328,6 +338,7 @@ import org.chromium.content_public.browser.WebContents;
private native void nativeScrollFocusedEditableNodeIntoView(long nativeWebContentsAndroid); private native void nativeScrollFocusedEditableNodeIntoView(long nativeWebContentsAndroid);
private native void nativeSelectWordAroundCaret(long nativeWebContentsAndroid); private native void nativeSelectWordAroundCaret(long nativeWebContentsAndroid);
private native String nativeGetURL(long nativeWebContentsAndroid); private native String nativeGetURL(long nativeWebContentsAndroid);
private native String nativeGetLastCommittedURL(long nativeWebContentsAndroid);
private native boolean nativeIsIncognito(long nativeWebContentsAndroid); private native boolean nativeIsIncognito(long nativeWebContentsAndroid);
private native void nativeResumeResponseDeferredAtStart(long nativeWebContentsAndroid); private native void nativeResumeResponseDeferredAtStart(long nativeWebContentsAndroid);
private native void nativeSetHasPendingNavigationTransitionForTesting( private native void nativeSetHasPendingNavigationTransitionForTesting(
...@@ -347,4 +358,6 @@ import org.chromium.content_public.browser.WebContents; ...@@ -347,4 +358,6 @@ import org.chromium.content_public.browser.WebContents;
String script, JavaScriptCallback callback); String script, JavaScriptCallback callback);
private native void nativeAddMessageToDevToolsConsole( private native void nativeAddMessageToDevToolsConsole(
long nativeWebContentsAndroid, int level, String message); long nativeWebContentsAndroid, int level, String message);
private native boolean nativeHasAccessedInitialDocument(
long nativeWebContentsAndroid);
} }
...@@ -138,6 +138,14 @@ public interface WebContents { ...@@ -138,6 +138,14 @@ public interface WebContents {
*/ */
public String getUrl(); 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. * Get the InCognito state of WebContents.
* *
...@@ -213,4 +221,12 @@ public interface WebContents { ...@@ -213,4 +221,12 @@ public interface WebContents {
* org.chromium.content_public.common.ConsoleMessageLevel. * org.chromium.content_public.common.ConsoleMessageLevel.
*/ */
public void addMessageToDevToolsConsole(int level, String message); 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();
} }
...@@ -9,6 +9,11 @@ namespace content { ...@@ -9,6 +9,11 @@ namespace content {
// Flags passed to the WebContentsDelegate.NavigationStateChanged to tell it // Flags passed to the WebContentsDelegate.NavigationStateChanged to tell it
// what has changed. Combine them to update more than one thing. // 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 { enum InvalidateTypes {
INVALIDATE_TYPE_URL = 1 << 0, // The URL has changed. INVALIDATE_TYPE_URL = 1 << 0, // The URL has changed.
INVALIDATE_TYPE_TAB = 1 << 1, // The favicon, app icon, or crashed INVALIDATE_TYPE_TAB = 1 << 1, // The favicon, app icon, or crashed
......
...@@ -80,11 +80,14 @@ public class TestWebServer { ...@@ -80,11 +80,14 @@ public class TestWebServer {
final boolean mIsRedirect; final boolean mIsRedirect;
final Runnable mResponseAction; final Runnable mResponseAction;
final boolean mIsNotFound; final boolean mIsNotFound;
final boolean mIsNoContent;
Response(byte[] responseData, List<Pair<String, String>> responseHeaders, Response(byte[] responseData, List<Pair<String, String>> responseHeaders,
boolean isRedirect, boolean isNotFound, Runnable responseAction) { boolean isRedirect, boolean isNotFound, boolean isNoContent,
Runnable responseAction) {
mIsRedirect = isRedirect; mIsRedirect = isRedirect;
mIsNotFound = isNotFound; mIsNotFound = isNotFound;
mIsNoContent = isNoContent;
mResponseData = responseData; mResponseData = responseData;
mResponseHeaders = responseHeaders == null mResponseHeaders = responseHeaders == null
? new ArrayList<Pair<String, String>>() : responseHeaders; ? new ArrayList<Pair<String, String>>() : responseHeaders;
...@@ -208,6 +211,7 @@ public class TestWebServer { ...@@ -208,6 +211,7 @@ public class TestWebServer {
private static final int RESPONSE_STATUS_NORMAL = 0; private static final int RESPONSE_STATUS_NORMAL = 0;
private static final int RESPONSE_STATUS_MOVED_TEMPORARILY = 1; private static final int RESPONSE_STATUS_MOVED_TEMPORARILY = 1;
private static final int RESPONSE_STATUS_NOT_FOUND = 2; private static final int RESPONSE_STATUS_NOT_FOUND = 2;
private static final int RESPONSE_STATUS_NO_CONTENT = 3;
private String setResponseInternal( private String setResponseInternal(
String requestPath, byte[] responseData, String requestPath, byte[] responseData,
...@@ -215,10 +219,12 @@ public class TestWebServer { ...@@ -215,10 +219,12 @@ public class TestWebServer {
int status) { int status) {
final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY); final boolean isRedirect = (status == RESPONSE_STATUS_MOVED_TEMPORARILY);
final boolean isNotFound = (status == RESPONSE_STATUS_NOT_FOUND); final boolean isNotFound = (status == RESPONSE_STATUS_NOT_FOUND);
final boolean isNoContent = (status == RESPONSE_STATUS_NO_CONTENT);
synchronized (mLock) { synchronized (mLock) {
mResponseMap.put(requestPath, new Response( mResponseMap.put(requestPath, new Response(
responseData, responseHeaders, isRedirect, isNotFound, responseAction)); responseData, responseHeaders, isRedirect, isNotFound, isNoContent,
responseAction));
mResponseCountMap.put(requestPath, Integer.valueOf(0)); mResponseCountMap.put(requestPath, Integer.valueOf(0));
mLastRequestMap.put(requestPath, null); mLastRequestMap.put(requestPath, null);
} }
...@@ -250,6 +256,19 @@ public class TestWebServer { ...@@ -250,6 +256,19 @@ public class TestWebServer {
RESPONSE_STATUS_NOT_FOUND); RESPONSE_STATUS_NOT_FOUND);
} }
/**
* 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 * Sets a response to be returned when a particular request path is passed
* in (with the option to specify additional headers). * in (with the option to specify additional headers).
...@@ -451,6 +470,10 @@ public class TestWebServer { ...@@ -451,6 +470,10 @@ public class TestWebServer {
} else if (response.mIsNotFound) { } else if (response.mIsNotFound) {
httpResponse = createResponse(HttpStatus.SC_NOT_FOUND); httpResponse = createResponse(HttpStatus.SC_NOT_FOUND);
servedResponseFor(path, request); 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) { } else if (response.mIsRedirect) {
httpResponse = createResponse(HttpStatus.SC_MOVED_TEMPORARILY); httpResponse = createResponse(HttpStatus.SC_MOVED_TEMPORARILY);
for (Pair<String, String> header : response.mResponseHeaders) { for (Pair<String, String> header : response.mResponseHeaders) {
......
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