web_contents_delegate_android.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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.
4
5#include "components/web_contents_delegate_android/web_contents_delegate_android.h"
6
7#include <android/keycodes.h>
8
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 "content/public/browser/android/content_view_core.h"
14#include "content/public/browser/color_chooser.h"
15#include "content/public/browser/invalidate_type.h"
16#include "content/public/browser/native_web_keyboard_event.h"
17#include "content/public/browser/page_navigator.h"
18#include "content/public/browser/render_widget_host_view.h"
19#include "content/public/browser/web_contents.h"
20#include "content/public/common/page_transition_types.h"
21#include "content/public/common/referrer.h"
22#include "jni/WebContentsDelegateAndroid_jni.h"
23#include "ui/base/window_open_disposition.h"
24#include "ui/gfx/rect.h"
25#include "url/gurl.h"
26
27using base::android::AttachCurrentThread;
28using base::android::ConvertUTF8ToJavaString;
29using base::android::ConvertUTF16ToJavaString;
30using base::android::ScopedJavaLocalRef;
31using content::ColorChooser;
32using content::WebContents;
33using content::WebContentsDelegate;
34
35namespace web_contents_delegate_android {
36
37WebContentsDelegateAndroid::WebContentsDelegateAndroid(JNIEnv* env, jobject obj)
38    : weak_java_delegate_(env, obj) {
39}
40
41WebContentsDelegateAndroid::~WebContentsDelegateAndroid() {
42}
43
44ScopedJavaLocalRef<jobject>
45WebContentsDelegateAndroid::GetJavaDelegate(JNIEnv* env) const {
46  return weak_java_delegate_.get(env);
47}
48
49// ----------------------------------------------------------------------------
50// WebContentsDelegate methods
51// ----------------------------------------------------------------------------
52
53ColorChooser* WebContentsDelegateAndroid::OpenColorChooser(WebContents* source,
54                                                           SkColor color)  {
55  return new ColorChooserAndroid(source, color);
56}
57
58// OpenURLFromTab() will be called when we're performing a browser-intiated
59// navigation. The most common scenario for this is opening new tabs (see
60// RenderViewImpl::decidePolicyForNavigation for more details).
61WebContents* WebContentsDelegateAndroid::OpenURLFromTab(
62    WebContents* source,
63    const content::OpenURLParams& params) {
64  const GURL& url = params.url;
65  WindowOpenDisposition disposition = params.disposition;
66  content::PageTransition transition(
67      PageTransitionFromInt(params.transition));
68
69  if (!source || (disposition != CURRENT_TAB &&
70                  disposition != NEW_FOREGROUND_TAB &&
71                  disposition != NEW_BACKGROUND_TAB &&
72                  disposition != OFF_THE_RECORD)) {
73    NOTIMPLEMENTED();
74    return NULL;
75  }
76
77  JNIEnv* env = AttachCurrentThread();
78  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
79  if (obj.is_null())
80    return WebContentsDelegate::OpenURLFromTab(source, params);
81
82  if (disposition == NEW_FOREGROUND_TAB ||
83      disposition == NEW_BACKGROUND_TAB ||
84      disposition == OFF_THE_RECORD) {
85    JNIEnv* env = AttachCurrentThread();
86    ScopedJavaLocalRef<jstring> java_url =
87        ConvertUTF8ToJavaString(env, url.spec());
88    ScopedJavaLocalRef<jstring> extra_headers =
89            ConvertUTF8ToJavaString(env, params.extra_headers);
90    ScopedJavaLocalRef<jbyteArray> post_data;
91    if (params.uses_post &&
92        params.browser_initiated_post_data.get() &&
93        params.browser_initiated_post_data.get()->size()) {
94      post_data = base::android::ToJavaByteArray(
95          env,
96          reinterpret_cast<const uint8*>(
97              params.browser_initiated_post_data.get()->front()),
98          params.browser_initiated_post_data.get()->size());
99    }
100    Java_WebContentsDelegateAndroid_openNewTab(env,
101                                               obj.obj(),
102                                               java_url.obj(),
103                                               extra_headers.obj(),
104                                               post_data.obj(),
105                                               disposition);
106    return NULL;
107  }
108
109  source->GetController().LoadURL(url, params.referrer, transition,
110                                  std::string());
111  return source;
112}
113
114void WebContentsDelegateAndroid::NavigationStateChanged(
115    const WebContents* source, unsigned changed_flags) {
116  JNIEnv* env = AttachCurrentThread();
117  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
118  if (obj.is_null())
119    return;
120  Java_WebContentsDelegateAndroid_navigationStateChanged(
121      env,
122      obj.obj(),
123      changed_flags);
124}
125
126void WebContentsDelegateAndroid::ActivateContents(WebContents* contents) {
127  JNIEnv* env = AttachCurrentThread();
128  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
129  if (obj.is_null())
130    return;
131  Java_WebContentsDelegateAndroid_activateContents(env, obj.obj());
132}
133
134void WebContentsDelegateAndroid::DeactivateContents(WebContents* contents) {
135  // On desktop the current window is deactivated here, bringing the next window
136  // to focus. Not implemented on Android.
137}
138
139void WebContentsDelegateAndroid::LoadingStateChanged(WebContents* source) {
140  JNIEnv* env = AttachCurrentThread();
141  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
142  if (obj.is_null())
143    return;
144  bool has_stopped = source == NULL || !source->IsLoading();
145
146  if (has_stopped)
147    Java_WebContentsDelegateAndroid_onLoadStopped(env, obj.obj());
148  else
149    Java_WebContentsDelegateAndroid_onLoadStarted(env, obj.obj());
150}
151
152void WebContentsDelegateAndroid::LoadProgressChanged(WebContents* source,
153                                                     double progress) {
154  JNIEnv* env = AttachCurrentThread();
155  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
156  if (obj.is_null())
157    return;
158  Java_WebContentsDelegateAndroid_notifyLoadProgressChanged(
159      env,
160      obj.obj(),
161      progress);
162}
163
164void WebContentsDelegateAndroid::RendererUnresponsive(WebContents* source) {
165  JNIEnv* env = AttachCurrentThread();
166  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
167  if (obj.is_null())
168    return;
169  Java_WebContentsDelegateAndroid_rendererUnresponsive(env, obj.obj());
170}
171
172void WebContentsDelegateAndroid::RendererResponsive(WebContents* source) {
173  JNIEnv* env = AttachCurrentThread();
174  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
175  if (obj.is_null())
176    return;
177  Java_WebContentsDelegateAndroid_rendererResponsive(env, obj.obj());
178}
179
180void WebContentsDelegateAndroid::CloseContents(WebContents* source) {
181  JNIEnv* env = AttachCurrentThread();
182  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
183  if (obj.is_null())
184    return;
185  Java_WebContentsDelegateAndroid_closeContents(env, obj.obj());
186}
187
188void WebContentsDelegateAndroid::MoveContents(WebContents* source,
189                                              const gfx::Rect& pos) {
190  // Do nothing.
191}
192
193bool WebContentsDelegateAndroid::AddMessageToConsole(
194    WebContents* source,
195    int32 level,
196    const base::string16& message,
197    int32 line_no,
198    const base::string16& source_id) {
199  JNIEnv* env = AttachCurrentThread();
200  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
201  if (obj.is_null())
202    return WebContentsDelegate::AddMessageToConsole(source, level, message,
203                                                    line_no, source_id);
204  ScopedJavaLocalRef<jstring> jmessage(ConvertUTF16ToJavaString(env, message));
205  ScopedJavaLocalRef<jstring> jsource_id(
206      ConvertUTF16ToJavaString(env, source_id));
207  int jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_DEBUG;
208  switch (level) {
209    case logging::LOG_VERBOSE:
210      jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_DEBUG;
211      break;
212    case logging::LOG_INFO:
213      jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_LOG;
214      break;
215    case logging::LOG_WARNING:
216      jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_WARNING;
217      break;
218    case logging::LOG_ERROR:
219      jlevel = WEB_CONTENTS_DELEGATE_LOG_LEVEL_ERROR;
220      break;
221    default:
222      NOTREACHED();
223  }
224  return Java_WebContentsDelegateAndroid_addMessageToConsole(
225      env,
226      GetJavaDelegate(env).obj(),
227      jlevel,
228      jmessage.obj(),
229      line_no,
230      jsource_id.obj());
231}
232
233// This is either called from TabContents::DidNavigateMainFramePostCommit() with
234// an empty GURL or responding to RenderViewHost::OnMsgUpateTargetURL(). In
235// Chrome, the latter is not always called, especially not during history
236// navigation. So we only handle the first case and pass the source TabContents'
237// url to Java to update the UI.
238void WebContentsDelegateAndroid::UpdateTargetURL(WebContents* source,
239                                                 int32 page_id,
240                                                 const GURL& url) {
241  if (!url.is_empty())
242    return;
243  JNIEnv* env = AttachCurrentThread();
244  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
245  if (obj.is_null())
246    return;
247  ScopedJavaLocalRef<jstring> java_url =
248      ConvertUTF8ToJavaString(env, source->GetURL().spec());
249  Java_WebContentsDelegateAndroid_onUpdateUrl(env,
250                                              obj.obj(),
251                                              java_url.obj());
252}
253
254void WebContentsDelegateAndroid::HandleKeyboardEvent(
255    WebContents* source,
256    const content::NativeWebKeyboardEvent& event) {
257  jobject key_event = event.os_event;
258  if (key_event) {
259    JNIEnv* env = AttachCurrentThread();
260    ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
261    if (obj.is_null())
262      return;
263    Java_WebContentsDelegateAndroid_handleKeyboardEvent(
264        env, obj.obj(), key_event);
265  }
266}
267
268bool WebContentsDelegateAndroid::TakeFocus(WebContents* source, bool reverse) {
269  JNIEnv* env = AttachCurrentThread();
270  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
271  if (obj.is_null())
272    return WebContentsDelegate::TakeFocus(source, reverse);
273  return Java_WebContentsDelegateAndroid_takeFocus(
274      env, obj.obj(), reverse);
275}
276
277void WebContentsDelegateAndroid::ShowRepostFormWarningDialog(
278    WebContents* source) {
279  JNIEnv* env = AttachCurrentThread();
280  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
281  if (obj.is_null())
282    return;
283  ScopedJavaLocalRef<jobject> content_view_core =
284      content::ContentViewCore::FromWebContents(source)->GetJavaObject();
285  if (content_view_core.is_null())
286    return;
287  Java_WebContentsDelegateAndroid_showRepostFormWarningDialog(env, obj.obj(),
288      content_view_core.obj());
289}
290
291void WebContentsDelegateAndroid::ToggleFullscreenModeForTab(
292    WebContents* web_contents,
293    bool enter_fullscreen) {
294  JNIEnv* env = AttachCurrentThread();
295  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
296  if (obj.is_null())
297    return;
298  Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(
299      env, obj.obj(), enter_fullscreen);
300}
301
302bool WebContentsDelegateAndroid::IsFullscreenForTabOrPending(
303    const WebContents* web_contents) const {
304  JNIEnv* env = AttachCurrentThread();
305  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
306  if (obj.is_null())
307    return false;
308  return Java_WebContentsDelegateAndroid_isFullscreenForTabOrPending(
309      env, obj.obj());
310}
311
312void WebContentsDelegateAndroid::DidProgrammaticallyScroll(
313    WebContents* web_contents, const gfx::Vector2d& scroll_point) {
314  JNIEnv* env = AttachCurrentThread();
315  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
316  if (obj.is_null())
317    return;
318  Java_WebContentsDelegateAndroid_didProgrammaticallyScroll(
319      env, obj.obj(), scroll_point.x(), scroll_point.y());
320}
321
322// ----------------------------------------------------------------------------
323// Native JNI methods
324// ----------------------------------------------------------------------------
325
326// Register native methods
327
328bool RegisterWebContentsDelegateAndroid(JNIEnv* env) {
329  return RegisterNativesImpl(env);
330}
331
332}  // namespace web_contents_delegate_android
333