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

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: removed ImeTest#testDoesNotHang_rendererCrashes which does not test anything 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.Log;
13 import org.chromium.base.VisibleForTesting;
14
15 /**
16 * A factory class for {@link ThreadedInputConnection}. The class also includes triggering
17 * mechanism (hack) to run our InputConnection on non-UI thread.
18 */
19 // TODO(changwan): add unit tests once Robolectric supports Android API level >= 21.
20 // See crbug.com/588547 for details.
21 public class ThreadedInputConnectionFactory implements ChromiumBaseInputConnecti on.Factory {
22 private static final String TAG = "cr_Ime";
23 private static final boolean DEBUG_LOGS = false;
24
25 private final Handler mHandler;
26 private final InputMethodManagerWrapper mInputMethodManagerWrapper;
27 private final InputMethodUma mInputMethodUma;
28 private ThreadedInputConnectionProxyView mProxyView;
29 private ThreadedInputConnection mThreadedInputConnection;
30
31 ThreadedInputConnectionFactory(
32 InputMethodManagerWrapper inputMethodManagerWrapper) {
33 mInputMethodManagerWrapper = inputMethodManagerWrapper;
34 mHandler = createHandler();
35 mInputMethodUma = createInputMethodUma();
36 }
37
38 @VisibleForTesting
39 protected Handler createHandler() {
40 HandlerThread thread =
41 new HandlerThread("InputConnectionHandlerThread", HandlerThread. NORM_PRIORITY);
42 thread.start();
43 return new Handler(thread.getLooper());
44 }
45
46 @VisibleForTesting
47 protected ThreadedInputConnectionProxyView createProxyView(
48 Handler handler, View containerView) {
49 return new ThreadedInputConnectionProxyView(
50 containerView.getContext(), handler, containerView);
51 }
52
53 @VisibleForTesting
54 protected InputMethodUma createInputMethodUma() {
55 return new InputMethodUma();
56 }
57
58 private boolean shouldTriggerDelayedOnCreateInputConnection() {
59 // Note that ThreadedInputConnectionProxyView intentionally calls
60 // View#onCreateInputConnection() and not a separate method in this clas s.
61 // There are third party apps that override WebView#onCreateInputConnect ion(),
62 // and we still want to call them for consistency. The setback here is t hat the only
63 // way to distinguish calls from InputMethodManager and from ProxyView i s by looking at
64 // the call stack.
65 for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
66 String className = ste.getClassName();
67 if (className != null
68 && (className.contains(ThreadedInputConnectionProxyView.clas s.getName())
69 || className.contains("TestInputMethodManagerWrapper"))) {
70 return false;
71 }
72 }
73 return true;
74 }
75
76 @Override
77 public ThreadedInputConnection initializeAndGet(
78 View view, ImeAdapter imeAdapter, int inputType, int inputFlags, int selectionStart,
79 int selectionEnd, EditorInfo outAttrs) {
80 ImeUtils.checkOnUiThread();
81 if (shouldTriggerDelayedOnCreateInputConnection()) {
82 triggerDelayedOnCreateInputConnection(view);
83 return null;
84 }
85 if (DEBUG_LOGS) Log.w(TAG, "initializeAndGet: called from proxy view");
86 if (mThreadedInputConnection == null) {
87 if (DEBUG_LOGS) Log.w(TAG, "Creating ThreadedInputConnection...");
88 mThreadedInputConnection = new ThreadedInputConnection(imeAdapter, m Handler);
89 }
90 mThreadedInputConnection.initializeOutAttrsOnUiThread(inputType, inputFl ags,
91 selectionStart, selectionEnd, outAttrs);
92 return mThreadedInputConnection;
93 }
94
95 private void triggerDelayedOnCreateInputConnection(final View view) {
96 if (DEBUG_LOGS) Log.w(TAG, "triggerDelayedOnCreateInputConnection");
97 if (mProxyView == null) {
98 mProxyView = createProxyView(mHandler, view);
99 }
100 mProxyView.requestFocus();
101 view.getHandler().post(new Runnable() {
102 @Override
103 public void run() {
104 // This is a hack to make InputMethodManager believe that the pr oxy view
105 // now has a focus. As a result, InputMethodManager will think t hat mProxyView
106 // is focused, and will call getHandler() of the view when creat ing input
107 // connection.
108
109 // Step 1: Set mProxyView as InputMethodManager#mNextServedView.
110 mProxyView.onWindowFocusChanged(true);
111
112 // Step 2: Have InputMethodManager focus in on mNextServedView.
113 // As a result, IMM will call onCreateInputConnection() on mProx yView on the same
114 // thread as mProxyView.getHandler(). It will also call subseque nt InputConnection
115 // methods on this IME thread.
116 mInputMethodManagerWrapper.isActive(view);
117
118 // Step 3: Check that the above hack worked.
119 mHandler.post(new Runnable() {
120 @Override
121 public void run() {
122 // Some other view already took focus. Container view sh ould be active
123 // otherwise regardless of whether proxy view is registe red or not.
124 if (!mInputMethodManagerWrapper.isActive(view)) return;
125
126 // Success.
127 if (mInputMethodManagerWrapper.isActive(mProxyView)) {
128 mInputMethodUma.recordProxyViewSuccess();
129 return;
130 }
131
132 if (mThreadedInputConnection == null) {
133 // First time and failed. It is highly likely that t his does not work
134 // systematically.
135 mInputMethodUma.recordProxyViewFailure();
136 onRegisterProxyViewFailed();
137 } else {
138 // Most likely that we already lost view focus.
139 mInputMethodUma.recordProxyViewDetectionFailure();
140 }
141 }
142 });
143 }
144 });
145 }
146
147 @VisibleForTesting
148 protected void onRegisterProxyViewFailed() {
149 throw new AssertionError("Failed to register proxy view");
150 }
151
152 @Override
153 public Handler getHandler() {
154 return mHandler;
155 }
156 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698