OLD | NEW |
---|---|
(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.metrics.RecordHistogram; | |
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 public class ThreadedInputConnectionFactory implements ChromiumBaseInputConnecti on.Factory { | |
23 private static final String TAG = "cr_Ime"; | |
24 private static final boolean DEBUG_LOGS = true; | |
Ted C
2016/02/19 18:26:17
don't forget to set this to false before committin
Changwan Ryu
2016/02/22 06:28:24
Done.
| |
25 | |
26 private final Handler mHandler; | |
27 private final InputMethodManagerWrapper mInputMethodManagerWrapper; | |
28 private final ImeAdapter mImeAdapter; | |
29 private ThreadedInputConnectionProxyView mProxyView; | |
30 private ThreadedInputConnection mThreadedInputConnection; | |
31 | |
32 ThreadedInputConnectionFactory( | |
33 InputMethodManagerWrapper inputMethodManagerWrapper, ImeAdapter imeA dapter) { | |
34 mImeAdapter = imeAdapter; | |
35 HandlerThread thread = | |
36 new HandlerThread("InputConnectionHandlerThread", HandlerThread. NORM_PRIORITY); | |
37 thread.start(); | |
38 mHandler = new Handler(thread.getLooper()); | |
39 mInputMethodManagerWrapper = inputMethodManagerWrapper; | |
40 } | |
41 | |
42 private boolean shouldTriggerDelayedOnCreateInputConnection() { | |
43 for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { | |
44 String className = ste.getClassName(); | |
45 if (className != null | |
46 && (className.contains(ThreadedInputConnectionProxyView.clas s.getName()) | |
47 || className.contains("TestInputMethodManagerWrapper"))) { | |
48 return false; | |
49 } | |
50 } | |
51 return true; | |
52 } | |
53 | |
54 @Override | |
55 public ChromiumBaseInputConnection initializeAndGet( | |
56 View view, ImeAdapter imeAdapter, int inputType, int inputFlags, int selectionStart, | |
57 int selectionEnd, EditorInfo outAttrs) { | |
58 ImeUtils.checkOnUiThread(); | |
59 if (shouldTriggerDelayedOnCreateInputConnection()) { | |
60 triggerDelayedOnCreateInputConnection(view); | |
61 return null; | |
62 } | |
63 if (DEBUG_LOGS) Log.w(TAG, "initializeAndGet: called from proxy view"); | |
64 if (mThreadedInputConnection == null) { | |
65 if (DEBUG_LOGS) Log.w(TAG, "Creating ThreadedInputConnection..."); | |
66 mThreadedInputConnection = new ThreadedInputConnection(imeAdapter, m Handler); | |
67 } | |
68 mThreadedInputConnection.initializeOutAttrsOnUiThread(inputType, inputFl ags, | |
69 selectionStart, selectionEnd, outAttrs); | |
70 return mThreadedInputConnection; | |
71 } | |
72 | |
73 private void triggerDelayedOnCreateInputConnection(final View view) { | |
74 if (DEBUG_LOGS) Log.w(TAG, "triggerDelayedOnCreateInputConnection"); | |
75 if (mProxyView == null) { | |
76 mProxyView = new ThreadedInputConnectionProxyView(view.getContext(), mHandler, view); | |
77 } | |
78 mProxyView.requestFocus(); | |
79 view.getHandler().post(new Runnable() { | |
80 @Override | |
81 public void run() { | |
82 // This is a hack to make InputMethodManager believe that the pr oxy view | |
83 // now has a focus. As a result, InputMethodManager will think t hat mProxyView | |
84 // is focused, and will call getHandler() of the view when creat ing input | |
85 // connection. | |
86 | |
87 // Step 1: Set mProxyView as InputMethodManager#mNextServedView. | |
88 // mProxyView.onWindowFocusChanged(true); | |
89 | |
90 // Step 2: Have InputMethodManager focus in on mNextServedView. | |
91 // As a result, IMM will call onCreateInputConnection() on mProx yView on the same | |
92 // thread as mProxyView.getHandler(). It will also call subseque nt InputConnection | |
93 // methods on this IME thread. | |
94 mInputMethodManagerWrapper.isActive(view); | |
95 | |
96 // Step 3: Check that the above hack worked. | |
97 mHandler.post(new Runnable() { | |
98 @Override | |
99 public void run() { | |
100 // Some other view already took focus. Container view sh ould be active | |
101 // otherwise regardless of whether proxy view is registe red or not. | |
102 if (!mInputMethodManagerWrapper.isActive(view)) return; | |
103 | |
104 // Success. | |
105 if (mInputMethodManagerWrapper.isActive(mProxyView)) { | |
106 RecordHistogram.recordEnumeratedHistogram( | |
107 InputMethodUma.UMA_REGISTER_PROXYVIEW, | |
108 InputMethodUma.UMA_PROXYVIEW_SUCCESS, | |
109 InputMethodUma.UMA_PROXYVIEW_COUNT); | |
110 return; | |
111 } | |
112 | |
113 if (mThreadedInputConnection == null) { | |
114 // First time and failed. It is highly likely that t his does not work | |
115 // systematically. | |
116 onProxyViewFailedToRegisterOnFirstTry(view); | |
117 } else { | |
118 // Most likely that we already lost view focus. | |
119 RecordHistogram.recordEnumeratedHistogram( | |
120 InputMethodUma.UMA_REGISTER_PROXYVIEW, | |
121 InputMethodUma.UMA_PROXYVIEW_DETECTION_FAILU RE, | |
122 InputMethodUma.UMA_PROXYVIEW_COUNT); | |
123 } | |
124 } | |
125 }); | |
126 } | |
127 }); | |
128 } | |
129 | |
130 private void onProxyViewFailedToRegisterOnFirstTry(final View view) { | |
Ted C
2016/02/19 18:26:17
would it be possible add a test for this (i.e. the
Changwan Ryu
2016/02/22 06:28:24
Hmm.. We're not using real InputMethodManager in t
| |
131 Log.w(TAG, "Failed to register proxy view. Falling back to ReplicaInputC onnection..."); | |
132 ThreadUtils.postOnUiThread(new Runnable() { | |
133 @Override | |
134 public void run() { | |
135 RecordHistogram.recordEnumeratedHistogram(InputMethodUma.UMA_REG ISTER_PROXYVIEW, | |
136 InputMethodUma.UMA_PROXYVIEW_FAILURE, InputMethodUma.UMA _PROXYVIEW_COUNT); | |
137 // Disable IME thread until Chrome gets closed. Note that this i s not a permanent | |
138 // change. | |
Ted C
2016/02/19 18:26:18
what about it isn't permanent? are you clearing t
Changwan Ryu
2016/02/19 22:17:11
I just wanted to comment that switch enabled by ap
| |
139 CommandLine.getInstance().appendSwitch(ContentSwitches.DISABLE_I ME_THREAD); | |
140 mImeAdapter.resetInputConnectionFactory(); | |
141 mInputMethodManagerWrapper.restartInput(view); | |
142 } | |
143 | |
144 }); | |
145 } | |
146 | |
147 @Override | |
148 public Handler getHandler() { | |
149 return mHandler; | |
150 } | |
151 } | |
OLD | NEW |