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

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

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 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 2015 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.Looper;
10 import android.os.Message;
11 import android.os.MessageQueue;
12 import android.text.Editable;
13 import android.view.View;
14 import android.view.inputmethod.EditorInfo;
15 import android.view.inputmethod.InputMethodManager;
16
17 import org.chromium.base.CommandLine;
18 import org.chromium.base.Log;
19 import org.chromium.content.common.ContentSwitches;
20
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24
25 /**
26 * Default factory for ChromiumBaseInputConnection classes.
27 */
28 public class ChromiumBaseInputConnectionFactory {
29 private static final String TAG = "cr.Ime";
30
31 private ChromiumInputConnection mChromiumInputConnection;
32 private View mView;
aelias_OOO_until_Jul13 2015/09/30 00:10:03 This member variable is only used to recreate if t
Changwan Ryu 2016/01/19 07:31:53 Removed and moved the logic up to ImeAdapter.
33
34 public ChromiumBaseInputConnection get(
35 View view, ImeAdapter imeAdapter, Editable editable, EditorInfo outA ttrs) {
36 if (CommandLine.getInstance().hasSwitch(ContentSwitches.USE_IME_THREAD)) {
37 ImeUtils.assertOnUiThread();
38 if (mChromiumInputConnection == null || view != mView) {
39 Log.w(TAG, "Creating ChromiumInputConnection...");
40 mChromiumInputConnection = new ChromiumInputConnection(view, ime Adapter);
41 ImeUtils.assertReally("View: " + view, mView == null || view == mView);
42 mView = view;
43 }
44 mChromiumInputConnection.reset();
45 mChromiumInputConnection.updateEditorInfo(
46 outAttrs, imeAdapter.getTextInputType(), imeAdapter.getTextI nputFlags());
47 switchInputConnectionLooper(view.getContext(), view.getHandler());
48 return mChromiumInputConnection;
49 } else {
50 return new AdapterInputConnection(view, imeAdapter, editable, outAtt rs);
51 }
52 }
53
54 /**
55 * Pump messages from a handler and add them to another handler.
56 *
57 * @param sourceHandler The source handler.
58 * @param targetHandler The target handler.
59 * @throws NoSuchFieldException
60 * @throws IllegalAccessException
61 * @throws IllegalArgumentException
62 */
63 private void pumpHandlerMessages(Handler sourceHandler, Handler targetHandle r)
64 throws NoSuchFieldException, IllegalAccessException, IllegalArgument Exception {
65 MessageQueue queue = sourceHandler.getLooper().getQueue();
66 Field messagesField = MessageQueue.class.getDeclaredField("mMessages");
67 Field nextField = Message.class.getDeclaredField("next");
68
69 synchronized (queue) {
70 // Copy messages first.
71 messagesField.setAccessible(true);
72 nextField.setAccessible(true);
73 Message msg = (Message) messagesField.get(queue);
74 while (msg != null) {
75 if (msg.getTarget() == sourceHandler) {
76 Log.d(TAG, "Copying a message to the new handler...");
77 Message newMsg = targetHandler.obtainMessage();
78 newMsg.copyFrom(msg);
79 targetHandler.sendMessage(newMsg);
80 }
81 msg = (Message) nextField.get(msg);
82 }
83 messagesField.setAccessible(false);
84 nextField.setAccessible(false);
85
86 // Now remove messages from the first handler.
87 sourceHandler.removeCallbacksAndMessages(null);
aelias_OOO_until_Jul13 2015/09/18 04:59:30 Is there any signal we can use to filter for IME-r
Changwan Ryu 2015/09/18 07:34:59 This removes callbacks and messages that belong to
88 }
89 }
90
91 /**
92 * Switch the looper in InputMethodManager so that future calls to InputConn ection
93 * can run in IME thread.
94 * TODO(changwan): add more description
95 *
96 * @param context
97 * @param viewHandler
98 */
99 private void switchInputConnectionLooper(Context context, Handler viewHandle r) {
Changwan Ryu 2015/09/17 06:58:01 Alex, this is the logic that implements the idea w
100 Log.d(TAG, "switchInputConnectionLooper");
101 // Retrieve the same singleton instance of InputMethodManager that calle d
102 // onCreateInputConnection().
103 final InputMethodManager inputMethodManager =
104 (InputMethodManager) context.getSystemService(Context.INPUT_METH OD_SERVICE);
105 final Handler icHandler = InputConnectionHandlerFactory.getInputConnecti onHandler();
106 viewHandler.post(new Runnable() {
107 @Override
108 public void run() {
109 Log.d(TAG, "switchInputConnectionLooper: replacing looper and ha ndler");
110 try {
111 // inputMethodManager.mServedInputConnectionWrapper.mMainLoo per =
112 // icHandler.getLooper();
113 Field inputConnectionWrapperField = InputMethodManager.class .getDeclaredField(
114 "mServedInputConnectionWrapper");
115 inputConnectionWrapperField.setAccessible(true);
116 Object inputConnectionWrapper =
117 inputConnectionWrapperField.get(inputMethodManager);
118 Class<?> iinputConnectionWrapperClass =
119 Class.forName("com.android.internal.view.IInputConne ctionWrapper");
120 Field looperField =
121 iinputConnectionWrapperClass.getDeclaredField("mMain Looper");
122 looperField.setAccessible(true);
123 looperField.set(inputConnectionWrapper, icHandler.getLooper( ));
124 looperField.setAccessible(false);
125
126 // inputMethodManager.mServedInputConnectionWrapper.mH =
127 // new IInputConnectionWrapper.MyHandler(icHandler.g etLooper());
128 Class<?> myHandlerClass = Class.forName(
129 "com.android.internal.view.IInputConnectionWrapper$M yHandler");
130 Constructor<?> ctor = myHandlerClass.getDeclaredConstructor(
131 iinputConnectionWrapperClass, Looper.class);
132 ctor.setAccessible(true);
133 Handler myHandler = (Handler) ctor.newInstance(
134 inputConnectionWrapper, icHandler.getLooper());
135 Field handlerField = iinputConnectionWrapperClass.getDeclare dField("mH");
136 ctor.setAccessible(false);
137 handlerField.setAccessible(true);
138 Handler oldHandler = (Handler) handlerField.get(inputConnect ionWrapper);
139 handlerField.set(inputConnectionWrapper, myHandler);
140 handlerField.setAccessible(false);
141
142 pumpHandlerMessages(oldHandler, myHandler);
143 } catch (IllegalAccessException | IllegalArgumentException | NoS uchFieldException
144 | ClassNotFoundException | NoSuchMethodException | Insta ntiationException
145 | InvocationTargetException | NullPointerException e) {
146 e.printStackTrace();
147 return;
148 }
149 Log.d(TAG, "switchInputConnectionLooper: replacing done.");
150 }
151 });
152 }
153 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698