Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/input/ChromiumInputConnectionFactory.java

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixed release test failures Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 package org.chromium.content.browser.input;
6
7 import android.content.Context;
8 import android.os.Handler;
9 import android.os.HandlerThread;
10 import android.os.Looper;
11 import android.os.Message;
12 import android.os.MessageQueue;
13 import android.view.View;
14 import android.view.inputmethod.EditorInfo;
15 import android.view.inputmethod.InputMethodManager;
16
17 import org.chromium.base.Log;
18
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23
24 /**
25 * Default factory for ChromiumBaseInputConnection classes.
26 */
27 public class ChromiumInputConnectionFactory implements ChromiumBaseInputConnecti on.Factory {
28 private static final String TAG = "cr_Ime";
29
30 private ChromiumInputConnection mChromiumInputConnection;
31 private final Handler mHandler;
32 private final ChromiumInputConnection.ThreadManager mThreadManager;
33
34 ChromiumInputConnectionFactory() {
35 HandlerThread thread =
36 new HandlerThread("InputConnectionHandlerThread", HandlerThread. NORM_PRIORITY);
37 thread.start();
38 mHandler = new Handler(thread.getLooper());
39 mThreadManager = new ChromiumInputConnection.ThreadManager(mHandler);
40 }
41
42 @Override
43 public ChromiumBaseInputConnection get(View view, ImeAdapter imeAdapter, int inputType,
aelias_OOO_until_Jul13 2016/01/21 07:43:04 Since this method is destructive, I'd prefer it be
Changwan Ryu 2016/01/22 10:22:16 Changed to initializeAndGet.
44 int inputFlags, EditorInfo outAttrs) {
45 ImeUtils.assertOnUiThread();
46 if (mChromiumInputConnection == null) {
47 Log.w(TAG, "Creating ChromiumInputConnection...");
aelias_OOO_until_Jul13 2016/01/21 07:43:04 Log.d
Changwan Ryu 2016/01/22 10:22:16 Done.
48 mChromiumInputConnection = new ChromiumInputConnection(imeAdapter, m ThreadManager);
49 }
50 mChromiumInputConnection.initializeOnUiThread(inputType, inputFlags, out Attrs);
51 switchInputConnectionLooper(view.getContext(), view.getHandler());
52 return mChromiumInputConnection;
53 }
54
55 /**
56 * Pump messages from a handler and add them to another handler.
57 *
58 * @param sourceHandler The source handler.
59 * @param targetHandler The target handler.
60 * @throws NoSuchFieldException
61 * @throws IllegalAccessException
62 * @throws IllegalArgumentException
63 * @throws NoSuchMethodException
64 * @throws InvocationTargetException
65 */
66 private void pumpHandlerMessages(Handler sourceHandler, Handler targetHandle r)
67 throws NoSuchFieldException, IllegalAccessException, IllegalArgument Exception,
68 NoSuchMethodException, InvocationTargetException {
69 Looper looper = sourceHandler.getLooper();
70 Method getQueueMethod = Looper.class.getDeclaredMethod("getQueue");
71 getQueueMethod.setAccessible(true);
72 MessageQueue queue = (MessageQueue) getQueueMethod.invoke(looper);
73 getQueueMethod.setAccessible(false);
74
75 Field messagesField = MessageQueue.class.getDeclaredField("mMessages");
76 Field nextField = Message.class.getDeclaredField("next");
77
78 synchronized (queue) {
79 // Copy messages first.
80 messagesField.setAccessible(true);
81 nextField.setAccessible(true);
82 Message msg = (Message) messagesField.get(queue);
83 while (msg != null) {
84 if (msg.getTarget() == sourceHandler) {
85 Log.d(TAG, "Copying a message to the new handler...");
86 Message newMsg = targetHandler.obtainMessage();
87 newMsg.copyFrom(msg);
88 targetHandler.sendMessage(newMsg);
89 }
90 msg = (Message) nextField.get(msg);
91 }
92 messagesField.setAccessible(false);
93 nextField.setAccessible(false);
94
95 // Now remove messages from the first handler.
96 sourceHandler.removeCallbacksAndMessages(null);
97 }
98 }
99
100 /**
101 * Switch the looper in InputMethodManager so that future calls to InputConn ection
102 * can run in IME thread.
103 *
104 * @param context The context
105 * @param viewHandler The current handler for the View that this InputConnec tion will be
106 * attached to.
107 */
108 private void switchInputConnectionLooper(Context context, Handler viewHandle r) {
109 Log.d(TAG, "switchInputConnectionLooper");
110 // Retrieve the same singleton instance of InputMethodManager that calle d
111 // onCreateInputConnection().
112 final InputMethodManager inputMethodManager =
113 (InputMethodManager) context.getSystemService(Context.INPUT_METH OD_SERVICE);
114 final Handler icHandler = mHandler;
115 viewHandler.post(new Runnable() {
116 @Override
117 public void run() {
118 Log.d(TAG, "switchInputConnectionLooper: replacing looper and ha ndler");
119 try {
120 // inputMethodManager.mServedInputConnectionWrapper.mMainLoo per =
121 // icHandler.getLooper();
122 Field inputConnectionWrapperField = InputMethodManager.class .getDeclaredField(
123 "mServedInputConnectionWrapper");
124 inputConnectionWrapperField.setAccessible(true);
125 Object inputConnectionWrapper =
126 inputConnectionWrapperField.get(inputMethodManager);
127 Class<?> iinputConnectionWrapperClass =
128 Class.forName("com.android.internal.view.IInputConne ctionWrapper");
129 Field looperField =
130 iinputConnectionWrapperClass.getDeclaredField("mMain Looper");
131 looperField.setAccessible(true);
132 looperField.set(inputConnectionWrapper, icHandler.getLooper( ));
133 looperField.setAccessible(false);
134
135 // inputMethodManager.mServedInputConnectionWrapper.mH =
136 // new IInputConnectionWrapper.MyHandler(icHandler.g etLooper());
137 Class<?> myHandlerClass = Class.forName(
138 "com.android.internal.view.IInputConnectionWrapper$M yHandler");
139 Constructor<?> ctor = myHandlerClass.getDeclaredConstructor(
140 iinputConnectionWrapperClass, Looper.class);
141 ctor.setAccessible(true);
142 Handler myHandler = (Handler) ctor.newInstance(
143 inputConnectionWrapper, icHandler.getLooper());
144 Field handlerField = iinputConnectionWrapperClass.getDeclare dField("mH");
145 ctor.setAccessible(false);
146 handlerField.setAccessible(true);
147 Handler oldHandler = (Handler) handlerField.get(inputConnect ionWrapper);
148 handlerField.set(inputConnectionWrapper, myHandler);
149 handlerField.setAccessible(false);
150
151 pumpHandlerMessages(oldHandler, myHandler);
152 } catch (IllegalAccessException | IllegalArgumentException | NoS uchFieldException
153 | ClassNotFoundException | NoSuchMethodException | Insta ntiationException
154 | InvocationTargetException | NullPointerException e) {
155 e.printStackTrace();
156 return;
157 }
158 Log.d(TAG, "switchInputConnectionLooper: replacing done.");
159 }
160 });
161 }
162 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698