1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "xwalk/runtime/browser/android/xwalk_settings.h"
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/command_line.h"
12 #include "content/browser/renderer_host/java/jni_helper.h"
13 #include "content/public/browser/navigation_controller.h"
14 #include "content/public/browser/navigation_entry.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/web_contents.h"
17 #include "jni/XWalkSettings_jni.h"
18 #include "webkit/common/webpreferences.h"
19 #include "xwalk/runtime/common/xwalk_content_client.h"
20 #include "xwalk/runtime/browser/android/renderer_host/xwalk_render_view_host_ext.h"
21 #include "xwalk/runtime/browser/android/xwalk_content.h"
23 using base::android::CheckException;
24 using base::android::ConvertJavaStringToUTF16;
25 using base::android::ConvertUTF16ToJavaString;
26 using base::android::ConvertUTF8ToJavaString;
27 using base::android::GetClass;
28 using base::android::ScopedJavaLocalRef;
29 using content::GetFieldID;
33 struct XWalkSettings::FieldIds {
34 // Note on speed. One may think that an approach that reads field values via
35 // JNI is ineffective and should not be used. Please keep in mind that in the
36 // legacy WebView the whole Sync method took <1ms on Xoom, and no one is
37 // expected to modify settings in performance-critical code.
40 explicit FieldIds(JNIEnv* env) {
41 const char* kStringClassName = "Ljava/lang/String;";
43 // FIXME: we should be using a new GetFieldIDFromClassName() with caching.
44 ScopedJavaLocalRef<jclass> clazz(
45 GetClass(env, "org/xwalk/core/XWalkSettings"));
46 allow_scripts_to_close_windows =
47 GetFieldID(env, clazz, "mAllowScriptsToCloseWindows", "Z");
48 load_images_automatically =
49 GetFieldID(env, clazz, "mLoadsImagesAutomatically", "Z");
51 GetFieldID(env, clazz, "mImagesEnabled", "Z");
53 GetFieldID(env, clazz, "mJavaScriptEnabled", "Z");
54 allow_universal_access_from_file_urls =
55 GetFieldID(env, clazz, "mAllowUniversalAccessFromFileURLs", "Z");
56 allow_file_access_from_file_urls =
57 GetFieldID(env, clazz, "mAllowFileAccessFromFileURLs", "Z");
58 java_script_can_open_windows_automatically =
59 GetFieldID(env, clazz, "mJavaScriptCanOpenWindowsAutomatically", "Z");
60 support_multiple_windows =
61 GetFieldID(env, clazz, "mSupportMultipleWindows", "Z");
63 GetFieldID(env, clazz, "mDomStorageEnabled", "Z");
65 GetFieldID(env, clazz, "mDatabaseEnabled", "Z");
67 GetFieldID(env, clazz, "mUseWideViewport", "Z");
68 media_playback_requires_user_gesture =
69 GetFieldID(env, clazz, "mMediaPlaybackRequiresUserGesture", "Z");
70 default_video_poster_url =
71 GetFieldID(env, clazz, "mDefaultVideoPosterURL", kStringClassName);
75 jfieldID allow_scripts_to_close_windows;
76 jfieldID load_images_automatically;
77 jfieldID images_enabled;
78 jfieldID java_script_enabled;
79 jfieldID allow_universal_access_from_file_urls;
80 jfieldID allow_file_access_from_file_urls;
81 jfieldID java_script_can_open_windows_automatically;
82 jfieldID support_multiple_windows;
83 jfieldID dom_storage_enabled;
84 jfieldID database_enabled;
85 jfieldID use_wide_viewport;
86 jfieldID media_playback_requires_user_gesture;
87 jfieldID default_video_poster_url;
90 XWalkSettings::XWalkSettings(JNIEnv* env, jobject obj, jint web_contents)
91 : WebContentsObserver(
92 reinterpret_cast<content::WebContents*>(web_contents)),
93 xwalk_settings_(env, obj) {
96 XWalkSettings::~XWalkSettings() {
97 JNIEnv* env = base::android::AttachCurrentThread();
98 ScopedJavaLocalRef<jobject> scoped_obj = xwalk_settings_.get(env);
99 jobject obj = scoped_obj.obj();
101 Java_XWalkSettings_nativeXWalkSettingsGone(env, obj,
102 reinterpret_cast<jint>(this));
105 void XWalkSettings::Destroy(JNIEnv* env, jobject obj) {
109 XWalkRenderViewHostExt* XWalkSettings::GetXWalkRenderViewHostExt() {
110 if (!web_contents()) return NULL;
111 XWalkContent* contents = XWalkContent::FromWebContents(web_contents());
112 if (!contents) return NULL;
113 return contents->render_view_host_ext();
116 void XWalkSettings::UpdateEverything() {
117 JNIEnv* env = base::android::AttachCurrentThread();
119 ScopedJavaLocalRef<jobject> scoped_obj = xwalk_settings_.get(env);
120 jobject obj = scoped_obj.obj();
123 Java_XWalkSettings_updateEverything(env, obj);
126 void XWalkSettings::UpdateEverythingLocked(JNIEnv* env, jobject obj) {
127 UpdateWebkitPreferences(env, obj);
128 UpdateUserAgent(env, obj);
131 void XWalkSettings::UpdateUserAgent(JNIEnv* env, jobject obj) {
132 if (!web_contents()) return;
134 ScopedJavaLocalRef<jstring> str =
135 Java_XWalkSettings_getUserAgentLocked(env, obj);
136 bool ua_overidden = str.obj() != NULL;
139 std::string override = base::android::ConvertJavaStringToUTF8(str);
140 web_contents()->SetUserAgentOverride(override);
143 const content::NavigationController& controller =
144 web_contents()->GetController();
145 for (int i = 0; i < controller.GetEntryCount(); ++i)
146 controller.GetEntryAtIndex(i)->SetIsOverridingUserAgent(ua_overidden);
149 void XWalkSettings::UpdateWebkitPreferences(JNIEnv* env, jobject obj) {
150 if (!web_contents()) return;
151 XWalkRenderViewHostExt* render_view_host_ext = GetXWalkRenderViewHostExt();
152 if (!render_view_host_ext) return;
155 field_ids_.reset(new FieldIds(env));
157 content::RenderViewHost* render_view_host =
158 web_contents()->GetRenderViewHost();
159 if (!render_view_host) return;
160 WebPreferences prefs = render_view_host->GetWebkitPreferences();
162 prefs.allow_scripts_to_close_windows =
163 env->GetBooleanField(obj, field_ids_->allow_scripts_to_close_windows);
165 prefs.loads_images_automatically =
166 env->GetBooleanField(obj, field_ids_->load_images_automatically);
168 prefs.images_enabled =
169 env->GetBooleanField(obj, field_ids_->images_enabled);
171 prefs.javascript_enabled =
172 env->GetBooleanField(obj, field_ids_->java_script_enabled);
174 prefs.allow_universal_access_from_file_urls = env->GetBooleanField(
175 obj, field_ids_->allow_universal_access_from_file_urls);
177 prefs.allow_file_access_from_file_urls = env->GetBooleanField(
178 obj, field_ids_->allow_file_access_from_file_urls);
180 prefs.javascript_can_open_windows_automatically = env->GetBooleanField(
181 obj, field_ids_->java_script_can_open_windows_automatically);
183 prefs.supports_multiple_windows = env->GetBooleanField(
184 obj, field_ids_->support_multiple_windows);
186 prefs.application_cache_enabled =
187 Java_XWalkSettings_getAppCacheEnabled(env, obj);
189 prefs.local_storage_enabled = env->GetBooleanField(
190 obj, field_ids_->dom_storage_enabled);
192 prefs.databases_enabled = env->GetBooleanField(
193 obj, field_ids_->database_enabled);
195 prefs.double_tap_to_zoom_enabled = prefs.use_wide_viewport =
196 env->GetBooleanField(obj, field_ids_->use_wide_viewport);
198 prefs.user_gesture_required_for_media_playback = env->GetBooleanField(
199 obj, field_ids_->media_playback_requires_user_gesture);
201 ScopedJavaLocalRef<jstring> str;
203 env, static_cast<jstring>(
204 env->GetObjectField(obj, field_ids_->default_video_poster_url)));
205 prefs.default_video_poster_url = str.obj() ?
206 GURL(ConvertJavaStringToUTF8(str)) : GURL();
208 render_view_host->UpdateWebkitPreferences(prefs);
211 void XWalkSettings::RenderViewCreated(
212 content::RenderViewHost* render_view_host) {
213 // A single WebContents can normally have 0 to many RenderViewHost instances
214 // associated with it.
215 // This is important since there is only one RenderViewHostExt instance per
216 // WebContents (and not one RVHExt per RVH, as you might expect) and updating
217 // settings via RVHExt only ever updates the 'current' RVH.
218 // In android_webview we don't swap out the RVH on cross-site navigations, so
219 // we shouldn't have to deal with the multiple RVH per WebContents case. That
220 // in turn means that the newly created RVH is always the 'current' RVH
221 // (since we only ever go from 0 to 1 RVH instances) and hence the DCHECK.
222 DCHECK(web_contents()->GetRenderViewHost() == render_view_host);
227 static jint Init(JNIEnv* env,
230 XWalkSettings* settings = new XWalkSettings(env, obj, web_contents);
231 return reinterpret_cast<jint>(settings);
234 static jstring GetDefaultUserAgent(JNIEnv* env, jclass clazz) {
235 return base::android::ConvertUTF8ToJavaString(
236 env, GetUserAgent()).Release();
239 bool RegisterXWalkSettings(JNIEnv* env) {
240 return RegisterNativesImpl(env) >= 0;