1 // Copyright (c) 2012 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 "components/web_contents_delegate_android/web_contents_delegate_android.h"
7 #include <android/keycodes.h>
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_array.h"
11 #include "base/android/jni_string.h"
12 #include "components/web_contents_delegate_android/color_chooser_android.h"
13 #include "components/web_contents_delegate_android/validation_message_bubble_android.h"
14 #include "content/public/browser/android/content_view_core.h"
15 #include "content/public/browser/color_chooser.h"
16 #include "content/public/browser/invalidate_type.h"
17 #include "content/public/browser/native_web_keyboard_event.h"
18 #include "content/public/browser/page_navigator.h"
19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/common/page_transition_types.h"
22 #include "content/public/common/referrer.h"
23 #include "jni/WebContentsDelegateAndroid_jni.h"
24 #include "ui/base/window_open_disposition.h"
25 #include "ui/gfx/rect.h"
28 using base::android::AttachCurrentThread
;
29 using base::android::ConvertUTF8ToJavaString
;
30 using base::android::ConvertUTF16ToJavaString
;
31 using base::android::ScopedJavaLocalRef
;
32 using content::ColorChooser
;
33 using content::RenderWidgetHostView
;
34 using content::WebContents
;
35 using content::WebContentsDelegate
;
37 namespace web_contents_delegate_android
{
39 WebContentsDelegateAndroid::WebContentsDelegateAndroid(JNIEnv
* env
, jobject obj
)
40 : weak_java_delegate_(env
, obj
) {
43 WebContentsDelegateAndroid::~WebContentsDelegateAndroid() {
46 ScopedJavaLocalRef
<jobject
>
47 WebContentsDelegateAndroid::GetJavaDelegate(JNIEnv
* env
) const {
48 return weak_java_delegate_
.get(env
);
51 // ----------------------------------------------------------------------------
52 // WebContentsDelegate methods
53 // ----------------------------------------------------------------------------
55 ColorChooser
* WebContentsDelegateAndroid::OpenColorChooser(
58 const std::vector
<content::ColorSuggestion
>& suggestions
) {
59 return new ColorChooserAndroid(source
, color
, suggestions
);
62 // OpenURLFromTab() will be called when we're performing a browser-intiated
63 // navigation. The most common scenario for this is opening new tabs (see
64 // RenderViewImpl::decidePolicyForNavigation for more details).
65 WebContents
* WebContentsDelegateAndroid::OpenURLFromTab(
67 const content::OpenURLParams
& params
) {
68 const GURL
& url
= params
.url
;
69 WindowOpenDisposition disposition
= params
.disposition
;
70 content::PageTransition
transition(
71 PageTransitionFromInt(params
.transition
));
73 if (!source
|| (disposition
!= CURRENT_TAB
&&
74 disposition
!= NEW_FOREGROUND_TAB
&&
75 disposition
!= NEW_BACKGROUND_TAB
&&
76 disposition
!= OFF_THE_RECORD
)) {
81 JNIEnv
* env
= AttachCurrentThread();
82 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
84 return WebContentsDelegate::OpenURLFromTab(source
, params
);
86 if (disposition
== NEW_FOREGROUND_TAB
||
87 disposition
== NEW_BACKGROUND_TAB
||
88 disposition
== OFF_THE_RECORD
) {
89 JNIEnv
* env
= AttachCurrentThread();
90 ScopedJavaLocalRef
<jstring
> java_url
=
91 ConvertUTF8ToJavaString(env
, url
.spec());
92 ScopedJavaLocalRef
<jstring
> extra_headers
=
93 ConvertUTF8ToJavaString(env
, params
.extra_headers
);
94 ScopedJavaLocalRef
<jbyteArray
> post_data
;
95 if (params
.uses_post
&&
96 params
.browser_initiated_post_data
.get() &&
97 params
.browser_initiated_post_data
.get()->size()) {
98 post_data
= base::android::ToJavaByteArray(
100 params
.browser_initiated_post_data
.get()->front_as
<uint8
>(),
101 params
.browser_initiated_post_data
.get()->size());
103 Java_WebContentsDelegateAndroid_openNewTab(env
,
112 source
->GetController().LoadURL(url
, params
.referrer
, transition
,
117 void WebContentsDelegateAndroid::NavigationStateChanged(
118 const WebContents
* source
, unsigned changed_flags
) {
119 JNIEnv
* env
= AttachCurrentThread();
120 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
123 Java_WebContentsDelegateAndroid_navigationStateChanged(
129 void WebContentsDelegateAndroid::ActivateContents(WebContents
* contents
) {
130 JNIEnv
* env
= AttachCurrentThread();
131 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
134 Java_WebContentsDelegateAndroid_activateContents(env
, obj
.obj());
137 void WebContentsDelegateAndroid::DeactivateContents(WebContents
* contents
) {
138 // On desktop the current window is deactivated here, bringing the next window
139 // to focus. Not implemented on Android.
142 void WebContentsDelegateAndroid::LoadingStateChanged(WebContents
* source
) {
143 JNIEnv
* env
= AttachCurrentThread();
144 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
147 bool has_stopped
= source
== NULL
|| !source
->IsLoading();
150 Java_WebContentsDelegateAndroid_onLoadStopped(env
, obj
.obj());
152 Java_WebContentsDelegateAndroid_onLoadStarted(env
, obj
.obj());
155 void WebContentsDelegateAndroid::LoadProgressChanged(WebContents
* source
,
157 JNIEnv
* env
= AttachCurrentThread();
158 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
161 Java_WebContentsDelegateAndroid_notifyLoadProgressChanged(
167 void WebContentsDelegateAndroid::RendererUnresponsive(WebContents
* source
) {
168 JNIEnv
* env
= AttachCurrentThread();
169 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
172 Java_WebContentsDelegateAndroid_rendererUnresponsive(env
, obj
.obj());
175 void WebContentsDelegateAndroid::RendererResponsive(WebContents
* source
) {
176 JNIEnv
* env
= AttachCurrentThread();
177 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
180 Java_WebContentsDelegateAndroid_rendererResponsive(env
, obj
.obj());
183 void WebContentsDelegateAndroid::CloseContents(WebContents
* source
) {
184 JNIEnv
* env
= AttachCurrentThread();
185 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
188 Java_WebContentsDelegateAndroid_closeContents(env
, obj
.obj());
191 void WebContentsDelegateAndroid::MoveContents(WebContents
* source
,
192 const gfx::Rect
& pos
) {
196 bool WebContentsDelegateAndroid::AddMessageToConsole(
199 const base::string16
& message
,
201 const base::string16
& source_id
) {
202 JNIEnv
* env
= AttachCurrentThread();
203 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
205 return WebContentsDelegate::AddMessageToConsole(source
, level
, message
,
207 ScopedJavaLocalRef
<jstring
> jmessage(ConvertUTF16ToJavaString(env
, message
));
208 ScopedJavaLocalRef
<jstring
> jsource_id(
209 ConvertUTF16ToJavaString(env
, source_id
));
210 int jlevel
= WEB_CONTENTS_DELEGATE_LOG_LEVEL_DEBUG
;
212 case logging::LOG_VERBOSE
:
213 jlevel
= WEB_CONTENTS_DELEGATE_LOG_LEVEL_DEBUG
;
215 case logging::LOG_INFO
:
216 jlevel
= WEB_CONTENTS_DELEGATE_LOG_LEVEL_LOG
;
218 case logging::LOG_WARNING
:
219 jlevel
= WEB_CONTENTS_DELEGATE_LOG_LEVEL_WARNING
;
221 case logging::LOG_ERROR
:
222 jlevel
= WEB_CONTENTS_DELEGATE_LOG_LEVEL_ERROR
;
227 return Java_WebContentsDelegateAndroid_addMessageToConsole(
229 GetJavaDelegate(env
).obj(),
236 // This is either called from TabContents::DidNavigateMainFramePostCommit() with
237 // an empty GURL or responding to RenderViewHost::OnMsgUpateTargetURL(). In
238 // Chrome, the latter is not always called, especially not during history
239 // navigation. So we only handle the first case and pass the source TabContents'
240 // url to Java to update the UI.
241 void WebContentsDelegateAndroid::UpdateTargetURL(WebContents
* source
,
246 JNIEnv
* env
= AttachCurrentThread();
247 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
250 ScopedJavaLocalRef
<jstring
> java_url
=
251 ConvertUTF8ToJavaString(env
, source
->GetURL().spec());
252 Java_WebContentsDelegateAndroid_onUpdateUrl(env
,
257 void WebContentsDelegateAndroid::HandleKeyboardEvent(
259 const content::NativeWebKeyboardEvent
& event
) {
260 jobject key_event
= event
.os_event
;
262 JNIEnv
* env
= AttachCurrentThread();
263 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
266 Java_WebContentsDelegateAndroid_handleKeyboardEvent(
267 env
, obj
.obj(), key_event
);
271 bool WebContentsDelegateAndroid::TakeFocus(WebContents
* source
, bool reverse
) {
272 JNIEnv
* env
= AttachCurrentThread();
273 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
275 return WebContentsDelegate::TakeFocus(source
, reverse
);
276 return Java_WebContentsDelegateAndroid_takeFocus(
277 env
, obj
.obj(), reverse
);
280 void WebContentsDelegateAndroid::ShowRepostFormWarningDialog(
281 WebContents
* source
) {
282 JNIEnv
* env
= AttachCurrentThread();
283 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
286 ScopedJavaLocalRef
<jobject
> content_view_core
=
287 content::ContentViewCore::FromWebContents(source
)->GetJavaObject();
288 if (content_view_core
.is_null())
290 Java_WebContentsDelegateAndroid_showRepostFormWarningDialog(env
, obj
.obj(),
291 content_view_core
.obj());
294 void WebContentsDelegateAndroid::ToggleFullscreenModeForTab(
295 WebContents
* web_contents
,
296 bool enter_fullscreen
) {
297 JNIEnv
* env
= AttachCurrentThread();
298 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
301 Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(
302 env
, obj
.obj(), enter_fullscreen
);
305 bool WebContentsDelegateAndroid::IsFullscreenForTabOrPending(
306 const WebContents
* web_contents
) const {
307 JNIEnv
* env
= AttachCurrentThread();
308 ScopedJavaLocalRef
<jobject
> obj
= GetJavaDelegate(env
);
311 return Java_WebContentsDelegateAndroid_isFullscreenForTabOrPending(
315 void WebContentsDelegateAndroid::ShowValidationMessage(
316 WebContents
* web_contents
,
317 const gfx::Rect
& anchor_in_root_view
,
318 const base::string16
& main_text
,
319 const base::string16
& sub_text
) {
320 RenderWidgetHostView
* rwhv
= web_contents
->GetRenderWidgetHostView();
322 validation_message_bubble_
.reset(
323 new ValidationMessageBubbleAndroid(rwhv
->GetRenderWidgetHost(),
330 void WebContentsDelegateAndroid::HideValidationMessage(
331 WebContents
* web_contents
) {
332 validation_message_bubble_
.reset();
335 void WebContentsDelegateAndroid::MoveValidationMessage(
336 WebContents
* web_contents
,
337 const gfx::Rect
& anchor_in_root_view
) {
338 if (!validation_message_bubble_
)
340 RenderWidgetHostView
* rwhv
= web_contents
->GetRenderWidgetHostView();
342 validation_message_bubble_
->SetPositionRelativeToAnchor(
343 rwhv
->GetRenderWidgetHost(), anchor_in_root_view
);
346 // ----------------------------------------------------------------------------
347 // Native JNI methods
348 // ----------------------------------------------------------------------------
350 // Register native methods
352 bool RegisterWebContentsDelegateAndroid(JNIEnv
* env
) {
353 return RegisterNativesImpl(env
);
356 } // namespace web_contents_delegate_android