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

Unified Diff: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java

Issue 2803203003: Revert of Migrate IME state update flow (Closed)
Patch Set: Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
index 55746b956cbb1d2904fb20f3a6a9328116e619ed..8de6adea10a9918720e32d561705eb96d057134d 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -4,12 +4,8 @@
package org.chromium.content.browser.input;
-import android.annotation.SuppressLint;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.text.SpannableString;
@@ -23,10 +19,8 @@
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputMethodManager;
import org.chromium.base.Log;
-import org.chromium.base.TraceEvent;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
@@ -34,15 +28,9 @@
import org.chromium.blink_public.web.WebInputEventType;
import org.chromium.blink_public.web.WebTextInputMode;
import org.chromium.content.browser.RenderCoordinates;
-import org.chromium.content.browser.ViewUtils;
import org.chromium.content.browser.picker.InputDialogContainer;
-import org.chromium.content_public.browser.ImeEventObserver;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ime.TextInputType;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
/**
* Adapts and plumbs android IME service onto the chrome text input API.
@@ -72,6 +60,36 @@
public static final int COMPOSITION_KEY_CODE = 229;
+ /**
+ * Interface for the delegate that needs to be notified of IME changes.
+ */
+ public interface ImeAdapterDelegate {
+ /**
+ * Called to notify the delegate about synthetic/real key events before sending to renderer.
+ */
+ void onImeEvent();
+
+ /**
+ * Called when the keyboard could not be shown due to the hardware keyboard being present.
+ */
+ void onKeyboardBoundsUnchanged();
+
+ /**
+ * @see BaseInputConnection#performContextMenuAction(int)
+ */
+ boolean performContextMenuAction(int id);
+
+ /**
+ * @return View that the keyboard should be attached to.
+ */
+ View getAttachedView();
+
+ /**
+ * @return Object that should be called for all keyboard show and hide requests.
+ */
+ ResultReceiver getNewShowKeyboardReceiver();
+ }
+
static char[] sSingleCharArray = new char[1];
static KeyCharacterMap sKeyCharacterMap;
@@ -80,29 +98,16 @@
private ChromiumBaseInputConnection mInputConnection;
private ChromiumBaseInputConnection.Factory mInputConnectionFactory;
- // NOTE: This object will not be released by Android framework until the matching
- // ResultReceiver in the InputMethodService (IME app) gets gc'ed.
- private ShowKeyboardResultReceiver mShowKeyboardResultReceiver;
-
- private final WebContents mWebContents;
- private View mContainerView;
-
+ private final ImeAdapterDelegate mViewEmbedder;
// This holds the information necessary for constructing CursorAnchorInfo, and notifies to
// InputMethodManager on appropriate timing, depending on how IME requested the information
// via InputConnection. The update request is per InputConnection, hence for each time it is
// re-created, the monitoring status will be reset.
private final CursorAnchorInfoController mCursorAnchorInfoController;
- private final List<ImeEventObserver> mEventObservers = new ArrayList<>();
-
private int mTextInputType = TextInputType.NONE;
private int mTextInputFlags;
private int mTextInputMode = WebTextInputMode.kDefault;
- private boolean mNodeEditable;
-
- // Viewport rect before the OSK was brought up.
- // Used to tell View#onSizeChanged to focus a form element.
- private final Rect mFocusPreOSKViewportRect = new Rect();
// Keep the current configuration to detect the change when onConfigurationChanged() is called.
private Configuration mCurrentConfig;
@@ -118,45 +123,18 @@
private boolean mIsConnected;
/**
- * {@ResultReceiver} passed in InputMethodManager#showSoftInput}. We need this to scroll to the
- * editable node at the right timing, which is after input method window shows up.
- */
- // TODO(crbug.com/635567): Fix this properly.
- @SuppressLint("ParcelCreator")
- private static class ShowKeyboardResultReceiver extends ResultReceiver {
- // Unfortunately, the memory life cycle of ResultReceiver object, once passed in
- // showSoftInput(), is in the control of Android's input method framework and IME app,
- // so we use a weakref to avoid tying ImeAdapter's lifetime to that of ResultReceiver
- // object.
- private final WeakReference<ImeAdapter> mImeAdapter;
-
- public ShowKeyboardResultReceiver(ImeAdapter imeAdapter, Handler handler) {
- super(handler);
- mImeAdapter = new WeakReference<>(imeAdapter);
- }
-
- @Override
- public void onReceiveResult(int resultCode, Bundle resultData) {
- ImeAdapter imeAdapter = mImeAdapter.get();
- if (imeAdapter == null) return;
- imeAdapter.onShowKeyboardReceiveResult(resultCode);
- }
- }
-
- /**
+ * @param initialConfiguration The initial configuration of the embedder's attached view.
* @param webContents WebContents instance with which this ImeAdapter is associated.
- * @param containerView {@link View} instance which input events are posted on.
* @param wrapper InputMethodManagerWrapper that should receive all the call directed to
* InputMethodManager.
- */
- public ImeAdapter(
- WebContents webContents, View containerView, InputMethodManagerWrapper wrapper) {
- mWebContents = webContents;
- mContainerView = containerView;
+ * @param embedder The view that is used for callbacks from ImeAdapter.
+ */
+ public ImeAdapter(Configuration initialConfiguration, WebContents webContents,
+ InputMethodManagerWrapper wrapper, ImeAdapterDelegate embedder) {
mInputMethodManagerWrapper = wrapper;
-
+ mViewEmbedder = embedder;
// Deep copy newConfig so that we can notice the difference.
- mCurrentConfig = new Configuration(mContainerView.getResources().getConfiguration());
+ mCurrentConfig = new Configuration(initialConfiguration);
// CursorAnchroInfo is supported only after L.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mCursorAnchorInfoController = CursorAnchorInfoController.create(wrapper,
@@ -188,18 +166,6 @@
mNativeImeAdapterAndroid = nativeInit(webContents);
}
- /**
- * Set the container view.
- * @param containerView {@link View} which this ImeAdapter works on.
- */
- public void setContainerView(View containerView) {
- mContainerView = containerView;
- }
-
- public void addEventObserver(ImeEventObserver eventObserver) {
- mEventObservers.add(eventObserver);
- }
-
private void createInputConnectionFactory() {
if (mInputConnectionFactory != null) return;
mInputConnectionFactory = new ThreadedInputConnectionFactory(mInputMethodManagerWrapper);
@@ -228,14 +194,15 @@
return null;
}
if (mInputConnectionFactory == null) return null;
- setInputConnection(mInputConnectionFactory.initializeAndGet(mContainerView, this,
- mTextInputType, mTextInputFlags, mTextInputMode, mLastSelectionStart,
+ setInputConnection(mInputConnectionFactory.initializeAndGet(mViewEmbedder.getAttachedView(),
+ this, mTextInputType, mTextInputFlags, mTextInputMode, mLastSelectionStart,
mLastSelectionEnd, outAttrs));
if (DEBUG_LOGS) Log.i(TAG, "onCreateInputConnection: " + mInputConnection);
if (mCursorAnchorInfoController != null) {
- mCursorAnchorInfoController.onRequestCursorUpdates(false /* not an immediate request */,
- false /* disable monitoring */, mContainerView);
+ mCursorAnchorInfoController.onRequestCursorUpdates(
+ false /* not an immediate request */, false /* disable monitoring */,
+ mViewEmbedder.getAttachedView());
}
if (isValid()) {
nativeRequestCursorUpdate(mNativeImeAdapterAndroid,
@@ -321,71 +288,54 @@
* selection.
* @param replyToRequest True when the update was requested by IME.
*/
- @CalledByNative
- private void updateState(int textInputType, int textInputFlags, int textInputMode,
+ public void updateState(int textInputType, int textInputFlags, int textInputMode,
boolean showIfNeeded, String text, int selectionStart, int selectionEnd,
int compositionStart, int compositionEnd, boolean replyToRequest) {
- TraceEvent.begin("ImeAdapter.updateState");
- try {
- if (DEBUG_LOGS) {
- Log.i(TAG, "updateState: type [%d->%d], flags [%d], show [%b], ", mTextInputType,
- textInputType, textInputFlags, showIfNeeded);
- }
- boolean needsRestart = false;
- if (mRestartInputOnNextStateUpdate) {
- needsRestart = true;
- mRestartInputOnNextStateUpdate = false;
- }
-
- mTextInputFlags = textInputFlags;
- if (mTextInputMode != textInputMode) {
- boolean editable = textInputMode != TextInputType.NONE;
- if (mNodeEditable != editable) {
- boolean password = textInputType == TextInputType.PASSWORD;
- for (ImeEventObserver observer : mEventObservers) {
- observer.onNodeAttributeUpdated(editable, password);
- }
- mNodeEditable = editable;
- }
- mTextInputMode = textInputMode;
- needsRestart = true;
- }
- if (mTextInputType != textInputType) {
- mTextInputType = textInputType;
- needsRestart = true;
- }
- if (mCursorAnchorInfoController != null
- && (!TextUtils.equals(mLastText, text) || mLastSelectionStart != selectionStart
- || mLastSelectionEnd != selectionEnd
- || mLastCompositionStart != compositionStart
- || mLastCompositionEnd != compositionEnd)) {
- mCursorAnchorInfoController.invalidateLastCursorAnchorInfo();
- }
- mLastText = text;
- mLastSelectionStart = selectionStart;
- mLastSelectionEnd = selectionEnd;
- mLastCompositionStart = compositionStart;
- mLastCompositionEnd = compositionEnd;
-
- if (textInputType == TextInputType.NONE) {
- hideKeyboard();
- } else {
- if (needsRestart) restartInput();
- // There is no API for us to get notified of user's dismissal of keyboard.
- // Therefore, we should try to show keyboard even when text input type hasn't
- // changed.
- if (showIfNeeded) showSoftKeyboard();
- }
-
- if (mInputConnection != null) {
- boolean singleLine = mTextInputType != TextInputType.TEXT_AREA
- && mTextInputType != TextInputType.CONTENT_EDITABLE;
- mInputConnection.updateStateOnUiThread(text, selectionStart, selectionEnd,
- compositionStart, compositionEnd, singleLine, replyToRequest);
- }
- } finally {
- TraceEvent.end("ImeAdapter.updateState");
- }
+ if (DEBUG_LOGS) {
+ Log.i(TAG, "updateState: type [%d->%d], flags [%d], show [%b], ", mTextInputType,
+ textInputType, textInputFlags, showIfNeeded);
+ }
+ boolean needsRestart = false;
+ if (mRestartInputOnNextStateUpdate) {
+ needsRestart = true;
+ mRestartInputOnNextStateUpdate = false;
+ }
+
+ mTextInputFlags = textInputFlags;
+ if (mTextInputMode != textInputMode) {
+ mTextInputMode = textInputMode;
+ needsRestart = true;
+ }
+ if (mTextInputType != textInputType) {
+ mTextInputType = textInputType;
+ needsRestart = true;
+ }
+ if (mCursorAnchorInfoController != null && (!TextUtils.equals(mLastText, text)
+ || mLastSelectionStart != selectionStart || mLastSelectionEnd != selectionEnd
+ || mLastCompositionStart != compositionStart
+ || mLastCompositionEnd != compositionEnd)) {
+ mCursorAnchorInfoController.invalidateLastCursorAnchorInfo();
+ }
+ mLastText = text;
+ mLastSelectionStart = selectionStart;
+ mLastSelectionEnd = selectionEnd;
+ mLastCompositionStart = compositionStart;
+ mLastCompositionEnd = compositionEnd;
+
+ if (textInputType == TextInputType.NONE) {
+ hideKeyboard();
+ } else {
+ if (needsRestart) restartInput();
+ // There is no API for us to get notified of user's dismissal of keyboard.
+ // Therefore, we should try to show keyboard even when text input type hasn't changed.
+ if (showIfNeeded) showSoftKeyboard();
+ }
+
+ if (mInputConnection == null) return;
+ boolean singleLine = mTextInputType != TextInputType.TEXT_AREA
+ && mTextInputType != TextInputType.CONTENT_EDITABLE;
+ mInputConnection.updateStateOnUiThread(text, selectionStart, selectionEnd, compositionStart,
+ compositionEnd, singleLine, replyToRequest);
}
/**
@@ -393,43 +343,12 @@
*/
private void showSoftKeyboard() {
if (DEBUG_LOGS) Log.i(TAG, "showSoftKeyboard");
- mInputMethodManagerWrapper.showSoftInput(mContainerView, 0, getNewShowKeyboardReceiver());
- if (mContainerView.getResources().getConfiguration().keyboard
+ mInputMethodManagerWrapper.showSoftInput(
+ mViewEmbedder.getAttachedView(), 0, mViewEmbedder.getNewShowKeyboardReceiver());
+ if (mViewEmbedder.getAttachedView().getResources().getConfiguration().keyboard
!= Configuration.KEYBOARD_NOKEYS) {
- mWebContents.scrollFocusedEditableNodeIntoView();
- }
- }
-
- /**
- * Call this when we get result from ResultReceiver passed in calling showSoftInput().
- * @param resultCode The result of showSoftInput() as defined in InputMethodManager.
- */
- public void onShowKeyboardReceiveResult(int resultCode) {
- if (resultCode == InputMethodManager.RESULT_SHOWN) {
- // If OSK is newly shown, delay the form focus until
- // the onSizeChanged (in order to adjust relative to the
- // new size).
- // TODO(jdduke): We should not assume that onSizeChanged will
- // always be called, crbug.com/294908.
- mContainerView.getWindowVisibleDisplayFrame(mFocusPreOSKViewportRect);
- } else if (ViewUtils.hasFocus(mContainerView)
- && resultCode == InputMethodManager.RESULT_UNCHANGED_SHOWN) {
- // If the OSK was already there, focus the form immediately.
- mWebContents.scrollFocusedEditableNodeIntoView();
- }
- }
-
- public Rect getFocusPreOSKViewportRect() {
- return mFocusPreOSKViewportRect;
- }
-
- @VisibleForTesting
- public ResultReceiver getNewShowKeyboardReceiver() {
- if (mShowKeyboardResultReceiver == null) {
- // Note: the returned object will get leaked by Android framework.
- mShowKeyboardResultReceiver = new ShowKeyboardResultReceiver(this, new Handler());
- }
- return mShowKeyboardResultReceiver;
+ mViewEmbedder.onKeyboardBoundsUnchanged();
+ }
}
/**
@@ -437,7 +356,7 @@
*/
private void hideKeyboard() {
if (DEBUG_LOGS) Log.i(TAG, "hideKeyboard");
- View view = mContainerView;
+ View view = mViewEmbedder.getAttachedView();
if (mInputMethodManagerWrapper.isActive(view)) {
// NOTE: we should not set ResultReceiver here. Otherwise, IMM will own ContentViewCore
// and ImeAdapter even after input method goes away and result gets received.
@@ -579,8 +498,8 @@
*/
void updateSelection(
int selectionStart, int selectionEnd, int compositionStart, int compositionEnd) {
- mInputMethodManagerWrapper.updateSelection(
- mContainerView, selectionStart, selectionEnd, compositionStart, compositionEnd);
+ mInputMethodManagerWrapper.updateSelection(mViewEmbedder.getAttachedView(),
+ selectionStart, selectionEnd, compositionStart, compositionEnd);
}
/**
@@ -588,7 +507,7 @@
*/
void restartInput() {
// This will eventually cause input method manager to call View#onCreateInputConnection().
- mInputMethodManagerWrapper.restartInput(mContainerView);
+ mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView());
if (mInputConnection != null) mInputConnection.onRestartInputOnUiThread();
}
@@ -597,22 +516,7 @@
*/
boolean performContextMenuAction(int id) {
if (DEBUG_LOGS) Log.i(TAG, "performContextMenuAction: id [%d]", id);
- switch (id) {
- case android.R.id.selectAll:
- mWebContents.selectAll();
- return true;
- case android.R.id.cut:
- mWebContents.cut();
- return true;
- case android.R.id.copy:
- mWebContents.copy();
- return true;
- case android.R.id.paste:
- mWebContents.paste();
- return true;
- default:
- return false;
- }
+ return mViewEmbedder.performContextMenuAction(id);
}
boolean performEditorAction(int actionCode) {
@@ -646,11 +550,6 @@
flags));
}
- private void onImeEvent() {
- for (ImeEventObserver observer : mEventObservers) observer.onImeEvent();
- if (mNodeEditable) mWebContents.dismissTextHandles();
- }
-
boolean sendCompositionToNative(
CharSequence text, int newCursorPosition, boolean isCommit, int unicodeFromKeyEvent) {
if (!isValid()) return false;
@@ -662,7 +561,7 @@
return true;
}
- onImeEvent();
+ mViewEmbedder.onImeEvent();
long timestampMs = SystemClock.uptimeMillis();
nativeSendKeyEvent(mNativeImeAdapterAndroid, null, WebInputEventType.RawKeyDown, 0,
timestampMs, COMPOSITION_KEY_CODE, 0, false, unicodeFromKeyEvent);
@@ -702,7 +601,7 @@
// sends ACTION_DOWN), so it's fine to silently drop it.
return false;
}
- onImeEvent();
+ mViewEmbedder.onImeEvent();
return nativeSendKeyEvent(mNativeImeAdapterAndroid, event, type,
getModifiers(event.getMetaState()), event.getEventTime(), event.getKeyCode(),
@@ -718,7 +617,7 @@
* @return Whether the native counterpart of ImeAdapter received the call.
*/
boolean deleteSurroundingText(int beforeLength, int afterLength) {
- onImeEvent();
+ mViewEmbedder.onImeEvent();
if (!isValid()) return false;
nativeSendKeyEvent(mNativeImeAdapterAndroid, null, WebInputEventType.RawKeyDown, 0,
SystemClock.uptimeMillis(), COMPOSITION_KEY_CODE, 0, false, 0);
@@ -737,7 +636,7 @@
* @return Whether the native counterpart of ImeAdapter received the call.
*/
boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
- onImeEvent();
+ mViewEmbedder.onImeEvent();
if (!isValid()) return false;
nativeSendKeyEvent(mNativeImeAdapterAndroid, null, WebInputEventType.RawKeyDown, 0,
SystemClock.uptimeMillis(), COMPOSITION_KEY_CODE, 0, false, 0);
@@ -813,8 +712,8 @@
nativeRequestCursorUpdate(mNativeImeAdapterAndroid, immediateRequest, monitorRequest);
}
if (mCursorAnchorInfoController == null) return false;
- return mCursorAnchorInfoController.onRequestCursorUpdates(
- immediateRequest, monitorRequest, mContainerView);
+ return mCursorAnchorInfoController.onRequestCursorUpdates(immediateRequest, monitorRequest,
+ mViewEmbedder.getAttachedView());
}
/**
@@ -835,7 +734,7 @@
if (mCursorAnchorInfoController == null) return;
mCursorAnchorInfoController.onUpdateFrameInfo(renderCoordinates, hasInsertionMarker,
isInsertionMarkerVisible, insertionMarkerHorizontal, insertionMarkerTop,
- insertionMarkerBottom, mContainerView);
+ insertionMarkerBottom, mViewEmbedder.getAttachedView());
}
@CalledByNative
@@ -869,7 +768,8 @@
@CalledByNative
private void setCharacterBounds(float[] characterBounds) {
if (mCursorAnchorInfoController == null) return;
- mCursorAnchorInfoController.setCompositionCharacterBounds(characterBounds, mContainerView);
+ mCursorAnchorInfoController.setCompositionCharacterBounds(characterBounds,
+ mViewEmbedder.getAttachedView());
}
@CalledByNative

Powered by Google App Engine
This is Rietveld 408576698