Battery Status API: add UMA logging for Linux.
[chromium-blink-merge.git] / content / browser / renderer_host / ime_adapter_android.cc
blob077e625f0ca9560da5378bc8228704d1817f5855
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 "content/browser/renderer_host/ime_adapter_android.h"
7 #include <algorithm>
8 #include <android/input.h>
9 #include <vector>
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h"
13 #include "base/android/scoped_java_ref.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "content/browser/frame_host/frame_tree.h"
17 #include "content/browser/frame_host/frame_tree_node.h"
18 #include "content/browser/frame_host/render_frame_host_impl.h"
19 #include "content/browser/renderer_host/render_view_host_delegate.h"
20 #include "content/browser/renderer_host/render_view_host_impl.h"
21 #include "content/browser/renderer_host/render_widget_host_impl.h"
22 #include "content/browser/renderer_host/render_widget_host_view_android.h"
23 #include "content/common/frame_messages.h"
24 #include "content/common/input_messages.h"
25 #include "content/common/view_messages.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/native_web_keyboard_event.h"
28 #include "content/public/browser/web_contents.h"
29 #include "jni/ImeAdapter_jni.h"
30 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
31 #include "third_party/WebKit/public/web/WebInputEvent.h"
32 #include "third_party/WebKit/public/web/WebTextInputType.h"
34 using base::android::AttachCurrentThread;
35 using base::android::ConvertJavaStringToUTF16;
37 namespace content {
38 namespace {
40 // Maps a java KeyEvent into a NativeWebKeyboardEvent.
41 // |java_key_event| is used to maintain a globalref for KeyEvent.
42 // |action| will help determine the WebInputEvent type.
43 // type, |modifiers|, |time_ms|, |key_code|, |unicode_char| is used to create
44 // WebKeyboardEvent. |key_code| is also needed ad need to treat the enter key
45 // as a key press of character \r.
46 NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent(
47 JNIEnv* env,
48 jobject java_key_event,
49 int action,
50 int modifiers,
51 long time_ms,
52 int key_code,
53 bool is_system_key,
54 int unicode_char) {
55 blink::WebInputEvent::Type type = blink::WebInputEvent::Undefined;
56 if (action == AKEY_EVENT_ACTION_DOWN)
57 type = blink::WebInputEvent::RawKeyDown;
58 else if (action == AKEY_EVENT_ACTION_UP)
59 type = blink::WebInputEvent::KeyUp;
60 return NativeWebKeyboardEvent(java_key_event, type, modifiers,
61 time_ms / 1000.0, key_code, unicode_char, is_system_key);
64 } // anonymous namespace
66 bool RegisterImeAdapter(JNIEnv* env) {
67 if (!RegisterNativesImpl(env))
68 return false;
70 Java_ImeAdapter_initializeWebInputEvents(env,
71 blink::WebInputEvent::RawKeyDown,
72 blink::WebInputEvent::KeyUp,
73 blink::WebInputEvent::Char,
74 blink::WebInputEvent::ShiftKey,
75 blink::WebInputEvent::AltKey,
76 blink::WebInputEvent::ControlKey,
77 blink::WebInputEvent::CapsLockOn,
78 blink::WebInputEvent::NumLockOn);
79 Java_ImeAdapter_initializeTextInputTypes(
80 env,
81 ui::TEXT_INPUT_TYPE_NONE,
82 ui::TEXT_INPUT_TYPE_TEXT,
83 ui::TEXT_INPUT_TYPE_TEXT_AREA,
84 ui::TEXT_INPUT_TYPE_PASSWORD,
85 ui::TEXT_INPUT_TYPE_SEARCH,
86 ui::TEXT_INPUT_TYPE_URL,
87 ui::TEXT_INPUT_TYPE_EMAIL,
88 ui::TEXT_INPUT_TYPE_TELEPHONE,
89 ui::TEXT_INPUT_TYPE_NUMBER,
90 ui::TEXT_INPUT_TYPE_CONTENT_EDITABLE);
91 Java_ImeAdapter_initializeTextInputFlags(
92 env,
93 blink::WebTextInputFlagAutocompleteOn,
94 blink::WebTextInputFlagAutocompleteOff,
95 blink::WebTextInputFlagAutocorrectOn,
96 blink::WebTextInputFlagAutocorrectOff,
97 blink::WebTextInputFlagSpellcheckOn,
98 blink::WebTextInputFlagSpellcheckOff);
99 return true;
102 // Callback from Java to convert BackgroundColorSpan data to a
103 // blink::WebCompositionUnderline instance, and append it to |underlines_ptr|.
104 void AppendBackgroundColorSpan(JNIEnv*,
105 jclass,
106 jlong underlines_ptr,
107 jint start,
108 jint end,
109 jint background_color) {
110 DCHECK(start >= 0);
111 DCHECK(end >= 0);
112 // Do not check |background_color|.
113 std::vector<blink::WebCompositionUnderline>* underlines =
114 reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
115 underlines_ptr);
116 underlines->push_back(
117 blink::WebCompositionUnderline(static_cast<unsigned>(start),
118 static_cast<unsigned>(end),
119 SK_ColorTRANSPARENT,
120 false,
121 static_cast<unsigned>(background_color)));
124 // Callback from Java to convert UnderlineSpan data to a
125 // blink::WebCompositionUnderline instance, and append it to |underlines_ptr|.
126 void AppendUnderlineSpan(JNIEnv*,
127 jclass,
128 jlong underlines_ptr,
129 jint start,
130 jint end) {
131 DCHECK(start >= 0);
132 DCHECK(end >= 0);
133 std::vector<blink::WebCompositionUnderline>* underlines =
134 reinterpret_cast<std::vector<blink::WebCompositionUnderline>*>(
135 underlines_ptr);
136 underlines->push_back(
137 blink::WebCompositionUnderline(static_cast<unsigned>(start),
138 static_cast<unsigned>(end),
139 SK_ColorBLACK,
140 false,
141 SK_ColorTRANSPARENT));
144 ImeAdapterAndroid::ImeAdapterAndroid(RenderWidgetHostViewAndroid* rwhva)
145 : rwhva_(rwhva) {
148 ImeAdapterAndroid::~ImeAdapterAndroid() {
149 JNIEnv* env = AttachCurrentThread();
150 base::android::ScopedJavaLocalRef<jobject> obj = java_ime_adapter_.get(env);
151 if (!obj.is_null())
152 Java_ImeAdapter_detach(env, obj.obj());
155 bool ImeAdapterAndroid::SendSyntheticKeyEvent(JNIEnv*,
156 jobject,
157 int type,
158 long time_ms,
159 int key_code,
160 int modifiers,
161 int text) {
162 NativeWebKeyboardEvent event(static_cast<blink::WebInputEvent::Type>(type),
163 modifiers, time_ms / 1000.0, key_code,
164 text, false /* is_system_key */);
165 rwhva_->SendKeyEvent(event);
166 return true;
169 bool ImeAdapterAndroid::SendKeyEvent(JNIEnv* env, jobject,
170 jobject original_key_event,
171 int action, int modifiers,
172 long time_ms, int key_code,
173 bool is_system_key, int unicode_char) {
174 NativeWebKeyboardEvent event = NativeWebKeyboardEventFromKeyEvent(
175 env, original_key_event, action, modifiers,
176 time_ms, key_code, is_system_key, unicode_char);
177 bool key_down_text_insertion =
178 event.type == blink::WebInputEvent::RawKeyDown && event.text[0];
179 // If we are going to follow up with a synthetic Char event, then that's the
180 // one we expect to test if it's handled or unhandled, so skip handling the
181 // "real" event in the browser.
182 event.skip_in_browser = key_down_text_insertion;
183 rwhva_->SendKeyEvent(event);
184 if (key_down_text_insertion) {
185 // Send a Char event, but without an os_event since we don't want to
186 // roundtrip back to java such synthetic event.
187 NativeWebKeyboardEvent char_event(blink::WebInputEvent::Char, modifiers,
188 time_ms / 1000.0, key_code, unicode_char,
189 is_system_key);
190 char_event.skip_in_browser = key_down_text_insertion;
191 rwhva_->SendKeyEvent(char_event);
193 return true;
196 void ImeAdapterAndroid::SetComposingText(JNIEnv* env,
197 jobject obj,
198 jobject text,
199 jstring text_str,
200 int new_cursor_pos) {
201 RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
202 if (!rwhi)
203 return;
205 base::string16 text16 = ConvertJavaStringToUTF16(env, text_str);
207 std::vector<blink::WebCompositionUnderline> underlines;
208 // Iterate over spans in |text|, dispatch those that we care about (e.g.,
209 // BackgroundColorSpan) to a matching callback (e.g.,
210 // AppendBackgroundColorSpan()), and populate |underlines|.
211 Java_ImeAdapter_populateUnderlinesFromSpans(
212 env, obj, text, reinterpret_cast<jlong>(&underlines));
214 // Default to plain underline if we didn't find any span that we care about.
215 if (underlines.empty()) {
216 underlines.push_back(blink::WebCompositionUnderline(
217 0, text16.length(), SK_ColorBLACK, false, SK_ColorTRANSPARENT));
219 // Sort spans by |.startOffset|.
220 std::sort(underlines.begin(), underlines.end());
222 // new_cursor_position is as described in the Android API for
223 // InputConnection#setComposingText, whereas the parameters for
224 // ImeSetComposition are relative to the start of the composition.
225 if (new_cursor_pos > 0)
226 new_cursor_pos = text16.length() + new_cursor_pos - 1;
228 rwhi->ImeSetComposition(text16, underlines, new_cursor_pos, new_cursor_pos);
231 void ImeAdapterAndroid::CommitText(JNIEnv* env, jobject, jstring text_str) {
232 RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
233 if (!rwhi)
234 return;
236 base::string16 text16 = ConvertJavaStringToUTF16(env, text_str);
237 rwhi->ImeConfirmComposition(text16, gfx::Range::InvalidRange(), false);
240 void ImeAdapterAndroid::FinishComposingText(JNIEnv* env, jobject) {
241 RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
242 if (!rwhi)
243 return;
245 rwhi->ImeConfirmComposition(base::string16(), gfx::Range::InvalidRange(),
246 true);
249 void ImeAdapterAndroid::AttachImeAdapter(JNIEnv* env, jobject java_object) {
250 java_ime_adapter_ = JavaObjectWeakGlobalRef(env, java_object);
253 void ImeAdapterAndroid::CancelComposition() {
254 base::android::ScopedJavaLocalRef<jobject> obj =
255 java_ime_adapter_.get(AttachCurrentThread());
256 if (!obj.is_null())
257 Java_ImeAdapter_cancelComposition(AttachCurrentThread(), obj.obj());
260 void ImeAdapterAndroid::FocusedNodeChanged(bool is_editable_node) {
261 base::android::ScopedJavaLocalRef<jobject> obj =
262 java_ime_adapter_.get(AttachCurrentThread());
263 if (!obj.is_null()) {
264 Java_ImeAdapter_focusedNodeChanged(AttachCurrentThread(),
265 obj.obj(),
266 is_editable_node);
270 void ImeAdapterAndroid::SetEditableSelectionOffsets(JNIEnv*, jobject,
271 int start, int end) {
272 RenderFrameHost* rfh = GetFocusedFrame();
273 if (!rfh)
274 return;
276 rfh->Send(new FrameMsg_SetEditableSelectionOffsets(rfh->GetRoutingID(),
277 start, end));
280 void ImeAdapterAndroid::SetComposingRegion(JNIEnv*, jobject,
281 int start, int end) {
282 RenderFrameHost* rfh = GetFocusedFrame();
283 if (!rfh)
284 return;
286 std::vector<blink::WebCompositionUnderline> underlines;
287 underlines.push_back(blink::WebCompositionUnderline(
288 0, end - start, SK_ColorBLACK, false, SK_ColorTRANSPARENT));
290 rfh->Send(new InputMsg_SetCompositionFromExistingText(
291 rfh->GetRoutingID(), start, end, underlines));
294 void ImeAdapterAndroid::DeleteSurroundingText(JNIEnv*, jobject,
295 int before, int after) {
296 RenderFrameHostImpl* rfh =
297 static_cast<RenderFrameHostImpl*>(GetFocusedFrame());
298 if (rfh)
299 rfh->ExtendSelectionAndDelete(before, after);
302 void ImeAdapterAndroid::Unselect(JNIEnv* env, jobject) {
303 WebContents* wc = GetWebContents();
304 if (wc)
305 wc->Unselect();
308 void ImeAdapterAndroid::SelectAll(JNIEnv* env, jobject) {
309 WebContents* wc = GetWebContents();
310 if (wc)
311 wc->SelectAll();
314 void ImeAdapterAndroid::Cut(JNIEnv* env, jobject) {
315 WebContents* wc = GetWebContents();
316 if (wc)
317 wc->Cut();
320 void ImeAdapterAndroid::Copy(JNIEnv* env, jobject) {
321 WebContents* wc = GetWebContents();
322 if (wc)
323 wc->Copy();
326 void ImeAdapterAndroid::Paste(JNIEnv* env, jobject) {
327 WebContents* wc = GetWebContents();
328 if (wc)
329 wc->Paste();
332 void ImeAdapterAndroid::ResetImeAdapter(JNIEnv* env, jobject) {
333 java_ime_adapter_.reset();
336 RenderWidgetHostImpl* ImeAdapterAndroid::GetRenderWidgetHostImpl() {
337 DCHECK_CURRENTLY_ON(BrowserThread::UI);
338 DCHECK(rwhva_);
339 RenderWidgetHost* rwh = rwhva_->GetRenderWidgetHost();
340 if (!rwh)
341 return NULL;
343 return RenderWidgetHostImpl::From(rwh);
346 RenderFrameHost* ImeAdapterAndroid::GetFocusedFrame() {
347 RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
348 if (!rwh)
349 return NULL;
350 if (!rwh->IsRenderView())
351 return NULL;
352 RenderViewHost* rvh = RenderViewHost::From(rwh);
353 FrameTreeNode* focused_frame =
354 rvh->GetDelegate()->GetFrameTree()->GetFocusedFrame();
355 if (!focused_frame)
356 return NULL;
358 return focused_frame->current_frame_host();
361 WebContents* ImeAdapterAndroid::GetWebContents() {
362 RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
363 if (!rwh)
364 return NULL;
365 if (!rwh->IsRenderView())
366 return NULL;
367 return WebContents::FromRenderViewHost(RenderViewHost::From(rwh));
370 } // namespace content