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

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

Issue 1278593004: Introduce ThreadedInputConnection behind a switch (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: prepare for factory unit test, propagate fallback to renderer Created 4 years, 10 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.os.Handler;
8 import android.os.HandlerThread;
9 import android.view.View;
10 import android.view.inputmethod.EditorInfo;
11
12 import org.chromium.base.CommandLine;
13 import org.chromium.base.Log;
14 import org.chromium.base.ThreadUtils;
15 import org.chromium.base.VisibleForTesting;
16 import org.chromium.content.common.ContentSwitches;
17
18 /**
19 * A factory class for {@link ThreadedInputConnection}. The class also includes triggering
20 * mechanism (hack) to run our InputConnection on non-UI thread.
21 */
22 // TODO(changwan): add unit tests once Robolectric supports Android API level >= 21.
23 // See crbug.com/588547 for details.
24 public class ThreadedInputConnectionFactory implements ChromiumBaseInputConnecti on.Factory {
25 private static final String TAG = "cr_Ime";
26 private static final boolean DEBUG_LOGS = false;
27
28 private final Handler mHandler;
29 private final InputMethodManagerWrapper mInputMethodManagerWrapper;
30 private final ImeAdapter mImeAdapter;
31 private final InputMethodUma mInputMethodUma;
32 private ThreadedInputConnectionProxyView mProxyView;
33 private ThreadedInputConnection mThreadedInputConnection;
34
35 ThreadedInputConnectionFactory(
36 InputMethodManagerWrapper inputMethodManagerWrapper, ImeAdapter imeA dapter) {
37 mImeAdapter = imeAdapter;
38 mInputMethodManagerWrapper = inputMethodManagerWrapper;
39 mHandler = createHandler();
40 mInputMethodUma = createInputMethodUma();
41 }
42
43 @VisibleForTesting
44 protected Handler createHandler() {
45 HandlerThread thread =
46 new HandlerThread("InputConnectionHandlerThread", HandlerThread. NORM_PRIORITY);
47 thread.start();
48 return new Handler(thread.getLooper());
49 }
50
51 @VisibleForTesting
52 protected ThreadedInputConnectionProxyView createProxyView(
53 Handler handler, View containerView) {
54 return new ThreadedInputConnectionProxyView(
55 containerView.getContext(), handler, containerView);
56 }
57
58 @VisibleForTesting
59 protected InputMethodUma createInputMethodUma() {
60 return new InputMethodUma();
61 }
62
63 private boolean shouldTriggerDelayedOnCreateInputConnection() {
64 for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
65 String className = ste.getClassName();
66 if (className != null
67 && (className.contains(ThreadedInputConnectionProxyView.clas s.getName())
68 || className.contains("TestInputMethodManagerWrapper"))) {
69 return false;
70 }
71 }
72 return true;
73 }
74
75 @Override
76 public ThreadedInputConnection initializeAndGet(
77 View view, ImeAdapter imeAdapter, int inputType, int inputFlags, int selectionStart,
78 int selectionEnd, EditorInfo outAttrs) {
79 ImeUtils.checkOnUiThread();
80 if (shouldTriggerDelayedOnCreateInputConnection()) {
81 triggerDelayedOnCreateInputConnection(view);
82 return null;
83 }
84 if (DEBUG_LOGS) Log.w(TAG, "initializeAndGet: called from proxy view");
85 if (mThreadedInputConnection == null) {
86 if (DEBUG_LOGS) Log.w(TAG, "Creating ThreadedInputConnection...");
87 mThreadedInputConnection = new ThreadedInputConnection(imeAdapter, m Handler);
88 }
89 mThreadedInputConnection.initializeOutAttrsOnUiThread(inputType, inputFl ags,
90 selectionStart, selectionEnd, outAttrs);
91 return mThreadedInputConnection;
92 }
93
94 private void triggerDelayedOnCreateInputConnection(final View view) {
95 if (DEBUG_LOGS) Log.w(TAG, "triggerDelayedOnCreateInputConnection");
96 if (mProxyView == null) {
97 mProxyView = createProxyView(mHandler, view);
98 }
99 mProxyView.requestFocus();
100 view.getHandler().post(new Runnable() {
101 @Override
102 public void run() {
103 // This is a hack to make InputMethodManager believe that the pr oxy view
104 // now has a focus. As a result, InputMethodManager will think t hat mProxyView
105 // is focused, and will call getHandler() of the view when creat ing input
106 // connection.
107
108 // Step 1: Set mProxyView as InputMethodManager#mNextServedView.
109 mProxyView.onWindowFocusChanged(true);
110
111 // Step 2: Have InputMethodManager focus in on mNextServedView.
112 // As a result, IMM will call onCreateInputConnection() on mProx yView on the same
113 // thread as mProxyView.getHandler(). It will also call subseque nt InputConnection
114 // methods on this IME thread.
115 mInputMethodManagerWrapper.isActive(view);
116
117 // Step 3: Check that the above hack worked.
118 mHandler.post(new Runnable() {
119 @Override
120 public void run() {
121 // Some other view already took focus. Container view sh ould be active
122 // otherwise regardless of whether proxy view is registe red or not.
123 if (!mInputMethodManagerWrapper.isActive(view)) return;
124
125 // Success.
126 if (mInputMethodManagerWrapper.isActive(mProxyView)) {
127 mInputMethodUma.recordProxyViewSuccess();
128 return;
129 }
130
131 if (mThreadedInputConnection == null) {
132 // First time and failed. It is highly likely that t his does not work
133 // systematically.
134 Log.w(TAG, "Failed to register proxy view, falling b ack to "
135 + "ReplicaInputConnection...");
136 mInputMethodUma.recordProxyViewFailure();
137 ThreadUtils.postOnUiThread(new Runnable() {
138 @Override
139 public void run() {
140 fallbackToReplicaInputConnection(view);
141 }
142 });
143 } else {
144 // Most likely that we already lost view focus.
145 mInputMethodUma.recordProxyViewDetectionFailure();
146 }
147 }
148 });
149 }
150 });
151 }
152
153 @VisibleForTesting
154 protected void fallbackToReplicaInputConnection(final View view) {
aelias_OOO_until_Jul13 2016/02/23 23:59:30 Because we plan to only ship ThreadedInputConnecti
Changwan Ryu 2016/02/24 00:43:29 Removed fallback mechanism and now we crash instea
155 // Disable IME thread until Chrome gets closed. Note that this is not a permanent
156 // change.
157 CommandLine.getInstance().appendSwitch(ContentSwitches.DISABLE_IME_THREA D);
158 mImeAdapter.disableImeThread();
159 mImeAdapter.resetInputConnectionFactory();
160 mInputMethodManagerWrapper.restartInput(view);
161 }
162
163 @Override
164 public Handler getHandler() {
165 return mHandler;
166 }
167 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698