summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/android/findbugs_filter/findbugs_known_bugs.txt2
-rw-r--r--chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java (renamed from chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java)20
-rw-r--r--chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java (renamed from chrome/android/javatests/src/org/chromium/chrome/browser/test/SelectPopupOtherContentViewTest.java)4
-rw-r--r--content/content_jni.gypi4
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java35
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java858
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java410
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/CursorController.java (renamed from content/public/android/java/src/org/chromium/content/browser/CursorController.java)2
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java (renamed from content/public/android/java/src/org/chromium/content/browser/DateTimeChooserAndroid.java)3
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/DateTimePickerDialog.java (renamed from content/public/android/java/src/org/chromium/content/browser/DateTimePickerDialog.java)2
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/HandleView.java (renamed from content/public/android/java/src/org/chromium/content/browser/HandleView.java)13
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java572
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java (renamed from content/public/android/java/src/org/chromium/content/browser/InputDialogContainer.java)8
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/InputMethodManagerWrapper.java (renamed from content/public/android/java/src/org/chromium/content/browser/InputMethodManagerWrapper.java)4
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/InsertionHandleController.java (renamed from content/public/android/java/src/org/chromium/content/browser/InsertionHandleController.java)29
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/MonthPicker.java (renamed from content/public/android/java/src/org/chromium/content/browser/MonthPicker.java)2
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/MonthPickerDialog.java (renamed from content/public/android/java/src/org/chromium/content/browser/MonthPickerDialog.java)4
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java (renamed from content/public/android/java/src/org/chromium/content/browser/SelectPopupDialog.java)8
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/input/SelectionHandleController.java (renamed from content/public/android/java/src/org/chromium/content/browser/SelectionHandleController.java)47
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java (renamed from content/public/android/javatests/src/org/chromium/content/browser/ImeTest.java)11
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java (renamed from content/public/android/javatests/src/org/chromium/content/browser/InsertionHandleTest.java)4
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java (renamed from content/public/android/javatests/src/org/chromium/content/browser/SelectPopupTest.java)3
22 files changed, 1066 insertions, 979 deletions
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index 61fc567..cb37ca2 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -25,11 +25,9 @@ M C RCN: Nullcheck of GestureDetector.mVelocityTracker at line 630 of value prev
M C USELESS_STRING: Invocation of toString on certChain in org.chromium.net.X509Util.verifyServerCertificates(byte[][], String) At X509Util.java
M D DMI: Hard coded reference to an absolute pathname in org.chromium.android_webview.test.ArchiveTest.testAutoBadPath() At ArchiveTest.java
M D DMI: Hard coded reference to an absolute pathname in org.chromium.android_webview.test.ArchiveTest.testExplicitBadPath() At ArchiveTest.java
-M D ICAST: integral division result cast to double or float in org.chromium.content.browser.HandleView.setOrientation(int) At HandleView.java
M D SF: Switch statement found in org.chromium.chrome.browser.ChromeBrowserProvider.insert(Uri, ContentValues) where one case falls through to the next case At ChromeBrowserProvider.java
M D SF: Switch statement found in org.chromium.chrome.browser.database.SQLiteCursor.fillWindow(int, CursorWindow) where default case is missing At SQLiteCursor.java
M D SF: Switch statement found in org.chromium.content.browser.ContentSettings$EventHandler$1.handleMessage(Message) where default case is missing At ContentSettings.java
-M D SF: Switch statement found in org.chromium.content.browser.HandleView.onTouchEvent(MotionEvent) where default case is missing At HandleView.java
M D SF: Switch statement found in org.chromium.content.browser.third_party.GestureDetector.onTouchEvent(MotionEvent) where default case is missing At GestureDetector.java
M D ST: Write to static field org.chromium.content.browser.ContentSettings.sAppCachePathIsSet from instance method org.chromium.content.browser.ContentSettings.setAppCachePath(String) At ContentSettings.java
M M LI: Incorrect lazy initialization and update of static field org.chromium.content.browser.ContentVideoView.sContentVideoView in org.chromium.content.browser.ContentVideoView.createContentVideoView(int) At ContentVideoView.java
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java
index 47bdbe0..54d15d3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/AutofillTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTest.java
@@ -2,33 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.chrome.browser.test;
-
-import android.app.Activity;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.IsolatedContext;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.MediumTest;
+package org.chromium.chrome.browser.autofill;
+
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Pair;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.browser.ChromeBrowserProvider;
-import org.chromium.chrome.browser.autofill.AutofillListAdapter;
import org.chromium.chrome.browser.autofill.AutofillPopup;
import org.chromium.chrome.browser.autofill.AutofillPopup.AutofillPopupDelegate;
import org.chromium.chrome.browser.autofill.AutofillSuggestion;
import org.chromium.chrome.testshell.ChromiumTestShellActivity;
import org.chromium.chrome.testshell.ChromiumTestShellTestBase;
import org.chromium.content.browser.ContainerViewDelegate;
-import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.test.util.TouchCommon;
import org.chromium.content.browser.test.util.UiUtils;
import org.chromium.content.browser.test.util.Criteria;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/test/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index ce4a7a5..d09c682 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/test/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.chrome.browser.input;
import android.test.suitebuilder.annotation.LargeTest;
@@ -10,7 +10,7 @@ import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.content.browser.ContentView;
-import org.chromium.content.browser.SelectPopupDialog;
+import org.chromium.content.browser.input.SelectPopupDialog;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.DOMUtils;
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index 3116c04..b52eaa3 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -18,10 +18,10 @@
'public/android/java/src/org/chromium/content/browser/ContentViewCore.java',
'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java',
'public/android/java/src/org/chromium/content/browser/ContentViewStatics.java',
- 'public/android/java/src/org/chromium/content/browser/DateTimeChooserAndroid.java',
'public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java',
'public/android/java/src/org/chromium/content/browser/DownloadController.java',
- 'public/android/java/src/org/chromium/content/browser/ImeAdapter.java',
+ 'public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java',
+ 'public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java',
'public/android/java/src/org/chromium/content/browser/InterstitialPageDelegateAndroid.java',
'public/android/java/src/org/chromium/content/browser/LoadUrlParams.java',
'public/android/java/src/org/chromium/content/browser/LocationProvider.java',
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 9b8cde6..6d44e04 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -42,8 +42,14 @@ import org.chromium.base.JNINamespace;
import org.chromium.base.WeakContext;
import org.chromium.content.R;
import org.chromium.content.browser.ContentViewGestureHandler.MotionEventDelegate;
-import org.chromium.content.browser.ImeAdapter.AdapterInputConnectionFactory;
import org.chromium.content.browser.accessibility.AccessibilityInjector;
+import org.chromium.content.browser.input.AdapterInputConnection;
+import org.chromium.content.browser.input.HandleView;
+import org.chromium.content.browser.input.ImeAdapter;
+import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory;
+import org.chromium.content.browser.input.InsertionHandleController;
+import org.chromium.content.browser.input.SelectPopupDialog;
+import org.chromium.content.browser.input.SelectionHandleController;
import org.chromium.content.common.TraceEvent;
import org.chromium.ui.gfx.NativeWindow;
@@ -192,7 +198,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
// Only valid when focused on a text / password field.
private ImeAdapter mImeAdapter;
private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory;
- private ImeAdapter.AdapterInputConnection mInputConnection;
+ private AdapterInputConnection mInputConnection;
private SelectionHandleController mSelectionHandleController;
private InsertionHandleController mInsertionHandleController;
@@ -326,17 +332,17 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
}
@VisibleForTesting
- protected ImeAdapter getImeAdapterForTest() {
+ public ImeAdapter getImeAdapterForTest() {
return mImeAdapter;
}
@VisibleForTesting
- protected void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
+ public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
mAdapterInputConnectionFactory = factory;
}
@VisibleForTesting
- protected ImeAdapter.AdapterInputConnection getInputConnectionForTest() {
+ public AdapterInputConnection getInputConnectionForTest() {
return mInputConnection;
}
@@ -1293,8 +1299,9 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore),
- ImeAdapter.sTextInputTypeNone, ImeAdapter.INVALID_SELECTION,
- ImeAdapter.INVALID_SELECTION);
+ ImeAdapter.getTextInputTypeNone(),
+ AdapterInputConnection.INVALID_SELECTION,
+ AdapterInputConnection.INVALID_SELECTION);
InputMethodManager manager = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
manager.restartInput(mContainerView);
@@ -1662,7 +1669,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
return mZoomManager.isMultiTouchZoomSupported();
}
- void selectPopupMenuItems(int[] indices) {
+ public void selectPopupMenuItems(int[] indices) {
if (mNativeContentViewCore != 0) {
nativeSelectPopupMenuItems(mNativeContentViewCore, indices);
}
@@ -2057,11 +2064,7 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
String text, int selectionStart, int selectionEnd,
int compositionStart, int compositionEnd, boolean showImeIfNeeded) {
TraceEvent.begin();
-
- // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces.
- text = text.replace('\u00A0', ' ');
-
- mSelectionEditable = (textInputType != ImeAdapter.sTextInputTypeNone);
+ mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone());
if (mActionMode != null) mActionMode.invalidate();
@@ -2069,12 +2072,6 @@ public class ContentViewCore implements MotionEventDelegate, NavigationClient {
selectionStart, selectionEnd, showImeIfNeeded);
if (mInputConnection != null) {
- // In WebKit if there's a composition then the selection will usually be the
- // same as the composition, whereas Android IMEs expect the selection to be
- // just a caret at the end of the composition.
- if (selectionStart == compositionStart && selectionEnd == compositionEnd) {
- selectionStart = selectionEnd;
- }
mInputConnection.setEditableText(text, selectionStart, selectionEnd,
compositionStart, compositionEnd);
}
diff --git a/content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java
deleted file mode 100644
index 1f73502..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/ImeAdapter.java
+++ /dev/null
@@ -1,858 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.Selection;
-import android.util.Log;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.BaseInputConnection;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import org.chromium.base.CalledByNative;
-import org.chromium.base.JNINamespace;
-
-/**
- * Adapts and plumbs android IME service onto the chrome text input API.
- * ImeAdapter provides an interface in both ways native <-> java:
- * 1. InputConnectionAdapter notifies native code of text composition state and
- * dispatch key events from java -> WebKit.
- * 2. Native ImeAdapter notifies java side to clear composition text.
- *
- * The basic flow is:
- * 1. When InputConnectionAdapter gets called with composition or result text:
- * If we receive a composition text or a result text, then we just need to
- * dispatch a synthetic key event with special keycode 229, and then dispatch
- * the composition or result text.
- * 2. Intercept dispatchKeyEvent() method for key events not handled by IME, we
- * need to dispatch them to webkit and check webkit's reply. Then inject a
- * new key event for further processing if webkit didn't handle it.
- *
- * Note that the native peer object does not take any strong reference onto the
- * instance of this java object, hence it is up to the client of this class (e.g.
- * the ViewEmbedder implementor) to hold a strong reference to it for the required
- * lifetime of the object.
- */
-@JNINamespace("content")
-class ImeAdapter {
- interface ViewEmbedder {
- /**
- * @param isFinish whether the event is occurring because input is finished.
- */
- public void onImeEvent(boolean isFinish);
- public void onSetFieldValue();
- public void onDismissInput();
- public View getAttachedView();
- public ResultReceiver getNewShowKeyboardReceiver();
- }
-
- static final int COMPOSITION_KEY_CODE = 229;
- /**
- * Selection value should be -1 if not known. See EditorInfo.java for details.
- */
- static final int INVALID_SELECTION = -1;
- static final int INVALID_COMPOSITION = -1;
-
- static int sEventTypeRawKeyDown;
- static int sEventTypeKeyUp;
- static int sEventTypeChar;
- static int sTextInputTypeNone;
- static int sTextInputTypeText;
- static int sTextInputTypeTextArea;
- static int sTextInputTypePassword;
- static int sTextInputTypeSearch;
- static int sTextInputTypeUrl;
- static int sTextInputTypeEmail;
- static int sTextInputTypeTel;
- static int sTextInputTypeNumber;
- static int sTextInputTypeWeek;
- static int sTextInputTypeContentEditable;
- static int sModifierShift;
- static int sModifierAlt;
- static int sModifierCtrl;
- static int sModifierCapsLockOn;
- static int sModifierNumLockOn;
-
- @CalledByNative
- static void initializeWebInputEvents(int eventTypeRawKeyDown, int eventTypeKeyUp,
- int eventTypeChar, int modifierShift, int modifierAlt, int modifierCtrl,
- int modifierCapsLockOn, int modifierNumLockOn) {
- sEventTypeRawKeyDown = eventTypeRawKeyDown;
- sEventTypeKeyUp = eventTypeKeyUp;
- sEventTypeChar = eventTypeChar;
- sModifierShift = modifierShift;
- sModifierAlt = modifierAlt;
- sModifierCtrl = modifierCtrl;
- sModifierCapsLockOn = modifierCapsLockOn;
- sModifierNumLockOn = modifierNumLockOn;
- }
-
- @CalledByNative
- static void initializeTextInputTypes(int textInputTypeNone, int textInputTypeText,
- int textInputTypeTextArea, int textInputTypePassword, int textInputTypeSearch,
- int textInputTypeUrl, int textInputTypeEmail, int textInputTypeTel,
- int textInputTypeNumber, int textInputTypeDate, int textInputTypeDateTime,
- int textInputTypeDateTimeLocal, int textInputTypeMonth, int textInputTypeTime,
- int textInputTypeWeek, int textInputTypeContentEditable) {
- sTextInputTypeNone = textInputTypeNone;
- sTextInputTypeText = textInputTypeText;
- sTextInputTypeTextArea = textInputTypeTextArea;
- sTextInputTypePassword = textInputTypePassword;
- sTextInputTypeSearch = textInputTypeSearch;
- sTextInputTypeUrl = textInputTypeUrl;
- sTextInputTypeEmail = textInputTypeEmail;
- sTextInputTypeTel = textInputTypeTel;
- sTextInputTypeNumber = textInputTypeNumber;
- sTextInputTypeWeek = textInputTypeWeek;
- sTextInputTypeContentEditable = textInputTypeContentEditable;
- }
-
- private int mNativeImeAdapterAndroid;
- private int mTextInputType;
- private int mInitialSelectionStart;
- private int mInitialSelectionEnd;
-
- private final Context mContext;
- private InputMethodManagerWrapper mInputMethodManagerWrapper;
- private final SelectionHandleController mSelectionHandleController;
- private final InsertionHandleController mInsertionHandleController;
- private AdapterInputConnection mInputConnection;
- private final ViewEmbedder mViewEmbedder;
- private final Handler mHandler;
-
- private class DelayedDismissInput implements Runnable {
- private final int mNativeImeAdapter;
-
- DelayedDismissInput(int nativeImeAdapter) {
- mNativeImeAdapter = nativeImeAdapter;
- }
-
- @Override
- public void run() {
- attach(mNativeImeAdapter, sTextInputTypeNone, INVALID_SELECTION, INVALID_SELECTION);
- dismissInput(true);
- }
- }
-
- private DelayedDismissInput mDismissInput = null;
-
- @VisibleForTesting
- protected boolean mIsShowWithoutHideOutstanding = false;
-
- // Delay introduced to avoid hiding the keyboard if new show requests are received.
- // The time required by the unfocus-focus events triggered by tab has been measured in soju:
- // Mean: 18.633 ms, Standard deviation: 7.9837 ms.
- // The value here should be higher enough to cover these cases, but not too high to avoid
- // letting the user perceiving important delays.
- private static final int INPUT_DISMISS_DELAY = 150;
-
- ImeAdapter(Context context, SelectionHandleController selectionHandleController,
- InsertionHandleController insertionHandleController, ViewEmbedder embedder) {
- mContext = context;
- mInputMethodManagerWrapper = new InputMethodManagerWrapper(context);
- mSelectionHandleController = selectionHandleController;
- mInsertionHandleController = insertionHandleController;
- mViewEmbedder = embedder;
- mHandler = new Handler();
- }
-
- boolean isFor(int nativeImeAdapter, int textInputType) {
- return mNativeImeAdapterAndroid == nativeImeAdapter &&
- mTextInputType == textInputType;
- }
-
- @VisibleForTesting
- protected void setInputMethodManagerWrapper(InputMethodManagerWrapper immw) {
- mInputMethodManagerWrapper = immw;
- }
-
- private InputMethodManagerWrapper getInputMethodManagerWrapper() {
- return mInputMethodManagerWrapper;
- }
-
- void attachAndShowIfNeeded(int nativeImeAdapter, int textInputType,
- int selectionStart, int selectionEnd, boolean showIfNeeded) {
- mHandler.removeCallbacks(mDismissInput);
-
- // If current input type is none and showIfNeeded is false, IME should not be shown
- // and input type should remain as none.
- if (mTextInputType == sTextInputTypeNone && !showIfNeeded) {
- return;
- }
-
- if (!isFor(nativeImeAdapter, textInputType)) {
- // Set a delayed task to perform unfocus. This avoids hiding the keyboard when tabbing
- // through text inputs or when JS rapidly changes focus to another text element.
- if (textInputType == sTextInputTypeNone) {
- mDismissInput = new DelayedDismissInput(nativeImeAdapter);
- mHandler.postDelayed(mDismissInput, INPUT_DISMISS_DELAY);
- return;
- }
-
- int previousType = mTextInputType;
- attach(nativeImeAdapter, textInputType, selectionStart, selectionEnd);
-
- mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView());
- if (showIfNeeded) {
- showKeyboard();
- }
- } else if (hasInputType() && showIfNeeded) {
- showKeyboard();
- }
- }
-
- void attach(int nativeImeAdapter, int textInputType, int selectionStart, int selectionEnd) {
- mNativeImeAdapterAndroid = nativeImeAdapter;
- mTextInputType = textInputType;
- mInitialSelectionStart = selectionStart;
- mInitialSelectionEnd = selectionEnd;
- nativeAttachImeAdapter(mNativeImeAdapterAndroid);
- }
-
- /**
- * Attaches the imeAdapter to its native counterpart. This is needed to start forwarding
- * keyboard events to WebKit.
- * @param nativeImeAdapter The pointer to the native ImeAdapter object.
- */
- void attach(int nativeImeAdapter) {
- mNativeImeAdapterAndroid = nativeImeAdapter;
- if (nativeImeAdapter != 0) {
- nativeAttachImeAdapter(mNativeImeAdapterAndroid);
- }
- }
-
- /**
- * Used to check whether the native counterpart of the ImeAdapter has been attached yet.
- * @return Whether native ImeAdapter has been attached and its pointer is currently nonzero.
- */
- boolean isNativeImeAdapterAttached() {
- return mNativeImeAdapterAndroid != 0;
- }
-
- private void showKeyboard() {
- mIsShowWithoutHideOutstanding = true;
- mInputMethodManagerWrapper.showSoftInput(mViewEmbedder.getAttachedView(), 0,
- mViewEmbedder.getNewShowKeyboardReceiver());
- }
-
- private void dismissInput(boolean unzoomIfNeeded) {
- hideKeyboard(unzoomIfNeeded);
- mViewEmbedder.onDismissInput();
- }
-
- private void hideKeyboard(boolean unzoomIfNeeded) {
- mIsShowWithoutHideOutstanding = false;
- View view = mViewEmbedder.getAttachedView();
- if (mInputMethodManagerWrapper.isActive(view)) {
- mInputMethodManagerWrapper.hideSoftInputFromWindow(view.getWindowToken(), 0,
- unzoomIfNeeded ? mViewEmbedder.getNewShowKeyboardReceiver() : null);
- }
- }
-
- @CalledByNative
- void detach() {
- mNativeImeAdapterAndroid = 0;
- mTextInputType = 0;
- }
-
- boolean hasInputType() {
- return mTextInputType != sTextInputTypeNone;
- }
-
- static boolean isTextInputType(int type) {
- return type != sTextInputTypeNone && !InputDialogContainer.isDialogInputType(type);
- }
-
- boolean hasTextInputType() {
- return isTextInputType(mTextInputType);
- }
-
- boolean dispatchKeyEvent(KeyEvent event) {
- return translateAndSendNativeEvents(event);
- }
-
- void commitText() {
- cancelComposition();
- if (mNativeImeAdapterAndroid != 0) {
- nativeCommitText(mNativeImeAdapterAndroid, "");
- }
- }
-
- @SuppressWarnings("unused")
- @CalledByNative
- private void cancelComposition() {
- if (mInputConnection != null) {
- mInputConnection.restartInput();
- }
- }
-
- @VisibleForTesting
- boolean checkCompositionQueueAndCallNative(String text, int newCursorPosition,
- boolean isCommit) {
- if (mNativeImeAdapterAndroid == 0) return false;
-
-
- // Committing an empty string finishes the current composition.
- boolean isFinish = text.isEmpty();
- if (!isFinish) {
- mSelectionHandleController.hideAndDisallowAutomaticShowing();
- mInsertionHandleController.hideAndDisallowAutomaticShowing();
- }
- mViewEmbedder.onImeEvent(isFinish);
- int keyCode = shouldSendKeyEventWithKeyCode(text);
- long timeStampMs = System.currentTimeMillis();
-
- if (keyCode != COMPOSITION_KEY_CODE) {
- sendKeyEventWithKeyCode(keyCode,
- KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
- } else {
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown,
- timeStampMs, keyCode, 0);
- if (isCommit) {
- nativeCommitText(mNativeImeAdapterAndroid, text);
- } else {
- nativeSetComposingText(mNativeImeAdapterAndroid, text, newCursorPosition);
- }
- nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp,
- timeStampMs, keyCode, 0);
- }
-
- return true;
- }
-
- private int shouldSendKeyEventWithKeyCode(String text) {
- if (text.length() != 1) return COMPOSITION_KEY_CODE;
-
- if (text.equals("\n")) return KeyEvent.KEYCODE_ENTER;
- else if (text.equals("\t")) return KeyEvent.KEYCODE_TAB;
- else return COMPOSITION_KEY_CODE;
- }
-
- private void sendKeyEventWithKeyCode(int keyCode, int flags) {
- long eventTime = System.currentTimeMillis();
- translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime,
- KeyEvent.ACTION_DOWN, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- flags));
- translateAndSendNativeEvents(new KeyEvent(System.currentTimeMillis(), eventTime,
- KeyEvent.ACTION_UP, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- flags));
- }
-
- private boolean translateAndSendNativeEvents(KeyEvent event) {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- int action = event.getAction();
- if (action != KeyEvent.ACTION_DOWN &&
- action != KeyEvent.ACTION_UP) {
- // action == KeyEvent.ACTION_MULTIPLE
- // TODO(bulach): confirm the actual behavior. Apparently:
- // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a
- // composition key down (229) followed by a commit text with the
- // string from event.getUnicodeChars().
- // Otherwise, we'd need to send an event with a
- // WebInputEvent::IsAutoRepeat modifier. We also need to verify when
- // we receive ACTION_MULTIPLE: we may receive it after an ACTION_DOWN,
- // and if that's the case, we'll need to review when to send the Char
- // event.
- return false;
- }
- mViewEmbedder.onImeEvent(false);
- return nativeSendKeyEvent(mNativeImeAdapterAndroid, event, event.getAction(),
- getModifiers(event.getMetaState()), event.getEventTime(), event.getKeyCode(),
- event.isSystem(), event.getUnicodeChar());
- }
-
- private void setInputConnection(AdapterInputConnection inputConnection) {
- mInputConnection = inputConnection;
- }
-
- private static int getModifiers(int metaState) {
- int modifiers = 0;
- if ((metaState & KeyEvent.META_SHIFT_ON) != 0) {
- modifiers |= sModifierShift;
- }
- if ((metaState & KeyEvent.META_ALT_ON) != 0) {
- modifiers |= sModifierAlt;
- }
- if ((metaState & KeyEvent.META_CTRL_ON) != 0) {
- modifiers |= sModifierCtrl;
- }
- if ((metaState & KeyEvent.META_CAPS_LOCK_ON) != 0) {
- modifiers |= sModifierCapsLockOn;
- }
- if ((metaState & KeyEvent.META_NUM_LOCK_ON) != 0) {
- modifiers |= sModifierNumLockOn;
- }
- return modifiers;
- }
-
- boolean isActive() {
- return mInputConnection != null && mInputConnection.isActive();
- }
-
- private boolean sendSyntheticKeyEvent(
- int eventType, long timestampMs, int keyCode, int unicodeChar) {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeSendSyntheticKeyEvent(
- mNativeImeAdapterAndroid, eventType, timestampMs, keyCode, unicodeChar);
- return true;
- }
-
- private boolean deleteSurroundingText(int leftLength, int rightLength) {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeDeleteSurroundingText(mNativeImeAdapterAndroid, leftLength, rightLength);
- return true;
- }
-
- @VisibleForTesting
- protected boolean setEditableSelectionOffsets(int start, int end) {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeSetEditableSelectionOffsets(mNativeImeAdapterAndroid, start, end);
- return true;
- }
-
- private void batchStateChanged(boolean isBegin) {
- if (mNativeImeAdapterAndroid == 0) return;
- nativeImeBatchStateChanged(mNativeImeAdapterAndroid, isBegin);
- }
-
- private boolean setComposingRegion(int start, int end) {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end);
- return true;
- }
-
- boolean unselect() {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeUnselect(mNativeImeAdapterAndroid);
- return true;
- }
-
- boolean selectAll() {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeSelectAll(mNativeImeAdapterAndroid);
- return true;
- }
-
- boolean cut() {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeCut(mNativeImeAdapterAndroid);
- return true;
- }
-
- boolean copy() {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativeCopy(mNativeImeAdapterAndroid);
- return true;
- }
-
- boolean paste() {
- if (mNativeImeAdapterAndroid == 0) return false;
-
- nativePaste(mNativeImeAdapterAndroid);
- return true;
- }
-
- public static class AdapterInputConnectionFactory {
- public AdapterInputConnection get(View view, ImeAdapter imeAdapter,
- EditorInfo outAttrs) {
- return new AdapterInputConnection(view, imeAdapter, outAttrs);
- }
- }
-
- // This InputConnection is created by ContentView.onCreateInputConnection.
- // It then adapts android's IME to chrome's RenderWidgetHostView using the
- // native ImeAdapterAndroid via the outer class ImeAdapter.
- public static class AdapterInputConnection extends BaseInputConnection {
- private static final String TAG =
- "org.chromium.content.browser.ImeAdapter$AdapterInputConnection";
- private static final boolean DEBUG = false;
- private final View mInternalView;
- private final ImeAdapter mImeAdapter;
-
- private boolean mSingleLine;
- private int mNumNestedBatchEdits = 0;
- private boolean mIgnoreTextInputStateUpdates = false;
-
- private int mLastUpdateSelectionStart = INVALID_SELECTION;
- private int mLastUpdateSelectionEnd = INVALID_SELECTION;
- private int mLastUpdateCompositionStart = INVALID_COMPOSITION;
- private int mLastUpdateCompositionEnd = INVALID_COMPOSITION;
-
- /**
- * Updates the AdapterInputConnection's internal representation of the text
- * being edited and its selection and composition properties. The resulting
- * Editable is accessible through the getEditable() method.
- * If the text has not changed, this also calls updateSelection on the InputMethodManager.
- * @param text The String contents of the field being edited
- * @param selectionStart The character offset of the selection start, or the caret
- * position if there is no selection
- * @param selectionEnd The character offset of the selection end, or the caret
- * position if there is no selection
- * @param compositionStart The character offset of the composition start, or -1
- * if there is no composition
- * @param compositionEnd The character offset of the composition end, or -1
- * if there is no selection
- */
- public void setEditableText(String text, int selectionStart, int selectionEnd,
- int compositionStart, int compositionEnd) {
- if (DEBUG) {
- Log.w(TAG, "setEditableText [" + text + "] [" + selectionStart + " " + selectionEnd
- + "] [" + compositionStart + " " + compositionEnd + "]");
- }
- Editable editable = getEditable();
-
- int prevSelectionStart = Selection.getSelectionStart(editable);
- int prevSelectionEnd = Selection.getSelectionEnd(editable);
- int prevCompositionStart = getComposingSpanStart(editable);
- int prevCompositionEnd = getComposingSpanEnd(editable);
- String prevText = editable.toString();
-
- selectionStart = Math.min(selectionStart, text.length());
- selectionEnd = Math.min(selectionEnd, text.length());
- compositionStart = Math.min(compositionStart, text.length());
- compositionEnd = Math.min(compositionEnd, text.length());
-
- boolean textUnchanged = prevText.equals(text);
-
- if (!textUnchanged) {
- editable.replace(0, editable.length(), text);
- }
-
- if (prevSelectionStart == selectionStart && prevSelectionEnd == selectionEnd
- && prevCompositionStart == compositionStart
- && prevCompositionEnd == compositionEnd) {
- // Nothing has changed; don't need to do anything
- return;
- }
-
- Selection.setSelection(editable, selectionStart, selectionEnd);
- super.setComposingRegion(compositionStart, compositionEnd);
-
- if (mIgnoreTextInputStateUpdates) return;
- updateSelection(selectionStart, selectionEnd, compositionStart, compositionEnd);
- }
-
- @VisibleForTesting
- protected void updateSelection(
- int selectionStart, int selectionEnd,
- int compositionStart, int compositionEnd) {
- // Avoid sending update if we sent an exact update already previously.
- if (mLastUpdateSelectionStart == selectionStart &&
- mLastUpdateSelectionEnd == selectionEnd &&
- mLastUpdateCompositionStart == compositionStart &&
- mLastUpdateCompositionEnd == compositionEnd) {
- return;
- }
- if (DEBUG) {
- Log.w(TAG, "updateSelection [" + selectionStart + " " + selectionEnd + "] ["
- + compositionStart + " " + compositionEnd + "]");
- }
- // updateSelection should be called every time the selection or composition changes
- // if it happens not within a batch edit, or at the end of each top level batch edit.
- getInputMethodManagerWrapper().updateSelection(mInternalView,
- selectionStart, selectionEnd, compositionStart, compositionEnd);
- mLastUpdateSelectionStart = selectionStart;
- mLastUpdateSelectionEnd = selectionEnd;
- mLastUpdateCompositionStart = compositionStart;
- mLastUpdateCompositionEnd = compositionEnd;
- }
-
- @Override
- public boolean setComposingText(CharSequence text, int newCursorPosition) {
- if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPosition + "]");
- super.setComposingText(text, newCursorPosition);
- return mImeAdapter.checkCompositionQueueAndCallNative(text.toString(),
- newCursorPosition, false);
- }
-
- @Override
- public boolean commitText(CharSequence text, int newCursorPosition) {
- if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]");
- super.commitText(text, newCursorPosition);
- return mImeAdapter.checkCompositionQueueAndCallNative(text.toString(),
- newCursorPosition, text.length() > 0);
- }
-
- @Override
- public boolean performEditorAction(int actionCode) {
- if (DEBUG) Log.w(TAG, "performEditorAction [" + actionCode + "]");
- if (actionCode == EditorInfo.IME_ACTION_NEXT) {
- restartInput();
- // Send TAB key event
- long timeStampMs = System.currentTimeMillis();
- mImeAdapter.sendSyntheticKeyEvent(
- sEventTypeRawKeyDown, timeStampMs, KeyEvent.KEYCODE_TAB, 0);
- } else {
- mImeAdapter.sendKeyEventWithKeyCode(KeyEvent.KEYCODE_ENTER,
- KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
- | KeyEvent.FLAG_EDITOR_ACTION);
- }
- return true;
- }
-
- @Override
- public boolean performContextMenuAction(int id) {
- if (DEBUG) Log.w(TAG, "performContextMenuAction [" + id + "]");
- switch (id) {
- case android.R.id.selectAll:
- return mImeAdapter.selectAll();
- case android.R.id.cut:
- return mImeAdapter.cut();
- case android.R.id.copy:
- return mImeAdapter.copy();
- case android.R.id.paste:
- return mImeAdapter.paste();
- default:
- return false;
- }
- }
-
- @Override
- public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
- if (DEBUG) Log.w(TAG, "getExtractedText");
- ExtractedText et = new ExtractedText();
- Editable editable = getEditable();
- et.text = editable.toString();
- et.partialEndOffset = editable.length();
- et.selectionStart = Selection.getSelectionStart(editable);
- et.selectionEnd = Selection.getSelectionEnd(editable);
- et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
- return et;
- }
-
- @Override
- public boolean beginBatchEdit() {
- if (DEBUG) Log.w(TAG, "beginBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
- if (mNumNestedBatchEdits == 0) mImeAdapter.batchStateChanged(true);
-
- mNumNestedBatchEdits++;
- return false;
- }
-
- @Override
- public boolean endBatchEdit() {
- if (mNumNestedBatchEdits == 0) return false;
-
- --mNumNestedBatchEdits;
- if (DEBUG) Log.w(TAG, "endBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
- if (mNumNestedBatchEdits == 0) mImeAdapter.batchStateChanged(false);
- return false;
- }
-
- @Override
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- if (DEBUG) {
- Log.w(TAG, "deleteSurroundingText [" + leftLength + " " + rightLength + "]");
- }
- if (!super.deleteSurroundingText(leftLength, rightLength)) {
- return false;
- }
- return mImeAdapter.deleteSurroundingText(leftLength, rightLength);
- }
-
- @Override
- public boolean sendKeyEvent(KeyEvent event) {
- if (DEBUG) Log.w(TAG, "sendKeyEvent [" + event.getAction() + "]");
- mImeAdapter.mSelectionHandleController.hideAndDisallowAutomaticShowing();
- mImeAdapter.mInsertionHandleController.hideAndDisallowAutomaticShowing();
-
- // If this is a key-up, and backspace/del or if the key has a character representation,
- // need to update the underlying Editable (i.e. the local representation of the text
- // being edited).
- if (event.getAction() == KeyEvent.ACTION_UP) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
- super.deleteSurroundingText(1, 0);
- } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
- super.deleteSurroundingText(0, 1);
- } else {
- int unicodeChar = event.getUnicodeChar();
- if (unicodeChar != 0) {
- Editable editable = getEditable();
- int selectionStart = Selection.getSelectionStart(editable);
- int selectionEnd = Selection.getSelectionEnd(editable);
- if (selectionStart > selectionEnd) {
- int temp = selectionStart;
- selectionStart = selectionEnd;
- selectionEnd = temp;
- }
- editable.replace(selectionStart, selectionEnd,
- Character.toString((char)unicodeChar));
- }
- }
- }
- mImeAdapter.translateAndSendNativeEvents(event);
- return true;
- }
-
- @Override
- public boolean finishComposingText() {
- if (DEBUG) Log.w(TAG, "finishComposingText");
- Editable editable = getEditable();
- if (getComposingSpanStart(editable) == getComposingSpanEnd(editable)) {
- return true;
- }
- super.finishComposingText();
- return mImeAdapter.checkCompositionQueueAndCallNative("", 0, true);
- }
-
- @Override
- public boolean setSelection(int start, int end) {
- if (DEBUG) Log.w(TAG, "setSelection");
- if (start < 0 || end < 0) return true;
- super.setSelection(start, end);
- return mImeAdapter.setEditableSelectionOffsets(start, end);
- }
-
- /**
- * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text
- * state is no longer what the IME has and that it needs to be updated.
- */
- void restartInput() {
- if (DEBUG) Log.w(TAG, "restartInput");
- getInputMethodManagerWrapper().restartInput(mInternalView);
- mIgnoreTextInputStateUpdates = false;
- mNumNestedBatchEdits = 0;
- }
-
- @Override
- public boolean setComposingRegion(int start, int end) {
- if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]");
- int a = Math.min(start, end);
- int b = Math.max(start, end);
- super.setComposingRegion(a, b);
- return mImeAdapter.setComposingRegion(a, b);
- }
-
- boolean isActive() {
- return getInputMethodManagerWrapper().isActive(mInternalView);
- }
-
- void setIgnoreTextInputStateUpdates(boolean shouldIgnore) {
- mIgnoreTextInputStateUpdates = shouldIgnore;
- if (shouldIgnore) return;
-
- Editable editable = getEditable();
- updateSelection(Selection.getSelectionStart(editable),
- Selection.getSelectionEnd(editable),
- getComposingSpanStart(editable),
- getComposingSpanEnd(editable));
- }
-
- @VisibleForTesting
- protected boolean isIgnoringTextInputStateUpdates() {
- return mIgnoreTextInputStateUpdates;
- }
-
- private InputMethodManagerWrapper getInputMethodManagerWrapper() {
- return mImeAdapter.getInputMethodManagerWrapper();
- }
-
- @VisibleForTesting
- protected AdapterInputConnection(View view, ImeAdapter imeAdapter, EditorInfo outAttrs) {
- super(view, true);
- mInternalView = view;
- mImeAdapter = imeAdapter;
- mImeAdapter.setInputConnection(this);
- mSingleLine = true;
- outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
- outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
- if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeText) {
- // Normal text field
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeTextArea ||
- imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeContentEditable) {
- // TextArea or contenteditable.
- outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
- | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
- | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_NONE;
- mSingleLine = false;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypePassword) {
- // Password
- outAttrs.inputType = InputType.TYPE_CLASS_TEXT
- | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeSearch) {
- // Search
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_SEARCH;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeUrl) {
- // Url
- // TYPE_TEXT_VARIATION_URI prevents Tab key from showing, so
- // exclude it for now.
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeEmail) {
- // Email
- outAttrs.inputType = InputType.TYPE_CLASS_TEXT
- | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeTel) {
- // Telephone
- // Number and telephone do not have both a Tab key and an
- // action in default OSK, so set the action to NEXT
- outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
- } else if (imeAdapter.mTextInputType == ImeAdapter.sTextInputTypeNumber) {
- // Number
- outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
- | InputType.TYPE_NUMBER_VARIATION_NORMAL;
- outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
- }
- outAttrs.initialSelStart = imeAdapter.mInitialSelectionStart;
- outAttrs.initialSelEnd = imeAdapter.mInitialSelectionStart;
- }
- }
-
- private native boolean nativeSendSyntheticKeyEvent(int nativeImeAdapterAndroid,
- int eventType, long timestampMs, int keyCode, int unicodeChar);
-
- private native boolean nativeSendKeyEvent(int nativeImeAdapterAndroid, KeyEvent event,
- int action, int modifiers, long timestampMs, int keyCode, boolean isSystemKey,
- int unicodeChar);
-
- private native void nativeSetComposingText(int nativeImeAdapterAndroid, String text,
- int newCursorPosition);
-
- private native void nativeCommitText(int nativeImeAdapterAndroid, String text);
-
- private native void nativeAttachImeAdapter(int nativeImeAdapterAndroid);
-
- private native void nativeSetEditableSelectionOffsets(int nativeImeAdapterAndroid,
- int start, int end);
-
- private native void nativeSetComposingRegion(int nativeImeAdapterAndroid, int start, int end);
-
- private native void nativeDeleteSurroundingText(int nativeImeAdapterAndroid,
- int before, int after);
-
- private native void nativeImeBatchStateChanged(int nativeImeAdapterAndroid, boolean isBegin);
-
- private native void nativeUnselect(int nativeImeAdapterAndroid);
- private native void nativeSelectAll(int nativeImeAdapterAndroid);
- private native void nativeCut(int nativeImeAdapterAndroid);
- private native void nativeCopy(int nativeImeAdapterAndroid);
- private native void nativePaste(int nativeImeAdapterAndroid);
-}
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
new file mode 100644
index 0000000..045a542
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
@@ -0,0 +1,410 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser.input;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import android.text.Editable;
+import android.text.InputType;
+import android.text.Selection;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedText;
+import android.view.inputmethod.ExtractedTextRequest;
+
+/**
+ * InputConnection is created by ContentView.onCreateInputConnection.
+ * It then adapts android's IME to chrome's RenderWidgetHostView using the
+ * native ImeAdapterAndroid via the class ImeAdapter.
+ */
+public class AdapterInputConnection extends BaseInputConnection {
+ private static final String TAG =
+ "org.chromium.content.browser.input.AdapterInputConnection";
+ private static final boolean DEBUG = false;
+ /**
+ * Selection value should be -1 if not known. See EditorInfo.java for details.
+ */
+ public static final int INVALID_SELECTION = -1;
+ public static final int INVALID_COMPOSITION = -1;
+
+ private final View mInternalView;
+ private final ImeAdapter mImeAdapter;
+
+ private boolean mSingleLine;
+ private int mNumNestedBatchEdits = 0;
+ private boolean mIgnoreTextInputStateUpdates = false;
+
+ private int mLastUpdateSelectionStart = INVALID_SELECTION;
+ private int mLastUpdateSelectionEnd = INVALID_SELECTION;
+ private int mLastUpdateCompositionStart = INVALID_COMPOSITION;
+ private int mLastUpdateCompositionEnd = INVALID_COMPOSITION;
+
+ @VisibleForTesting
+ AdapterInputConnection(View view, ImeAdapter imeAdapter, EditorInfo outAttrs) {
+ super(view, true);
+ mInternalView = view;
+ mImeAdapter = imeAdapter;
+ mImeAdapter.setInputConnection(this);
+ mSingleLine = true;
+ outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
+ outAttrs.inputType = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
+
+ if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeText) {
+ // Normal text field
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeTextArea ||
+ imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeContentEditable) {
+ // TextArea or contenteditable.
+ outAttrs.inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
+ | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_NONE;
+ mSingleLine = false;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypePassword) {
+ // Password
+ outAttrs.inputType = InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeSearch) {
+ // Search
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_SEARCH;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeUrl) {
+ // Url
+ // TYPE_TEXT_VARIATION_URI prevents Tab key from showing, so
+ // exclude it for now.
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeEmail) {
+ // Email
+ outAttrs.inputType = InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_GO;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeTel) {
+ // Telephone
+ // Number and telephone do not have both a Tab key and an
+ // action in default OSK, so set the action to NEXT
+ outAttrs.inputType = InputType.TYPE_CLASS_PHONE;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
+ } else if (imeAdapter.getTextInputType() == ImeAdapter.sTextInputTypeNumber) {
+ // Number
+ outAttrs.inputType = InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_NORMAL;
+ outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
+ }
+ outAttrs.initialSelStart = imeAdapter.getInitialSelectionStart();
+ outAttrs.initialSelEnd = imeAdapter.getInitialSelectionStart();
+ }
+
+ /**
+ * Updates the AdapterInputConnection's internal representation of the text
+ * being edited and its selection and composition properties. The resulting
+ * Editable is accessible through the getEditable() method.
+ * If the text has not changed, this also calls updateSelection on the InputMethodManager.
+ * @param text The String contents of the field being edited
+ * @param selectionStart The character offset of the selection start, or the caret
+ * position if there is no selection
+ * @param selectionEnd The character offset of the selection end, or the caret
+ * position if there is no selection
+ * @param compositionStart The character offset of the composition start, or -1
+ * if there is no composition
+ * @param compositionEnd The character offset of the composition end, or -1
+ * if there is no selection
+ */
+ public void setEditableText(String text, int selectionStart, int selectionEnd,
+ int compositionStart, int compositionEnd) {
+ if (DEBUG) {
+ Log.w(TAG, "setEditableText [" + text + "] [" + selectionStart + " " + selectionEnd
+ + "] [" + compositionStart + " " + compositionEnd + "]");
+ }
+ // Non-breaking spaces can cause the IME to get confused. Replace with normal spaces.
+ text = text.replace('\u00A0', ' ');
+
+ Editable editable = getEditable();
+
+ int prevSelectionStart = Selection.getSelectionStart(editable);
+ int prevSelectionEnd = Selection.getSelectionEnd(editable);
+ int prevCompositionStart = getComposingSpanStart(editable);
+ int prevCompositionEnd = getComposingSpanEnd(editable);
+ String prevText = editable.toString();
+
+ selectionStart = Math.min(selectionStart, text.length());
+ selectionEnd = Math.min(selectionEnd, text.length());
+ compositionStart = Math.min(compositionStart, text.length());
+ compositionEnd = Math.min(compositionEnd, text.length());
+
+ boolean textUnchanged = prevText.equals(text);
+
+ if (!textUnchanged) {
+ editable.replace(0, editable.length(), text);
+ }
+
+ if (prevSelectionStart == selectionStart && prevSelectionEnd == selectionEnd
+ && prevCompositionStart == compositionStart
+ && prevCompositionEnd == compositionEnd) {
+ // Nothing has changed; don't need to do anything
+ return;
+ }
+
+ Selection.setSelection(editable, selectionStart, selectionEnd);
+ super.setComposingRegion(compositionStart, compositionEnd);
+
+ if (mIgnoreTextInputStateUpdates) return;
+ updateSelection(selectionStart, selectionEnd, compositionStart, compositionEnd);
+ }
+
+ @VisibleForTesting
+ protected void updateSelection(
+ int selectionStart, int selectionEnd,
+ int compositionStart, int compositionEnd) {
+ // Avoid sending update if we sent an exact update already previously.
+ if (mLastUpdateSelectionStart == selectionStart &&
+ mLastUpdateSelectionEnd == selectionEnd &&
+ mLastUpdateCompositionStart == compositionStart &&
+ mLastUpdateCompositionEnd == compositionEnd) {
+ return;
+ }
+ if (DEBUG) {
+ Log.w(TAG, "updateSelection [" + selectionStart + " " + selectionEnd + "] ["
+ + compositionStart + " " + compositionEnd + "]");
+ }
+ // updateSelection should be called every time the selection or composition changes
+ // if it happens not within a batch edit, or at the end of each top level batch edit.
+ getInputMethodManagerWrapper().updateSelection(mInternalView,
+ selectionStart, selectionEnd, compositionStart, compositionEnd);
+ mLastUpdateSelectionStart = selectionStart;
+ mLastUpdateSelectionEnd = selectionEnd;
+ mLastUpdateCompositionStart = compositionStart;
+ mLastUpdateCompositionEnd = compositionEnd;
+ }
+
+ /**
+ * @see BaseInputConnection#setComposingText(java.lang.CharSequence, int)
+ */
+ @Override
+ public boolean setComposingText(CharSequence text, int newCursorPosition) {
+ if (DEBUG) Log.w(TAG, "setComposingText [" + text + "] [" + newCursorPosition + "]");
+ super.setComposingText(text, newCursorPosition);
+ return mImeAdapter.checkCompositionQueueAndCallNative(text.toString(),
+ newCursorPosition, false);
+ }
+
+ /**
+ * @see BaseInputConnection#commitText(java.lang.CharSequence, int)
+ */
+ @Override
+ public boolean commitText(CharSequence text, int newCursorPosition) {
+ if (DEBUG) Log.w(TAG, "commitText [" + text + "] [" + newCursorPosition + "]");
+ super.commitText(text, newCursorPosition);
+ return mImeAdapter.checkCompositionQueueAndCallNative(text.toString(),
+ newCursorPosition, text.length() > 0);
+ }
+
+ /**
+ * @see BaseInputConnection#performEditorAction(int)
+ */
+ @Override
+ public boolean performEditorAction(int actionCode) {
+ if (DEBUG) Log.w(TAG, "performEditorAction [" + actionCode + "]");
+ if (actionCode == EditorInfo.IME_ACTION_NEXT) {
+ restartInput();
+ // Send TAB key event
+ long timeStampMs = System.currentTimeMillis();
+ mImeAdapter.sendSyntheticKeyEvent(
+ ImeAdapter.sEventTypeRawKeyDown, timeStampMs, KeyEvent.KEYCODE_TAB, 0);
+ } else {
+ mImeAdapter.sendKeyEventWithKeyCode(KeyEvent.KEYCODE_ENTER,
+ KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
+ | KeyEvent.FLAG_EDITOR_ACTION);
+ }
+ return true;
+ }
+
+ /**
+ * @see BaseInputConnection#performContextMenuAction(int)
+ */
+ @Override
+ public boolean performContextMenuAction(int id) {
+ if (DEBUG) Log.w(TAG, "performContextMenuAction [" + id + "]");
+ switch (id) {
+ case android.R.id.selectAll:
+ return mImeAdapter.selectAll();
+ case android.R.id.cut:
+ return mImeAdapter.cut();
+ case android.R.id.copy:
+ return mImeAdapter.copy();
+ case android.R.id.paste:
+ return mImeAdapter.paste();
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * @see BaseInputConnection#getExtractedText(android.view.inputmethod.ExtractedTextRequest,
+ * int)
+ */
+ @Override
+ public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
+ if (DEBUG) Log.w(TAG, "getExtractedText");
+ ExtractedText et = new ExtractedText();
+ Editable editable = getEditable();
+ et.text = editable.toString();
+ et.partialEndOffset = editable.length();
+ et.selectionStart = Selection.getSelectionStart(editable);
+ et.selectionEnd = Selection.getSelectionEnd(editable);
+ et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
+ return et;
+ }
+
+ /**
+ * @see BaseInputConnection#beginBatchEdit()
+ */
+ @Override
+ public boolean beginBatchEdit() {
+ if (DEBUG) Log.w(TAG, "beginBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
+ if (mNumNestedBatchEdits == 0) mImeAdapter.batchStateChanged(true);
+
+ mNumNestedBatchEdits++;
+ return false;
+ }
+
+ /**
+ * @see BaseInputConnection#endBatchEdit()
+ */
+ @Override
+ public boolean endBatchEdit() {
+ if (mNumNestedBatchEdits == 0) return false;
+
+ --mNumNestedBatchEdits;
+ if (DEBUG) Log.w(TAG, "endBatchEdit [" + (mNumNestedBatchEdits == 0) + "]");
+ if (mNumNestedBatchEdits == 0) mImeAdapter.batchStateChanged(false);
+ return false;
+ }
+
+ /**
+ * @see BaseInputConnection#deleteSurroundingText(int, int)
+ */
+ @Override
+ public boolean deleteSurroundingText(int leftLength, int rightLength) {
+ if (DEBUG) {
+ Log.w(TAG, "deleteSurroundingText [" + leftLength + " " + rightLength + "]");
+ }
+ if (!super.deleteSurroundingText(leftLength, rightLength)) {
+ return false;
+ }
+ return mImeAdapter.deleteSurroundingText(leftLength, rightLength);
+ }
+
+ /**
+ * @see BaseInputConnection#sendKeyEvent(android.view.KeyEvent)
+ */
+ @Override
+ public boolean sendKeyEvent(KeyEvent event) {
+ if (DEBUG) Log.w(TAG, "sendKeyEvent [" + event.getAction() + "]");
+ mImeAdapter.hideSelectionAndInsertionHandleControllers();
+
+ // If this is a key-up, and backspace/del or if the key has a character representation,
+ // need to update the underlying Editable (i.e. the local representation of the text
+ // being edited).
+ if (event.getAction() == KeyEvent.ACTION_UP) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
+ super.deleteSurroundingText(1, 0);
+ } else if (event.getKeyCode() == KeyEvent.KEYCODE_FORWARD_DEL) {
+ super.deleteSurroundingText(0, 1);
+ } else {
+ int unicodeChar = event.getUnicodeChar();
+ if (unicodeChar != 0) {
+ Editable editable = getEditable();
+ int selectionStart = Selection.getSelectionStart(editable);
+ int selectionEnd = Selection.getSelectionEnd(editable);
+ if (selectionStart > selectionEnd) {
+ int temp = selectionStart;
+ selectionStart = selectionEnd;
+ selectionEnd = temp;
+ }
+ editable.replace(selectionStart, selectionEnd,
+ Character.toString((char)unicodeChar));
+ }
+ }
+ }
+ mImeAdapter.translateAndSendNativeEvents(event);
+ return true;
+ }
+
+ /**
+ * @see BaseInputConnection#finishComposingText()
+ */
+ @Override
+ public boolean finishComposingText() {
+ if (DEBUG) Log.w(TAG, "finishComposingText");
+ Editable editable = getEditable();
+ if (getComposingSpanStart(editable) == getComposingSpanEnd(editable)) {
+ return true;
+ }
+ super.finishComposingText();
+ return mImeAdapter.checkCompositionQueueAndCallNative("", 0, true);
+ }
+
+ /**
+ * @see BaseInputConnection#setSelection(int, int)
+ */
+ @Override
+ public boolean setSelection(int start, int end) {
+ if (DEBUG) Log.w(TAG, "setSelection");
+ if (start < 0 || end < 0) return true;
+ super.setSelection(start, end);
+ return mImeAdapter.setEditableSelectionOffsets(start, end);
+ }
+
+ /**
+ * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text
+ * state is no longer what the IME has and that it needs to be updated.
+ */
+ void restartInput() {
+ if (DEBUG) Log.w(TAG, "restartInput");
+ getInputMethodManagerWrapper().restartInput(mInternalView);
+ mIgnoreTextInputStateUpdates = false;
+ mNumNestedBatchEdits = 0;
+ }
+
+ /**
+ * @see BaseInputConnection#setComposingRegion(int, int)
+ */
+ @Override
+ public boolean setComposingRegion(int start, int end) {
+ if (DEBUG) Log.w(TAG, "setComposingRegion [" + start + " " + end + "]");
+ int a = Math.min(start, end);
+ int b = Math.max(start, end);
+ super.setComposingRegion(a, b);
+ return mImeAdapter.setComposingRegion(a, b);
+ }
+
+ boolean isActive() {
+ return getInputMethodManagerWrapper().isActive(mInternalView);
+ }
+
+ public void setIgnoreTextInputStateUpdates(boolean shouldIgnore) {
+ mIgnoreTextInputStateUpdates = shouldIgnore;
+ if (shouldIgnore) return;
+
+ Editable editable = getEditable();
+ updateSelection(Selection.getSelectionStart(editable),
+ Selection.getSelectionEnd(editable),
+ getComposingSpanStart(editable),
+ getComposingSpanEnd(editable));
+ }
+
+ @VisibleForTesting
+ protected boolean isIgnoringTextInputStateUpdates() {
+ return mIgnoreTextInputStateUpdates;
+ }
+
+ private InputMethodManagerWrapper getInputMethodManagerWrapper() {
+ return mImeAdapter.getInputMethodManagerWrapper();
+ }
+}
diff --git a/content/public/android/java/src/org/chromium/content/browser/CursorController.java b/content/public/android/java/src/org/chromium/content/browser/input/CursorController.java
index 6e572c8..10e3064 100644
--- a/content/public/android/java/src/org/chromium/content/browser/CursorController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/CursorController.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.view.ViewTreeObserver;
diff --git a/content/public/android/java/src/org/chromium/content/browser/DateTimeChooserAndroid.java b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java
index 7fc146b..f8fca54 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DateTimeChooserAndroid.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/DateTimeChooserAndroid.java
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
+import org.chromium.content.browser.ContentViewCore;
import android.content.Context;
diff --git a/content/public/android/java/src/org/chromium/content/browser/DateTimePickerDialog.java b/content/public/android/java/src/org/chromium/content/browser/input/DateTimePickerDialog.java
index c122c29..29bca66 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DateTimePickerDialog.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/DateTimePickerDialog.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.app.AlertDialog;
import android.content.Context;
diff --git a/content/public/android/java/src/org/chromium/content/browser/HandleView.java b/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java
index a772d5d..a220894 100644
--- a/content/public/android/java/src/org/chromium/content/browser/HandleView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/HandleView.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.content.Context;
import android.content.res.TypedArray;
@@ -27,7 +27,7 @@ import android.widget.TextView;
/**
* View that displays a selection or insertion handle for text editing.
*/
-class HandleView extends View {
+public class HandleView extends View {
private static final float FADE_DURATION = 200.f;
private Drawable mDrawable;
@@ -113,7 +113,7 @@ class HandleView extends View {
}
mDrawable = mSelectHandleLeft;
handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = (handleWidth * 3) / 4;
+ mHotspotX = (handleWidth * 3) / 4f;
break;
}
@@ -124,7 +124,7 @@ class HandleView extends View {
}
mDrawable = mSelectHandleRight;
handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = handleWidth / 4;
+ mHotspotX = handleWidth / 4f;
break;
}
@@ -136,7 +136,7 @@ class HandleView extends View {
}
mDrawable = mSelectHandleCenter;
handleWidth = mDrawable.getIntrinsicWidth();
- mHotspotX = handleWidth / 2;
+ mHotspotX = handleWidth / 2f;
mIsInsertionHandle = true;
break;
}
@@ -306,6 +306,9 @@ class HandleView extends View {
case MotionEvent.ACTION_CANCEL:
mIsDragging = false;
break;
+
+ default:
+ return false;
}
return true;
}
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
new file mode 100644
index 0000000..1ea57b4
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -0,0 +1,572 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser.input;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+
+/**
+ * Adapts and plumbs android IME service onto the chrome text input API.
+ * ImeAdapter provides an interface in both ways native <-> java:
+ * 1. InputConnectionAdapter notifies native code of text composition state and
+ * dispatch key events from java -> WebKit.
+ * 2. Native ImeAdapter notifies java side to clear composition text.
+ *
+ * The basic flow is:
+ * 1. When InputConnectionAdapter gets called with composition or result text:
+ * If we receive a composition text or a result text, then we just need to
+ * dispatch a synthetic key event with special keycode 229, and then dispatch
+ * the composition or result text.
+ * 2. Intercept dispatchKeyEvent() method for key events not handled by IME, we
+ * need to dispatch them to webkit and check webkit's reply. Then inject a
+ * new key event for further processing if webkit didn't handle it.
+ *
+ * Note that the native peer object does not take any strong reference onto the
+ * instance of this java object, hence it is up to the client of this class (e.g.
+ * the ViewEmbedder implementor) to hold a strong reference to it for the required
+ * lifetime of the object.
+ */
+@JNINamespace("content")
+public class ImeAdapter {
+ public interface ViewEmbedder {
+ /**
+ * @param isFinish whether the event is occurring because input is finished.
+ */
+ void onImeEvent(boolean isFinish);
+ void onSetFieldValue();
+ void onDismissInput();
+ View getAttachedView();
+ ResultReceiver getNewShowKeyboardReceiver();
+ }
+
+ private class DelayedDismissInput implements Runnable {
+ private final int mNativeImeAdapter;
+
+ DelayedDismissInput(int nativeImeAdapter) {
+ mNativeImeAdapter = nativeImeAdapter;
+ }
+
+ @Override
+ public void run() {
+ attach(mNativeImeAdapter, sTextInputTypeNone, AdapterInputConnection.INVALID_SELECTION,
+ AdapterInputConnection.INVALID_SELECTION);
+ dismissInput(true);
+ }
+ }
+
+ private static final int COMPOSITION_KEY_CODE = 229;
+
+ // Delay introduced to avoid hiding the keyboard if new show requests are received.
+ // The time required by the unfocus-focus events triggered by tab has been measured in soju:
+ // Mean: 18.633 ms, Standard deviation: 7.9837 ms.
+ // The value here should be higher enough to cover these cases, but not too high to avoid
+ // letting the user perceiving important delays.
+ private static final int INPUT_DISMISS_DELAY = 150;
+
+ // All the constants that are retrieved from the C++ code.
+ // They get set through initializeWebInputEvents and initializeTextInputTypes calls.
+ static int sEventTypeRawKeyDown;
+ static int sEventTypeKeyUp;
+ static int sEventTypeChar;
+ static int sTextInputTypeNone;
+ static int sTextInputTypeText;
+ static int sTextInputTypeTextArea;
+ static int sTextInputTypePassword;
+ static int sTextInputTypeSearch;
+ static int sTextInputTypeUrl;
+ static int sTextInputTypeEmail;
+ static int sTextInputTypeTel;
+ static int sTextInputTypeNumber;
+ static int sTextInputTypeWeek;
+ static int sTextInputTypeContentEditable;
+ static int sModifierShift;
+ static int sModifierAlt;
+ static int sModifierCtrl;
+ static int sModifierCapsLockOn;
+ static int sModifierNumLockOn;
+
+ private int mNativeImeAdapterAndroid;
+ private final Context mContext;
+ private InputMethodManagerWrapper mInputMethodManagerWrapper;
+ private AdapterInputConnection mInputConnection;
+ private final ViewEmbedder mViewEmbedder;
+ private final Handler mHandler;
+ private DelayedDismissInput mDismissInput = null;
+ private final SelectionHandleController mSelectionHandleController;
+ private final InsertionHandleController mInsertionHandleController;
+ private int mTextInputType;
+ private int mInitialSelectionStart;
+ private int mInitialSelectionEnd;
+
+ @VisibleForTesting
+ boolean mIsShowWithoutHideOutstanding = false;
+
+ /**
+ * @param context View context.
+ * @param selectionHandleController The controller that handles selection.
+ * @param insertionHandleController The controller that handles insertion.
+ * @param embedder The view that is used for callbacks from ImeAdapter.
+ */
+ public ImeAdapter(Context context, SelectionHandleController selectionHandleController,
+ InsertionHandleController insertionHandleController, ViewEmbedder embedder) {
+ mContext = context;
+ mInputMethodManagerWrapper = new InputMethodManagerWrapper(context);
+ mSelectionHandleController = selectionHandleController;
+ mInsertionHandleController = insertionHandleController;
+ mViewEmbedder = embedder;
+ mHandler = new Handler();
+ }
+
+ public static class AdapterInputConnectionFactory {
+ public AdapterInputConnection get(View view, ImeAdapter imeAdapter,
+ EditorInfo outAttrs) {
+ return new AdapterInputConnection(view, imeAdapter, outAttrs);
+ }
+ }
+
+ @VisibleForTesting
+ protected void setInputMethodManagerWrapper(InputMethodManagerWrapper immw) {
+ mInputMethodManagerWrapper = immw;
+ }
+
+ /**
+ * Should be only used by AdapterInputConnection.
+ * @return InputMethodManagerWrapper that should receive all the calls directed to
+ * InputMethodManager.
+ */
+ InputMethodManagerWrapper getInputMethodManagerWrapper() {
+ return mInputMethodManagerWrapper;
+ }
+
+ /**
+ * Set the current active InputConnection when a new InputConnection is constructed.
+ * @param inputConnection The input connection that is currently used with IME.
+ */
+ void setInputConnection(AdapterInputConnection inputConnection) {
+ mInputConnection = inputConnection;
+ }
+
+ /**
+ * Should be only used by AdapterInputConnection.
+ * @return The input type of currently focused element.
+ */
+ int getTextInputType() {
+ return mTextInputType;
+ }
+
+ /**
+ * Should be only used by AdapterInputConnection.
+ * @return The starting index of the initial text selection.
+ */
+ int getInitialSelectionStart() {
+ return mInitialSelectionStart;
+ }
+
+ /**
+ * Should be only used by AdapterInputConnection.
+ * @return The ending index of the initial text selection.
+ */
+ int getInitialSelectionEnd() {
+ return mInitialSelectionEnd;
+ }
+
+ public static int getTextInputTypeNone() {
+ return sTextInputTypeNone;
+ }
+
+ private static int getModifiers(int metaState) {
+ int modifiers = 0;
+ if ((metaState & KeyEvent.META_SHIFT_ON) != 0) {
+ modifiers |= sModifierShift;
+ }
+ if ((metaState & KeyEvent.META_ALT_ON) != 0) {
+ modifiers |= sModifierAlt;
+ }
+ if ((metaState & KeyEvent.META_CTRL_ON) != 0) {
+ modifiers |= sModifierCtrl;
+ }
+ if ((metaState & KeyEvent.META_CAPS_LOCK_ON) != 0) {
+ modifiers |= sModifierCapsLockOn;
+ }
+ if ((metaState & KeyEvent.META_NUM_LOCK_ON) != 0) {
+ modifiers |= sModifierNumLockOn;
+ }
+ return modifiers;
+ }
+
+ void hideSelectionAndInsertionHandleControllers() {
+ mSelectionHandleController.hideAndDisallowAutomaticShowing();
+ mInsertionHandleController.hideAndDisallowAutomaticShowing();
+ }
+
+ public boolean isActive() {
+ return mInputConnection != null && mInputConnection.isActive();
+ }
+
+ private boolean isFor(int nativeImeAdapter, int textInputType) {
+ return mNativeImeAdapterAndroid == nativeImeAdapter &&
+ mTextInputType == textInputType;
+ }
+
+ public void attachAndShowIfNeeded(int nativeImeAdapter, int textInputType,
+ int selectionStart, int selectionEnd, boolean showIfNeeded) {
+ mHandler.removeCallbacks(mDismissInput);
+
+ // If current input type is none and showIfNeeded is false, IME should not be shown
+ // and input type should remain as none.
+ if (mTextInputType == sTextInputTypeNone && !showIfNeeded) {
+ return;
+ }
+
+ if (!isFor(nativeImeAdapter, textInputType)) {
+ // Set a delayed task to perform unfocus. This avoids hiding the keyboard when tabbing
+ // through text inputs or when JS rapidly changes focus to another text element.
+ if (textInputType == sTextInputTypeNone) {
+ mDismissInput = new DelayedDismissInput(nativeImeAdapter);
+ mHandler.postDelayed(mDismissInput, INPUT_DISMISS_DELAY);
+ return;
+ }
+
+ int previousType = mTextInputType;
+ attach(nativeImeAdapter, textInputType, selectionStart, selectionEnd);
+
+ mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView());
+ if (showIfNeeded) {
+ showKeyboard();
+ }
+ } else if (hasInputType() && showIfNeeded) {
+ showKeyboard();
+ }
+ }
+
+ public void attach(int nativeImeAdapter, int textInputType, int selectionStart,
+ int selectionEnd) {
+ mNativeImeAdapterAndroid = nativeImeAdapter;
+ mTextInputType = textInputType;
+ mInitialSelectionStart = selectionStart;
+ mInitialSelectionEnd = selectionEnd;
+ nativeAttachImeAdapter(mNativeImeAdapterAndroid);
+ }
+
+ /**
+ * Attaches the imeAdapter to its native counterpart. This is needed to start forwarding
+ * keyboard events to WebKit.
+ * @param nativeImeAdapter The pointer to the native ImeAdapter object.
+ */
+ public void attach(int nativeImeAdapter) {
+ mNativeImeAdapterAndroid = nativeImeAdapter;
+ if (nativeImeAdapter != 0) {
+ nativeAttachImeAdapter(mNativeImeAdapterAndroid);
+ }
+ }
+
+ /**
+ * Used to check whether the native counterpart of the ImeAdapter has been attached yet.
+ * @return Whether native ImeAdapter has been attached and its pointer is currently nonzero.
+ */
+ public boolean isNativeImeAdapterAttached() {
+ return mNativeImeAdapterAndroid != 0;
+ }
+
+ private void showKeyboard() {
+ mIsShowWithoutHideOutstanding = true;
+ mInputMethodManagerWrapper.showSoftInput(mViewEmbedder.getAttachedView(), 0,
+ mViewEmbedder.getNewShowKeyboardReceiver());
+ }
+
+ private void dismissInput(boolean unzoomIfNeeded) {
+ hideKeyboard(unzoomIfNeeded);
+ mViewEmbedder.onDismissInput();
+ }
+
+ private void hideKeyboard(boolean unzoomIfNeeded) {
+ mIsShowWithoutHideOutstanding = false;
+ View view = mViewEmbedder.getAttachedView();
+ if (mInputMethodManagerWrapper.isActive(view)) {
+ mInputMethodManagerWrapper.hideSoftInputFromWindow(view.getWindowToken(), 0,
+ unzoomIfNeeded ? mViewEmbedder.getNewShowKeyboardReceiver() : null);
+ }
+ }
+
+ private boolean hasInputType() {
+ return mTextInputType != sTextInputTypeNone;
+ }
+
+ static boolean isTextInputType(int type) {
+ return type != sTextInputTypeNone && !InputDialogContainer.isDialogInputType(type);
+ }
+
+ public boolean hasTextInputType() {
+ return isTextInputType(mTextInputType);
+ }
+
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ return translateAndSendNativeEvents(event);
+ }
+
+ private int shouldSendKeyEventWithKeyCode(String text) {
+ if (text.length() != 1) return COMPOSITION_KEY_CODE;
+
+ if (text.equals("\n")) return KeyEvent.KEYCODE_ENTER;
+ else if (text.equals("\t")) return KeyEvent.KEYCODE_TAB;
+ else return COMPOSITION_KEY_CODE;
+ }
+
+ void sendKeyEventWithKeyCode(int keyCode, int flags) {
+ long eventTime = System.currentTimeMillis();
+ translateAndSendNativeEvents(new KeyEvent(eventTime, eventTime,
+ KeyEvent.ACTION_DOWN, keyCode, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ flags));
+ translateAndSendNativeEvents(new KeyEvent(System.currentTimeMillis(), eventTime,
+ KeyEvent.ACTION_UP, keyCode, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ flags));
+ }
+
+ // Calls from Java to C++
+
+ @VisibleForTesting
+ boolean checkCompositionQueueAndCallNative(String text, int newCursorPosition,
+ boolean isCommit) {
+ if (mNativeImeAdapterAndroid == 0) return false;
+
+ // Committing an empty string finishes the current composition.
+ boolean isFinish = text.isEmpty();
+ if (!isFinish) {
+ mSelectionHandleController.hideAndDisallowAutomaticShowing();
+ mInsertionHandleController.hideAndDisallowAutomaticShowing();
+ }
+ mViewEmbedder.onImeEvent(isFinish);
+ int keyCode = shouldSendKeyEventWithKeyCode(text);
+ long timeStampMs = System.currentTimeMillis();
+
+ if (keyCode != COMPOSITION_KEY_CODE) {
+ sendKeyEventWithKeyCode(keyCode,
+ KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
+ } else {
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeRawKeyDown,
+ timeStampMs, keyCode, 0);
+ if (isCommit) {
+ nativeCommitText(mNativeImeAdapterAndroid, text);
+ } else {
+ nativeSetComposingText(mNativeImeAdapterAndroid, text, newCursorPosition);
+ }
+ nativeSendSyntheticKeyEvent(mNativeImeAdapterAndroid, sEventTypeKeyUp,
+ timeStampMs, keyCode, 0);
+ }
+
+ return true;
+ }
+
+ boolean translateAndSendNativeEvents(KeyEvent event) {
+ if (mNativeImeAdapterAndroid == 0) return false;
+
+ int action = event.getAction();
+ if (action != KeyEvent.ACTION_DOWN &&
+ action != KeyEvent.ACTION_UP) {
+ // action == KeyEvent.ACTION_MULTIPLE
+ // TODO(bulach): confirm the actual behavior. Apparently:
+ // If event.getKeyCode() == KEYCODE_UNKNOWN, we can send a
+ // composition key down (229) followed by a commit text with the
+ // string from event.getUnicodeChars().
+ // Otherwise, we'd need to send an event with a
+ // WebInputEvent::IsAutoRepeat modifier. We also need to verify when
+ // we receive ACTION_MULTIPLE: we may receive it after an ACTION_DOWN,
+ // and if that's the case, we'll need to review when to send the Char
+ // event.
+ return false;
+ }
+ mViewEmbedder.onImeEvent(false);
+ return nativeSendKeyEvent(mNativeImeAdapterAndroid, event, event.getAction(),
+ getModifiers(event.getMetaState()), event.getEventTime(), event.getKeyCode(),
+ event.isSystem(), event.getUnicodeChar());
+ }
+
+ boolean sendSyntheticKeyEvent(
+ int eventType, long timestampMs, int keyCode, int unicodeChar) {
+ if (mNativeImeAdapterAndroid == 0) return false;
+
+ nativeSendSyntheticKeyEvent(
+ mNativeImeAdapterAndroid, eventType, timestampMs, keyCode, unicodeChar);
+ return true;
+ }
+
+ boolean deleteSurroundingText(int leftLength, int rightLength) {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeDeleteSurroundingText(mNativeImeAdapterAndroid, leftLength, rightLength);
+ return true;
+ }
+
+ @VisibleForTesting
+ protected boolean setEditableSelectionOffsets(int start, int end) {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeSetEditableSelectionOffsets(mNativeImeAdapterAndroid, start, end);
+ return true;
+ }
+
+ void batchStateChanged(boolean isBegin) {
+ if (mNativeImeAdapterAndroid == 0) return;
+ nativeImeBatchStateChanged(mNativeImeAdapterAndroid, isBegin);
+ }
+
+ void commitText() {
+ cancelComposition();
+ if (mNativeImeAdapterAndroid != 0) {
+ nativeCommitText(mNativeImeAdapterAndroid, "");
+ }
+ }
+
+ /**
+ * Send a request to the native counterpart to set compositing region to given indices.
+ * @param start The start of the composition.
+ * @param end The end of the composition.
+ * @return Whether the native counterpart of ImeAdapter received the call.
+ */
+ boolean setComposingRegion(int start, int end) {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeSetComposingRegion(mNativeImeAdapterAndroid, start, end);
+ return true;
+ }
+
+ /**
+ * Send a request to the native counterpart to unselect text.
+ * @return Whether the native counterpart of ImeAdapter received the call.
+ */
+ public boolean unselect() {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeUnselect(mNativeImeAdapterAndroid);
+ return true;
+ }
+
+ /**
+ * Send a request to the native counterpart of ImeAdapter to select all the text.
+ * @return Whether the native counterpart of ImeAdapter received the call.
+ */
+ public boolean selectAll() {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeSelectAll(mNativeImeAdapterAndroid);
+ return true;
+ }
+
+ /**
+ * Send a request to the native counterpart of ImeAdapter to cut the selected text.
+ * @return Whether the native counterpart of ImeAdapter received the call.
+ */
+ public boolean cut() {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeCut(mNativeImeAdapterAndroid);
+ return true;
+ }
+
+ /**
+ * Send a request to the native counterpart of ImeAdapter to copy the selected text.
+ * @return Whether the native counterpart of ImeAdapter received the call.
+ */
+ public boolean copy() {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativeCopy(mNativeImeAdapterAndroid);
+ return true;
+ }
+
+ /**
+ * Send a request to the native counterpart of ImeAdapter to paste the text from the clipboard.
+ * @return Whether the native counterpart of ImeAdapter received the call.
+ */
+ public boolean paste() {
+ if (mNativeImeAdapterAndroid == 0) return false;
+ nativePaste(mNativeImeAdapterAndroid);
+ return true;
+ }
+
+ // Calls from C++ to Java
+
+ @CalledByNative
+ private static void initializeWebInputEvents(int eventTypeRawKeyDown, int eventTypeKeyUp,
+ int eventTypeChar, int modifierShift, int modifierAlt, int modifierCtrl,
+ int modifierCapsLockOn, int modifierNumLockOn) {
+ sEventTypeRawKeyDown = eventTypeRawKeyDown;
+ sEventTypeKeyUp = eventTypeKeyUp;
+ sEventTypeChar = eventTypeChar;
+ sModifierShift = modifierShift;
+ sModifierAlt = modifierAlt;
+ sModifierCtrl = modifierCtrl;
+ sModifierCapsLockOn = modifierCapsLockOn;
+ sModifierNumLockOn = modifierNumLockOn;
+ }
+
+ @CalledByNative
+ private static void initializeTextInputTypes(int textInputTypeNone, int textInputTypeText,
+ int textInputTypeTextArea, int textInputTypePassword, int textInputTypeSearch,
+ int textInputTypeUrl, int textInputTypeEmail, int textInputTypeTel,
+ int textInputTypeNumber, int textInputTypeDate, int textInputTypeDateTime,
+ int textInputTypeDateTimeLocal, int textInputTypeMonth, int textInputTypeTime,
+ int textInputTypeWeek, int textInputTypeContentEditable) {
+ sTextInputTypeNone = textInputTypeNone;
+ sTextInputTypeText = textInputTypeText;
+ sTextInputTypeTextArea = textInputTypeTextArea;
+ sTextInputTypePassword = textInputTypePassword;
+ sTextInputTypeSearch = textInputTypeSearch;
+ sTextInputTypeUrl = textInputTypeUrl;
+ sTextInputTypeEmail = textInputTypeEmail;
+ sTextInputTypeTel = textInputTypeTel;
+ sTextInputTypeNumber = textInputTypeNumber;
+ sTextInputTypeWeek = textInputTypeWeek;
+ sTextInputTypeContentEditable = textInputTypeContentEditable;
+ }
+
+ @CalledByNative
+ private void cancelComposition() {
+ if (mInputConnection != null) {
+ mInputConnection.restartInput();
+ }
+ }
+
+ @CalledByNative
+ void detach() {
+ mNativeImeAdapterAndroid = 0;
+ mTextInputType = 0;
+ }
+
+ private native boolean nativeSendSyntheticKeyEvent(int nativeImeAdapterAndroid,
+ int eventType, long timestampMs, int keyCode, int unicodeChar);
+
+ private native boolean nativeSendKeyEvent(int nativeImeAdapterAndroid, KeyEvent event,
+ int action, int modifiers, long timestampMs, int keyCode, boolean isSystemKey,
+ int unicodeChar);
+
+ private native void nativeSetComposingText(int nativeImeAdapterAndroid, String text,
+ int newCursorPosition);
+
+ private native void nativeCommitText(int nativeImeAdapterAndroid, String text);
+
+ private native void nativeAttachImeAdapter(int nativeImeAdapterAndroid);
+
+ private native void nativeSetEditableSelectionOffsets(int nativeImeAdapterAndroid,
+ int start, int end);
+
+ private native void nativeSetComposingRegion(int nativeImeAdapterAndroid, int start, int end);
+
+ private native void nativeDeleteSurroundingText(int nativeImeAdapterAndroid,
+ int before, int after);
+
+ private native void nativeImeBatchStateChanged(int nativeImeAdapterAndroid, boolean isBegin);
+
+ private native void nativeUnselect(int nativeImeAdapterAndroid);
+ private native void nativeSelectAll(int nativeImeAdapterAndroid);
+ private native void nativeCut(int nativeImeAdapterAndroid);
+ private native void nativeCopy(int nativeImeAdapterAndroid);
+ private native void nativePaste(int nativeImeAdapterAndroid);
+}
diff --git a/content/public/android/java/src/org/chromium/content/browser/InputDialogContainer.java b/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java
index 466665d..11189c5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/InputDialogContainer.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/InputDialogContainer.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
@@ -18,8 +18,8 @@ import android.text.format.Time;
import android.widget.DatePicker;
import android.widget.TimePicker;
-import org.chromium.content.browser.DateTimePickerDialog.OnDateTimeSetListener;
-import org.chromium.content.browser.MonthPickerDialog.OnMonthSetListener;
+import org.chromium.content.browser.input.DateTimePickerDialog.OnDateTimeSetListener;
+import org.chromium.content.browser.input.MonthPickerDialog.OnMonthSetListener;
import org.chromium.content.R;
import java.text.ParseException;
@@ -27,7 +27,7 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
-class InputDialogContainer {
+public class InputDialogContainer {
interface InputActionDelegate {
void cancelDateTimeDialog();
diff --git a/content/public/android/java/src/org/chromium/content/browser/InputMethodManagerWrapper.java b/content/public/android/java/src/org/chromium/content/browser/input/InputMethodManagerWrapper.java
index 572582e..34b8b4e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/InputMethodManagerWrapper.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/InputMethodManagerWrapper.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.content.Context;
import android.os.IBinder;
@@ -13,7 +13,7 @@ import android.view.inputmethod.InputMethodManager;
/**
* Wrapper around Android's InputMethodManager
*/
-public class InputMethodManagerWrapper {
+class InputMethodManagerWrapper {
private final Context mContext;
public InputMethodManagerWrapper(Context context) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/InsertionHandleController.java b/content/public/android/java/src/org/chromium/content/browser/input/InsertionHandleController.java
index 18fb7a4..e3ab838 100644
--- a/content/public/android/java/src/org/chromium/content/browser/InsertionHandleController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/InsertionHandleController.java
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.graphics.PointF;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -20,7 +19,7 @@ import android.widget.PopupWindow;
/**
* CursorController for inserting text at the cursor position.
*/
-abstract class InsertionHandleController implements CursorController {
+public abstract class InsertionHandleController implements CursorController {
/** The handle view, lazily created when first shown */
private HandleView mHandle;
@@ -36,18 +35,18 @@ abstract class InsertionHandleController implements CursorController {
private Context mContext;
- InsertionHandleController(View parent) {
+ public InsertionHandleController(View parent) {
mParent = parent;
mContext = parent.getContext();
}
/** Allows the handle to be shown automatically when cursor position changes */
- void allowAutomaticShowing() {
+ public void allowAutomaticShowing() {
mAllowAutomaticShowing = true;
}
/** Disallows the handle from being shown automatically when cursor position changes */
- void hideAndDisallowAutomaticShowing() {
+ public void hideAndDisallowAutomaticShowing() {
hide();
mAllowAutomaticShowing = false;
}
@@ -55,7 +54,7 @@ abstract class InsertionHandleController implements CursorController {
/**
* Shows the handle.
*/
- void showHandle() {
+ public void showHandle() {
createHandleIfNeeded();
showHandleIfNeeded();
}
@@ -66,13 +65,13 @@ abstract class InsertionHandleController implements CursorController {
}
}
- void showHandleWithPastePopup() {
+ public void showHandleWithPastePopup() {
showHandle();
showPastePopup();
}
/** Shows the handle at the given coordinates, as long as automatic showing is allowed */
- void onCursorPositionChanged() {
+ public void onCursorPositionChanged() {
if (mAllowAutomaticShowing) {
showHandle();
}
@@ -83,25 +82,21 @@ abstract class InsertionHandleController implements CursorController {
* @param x Handle x in physical pixels.
* @param y Handle y in physical pixels.
*/
- void setHandlePosition(int x, int y) {
- mHandle.positionAt(x, y);
- }
-
- void setHandlePosition(float x, float y) {
- setHandlePosition((int) x, (int) y);
+ public void setHandlePosition(float x, float y) {
+ mHandle.positionAt((int) x, (int) y);
}
/**
* If the handle is not visible, sets its visibility to View.VISIBLE and begins fading it in.
*/
- void beginHandleFadeIn() {
+ public void beginHandleFadeIn() {
mHandle.beginFadeIn();
}
/**
* Sets the handle to the given visibility.
*/
- void setHandleVisibility(int visibility) {
+ public void setHandleVisibility(int visibility) {
mHandle.setVisibility(visibility);
}
diff --git a/content/public/android/java/src/org/chromium/content/browser/MonthPicker.java b/content/public/android/java/src/org/chromium/content/browser/input/MonthPicker.java
index 5c425d7..01e636e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/MonthPicker.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/MonthPicker.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.content.Context;
import android.content.res.Configuration;
diff --git a/content/public/android/java/src/org/chromium/content/browser/MonthPickerDialog.java b/content/public/android/java/src/org/chromium/content/browser/input/MonthPickerDialog.java
index cf8c770..354810e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/MonthPickerDialog.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/MonthPickerDialog.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.app.AlertDialog;
import android.content.Context;
@@ -12,7 +12,7 @@ import android.os.Build;
import android.os.Bundle;
import android.view.View;
-import org.chromium.content.browser.MonthPicker.OnMonthChangedListener;
+import org.chromium.content.browser.input.MonthPicker.OnMonthChangedListener;
import org.chromium.content.R;
public class MonthPickerDialog extends AlertDialog implements OnClickListener,
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectPopupDialog.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java
index b5d00a5..d32266b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectPopupDialog.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopupDialog.java
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
+
+import org.chromium.content.browser.ContentViewCore;
import android.app.AlertDialog;
import android.content.DialogInterface;
@@ -18,7 +20,7 @@ import android.widget.ListView;
/**
* Handles the popup dialog for the <select> HTML tag support.
*/
-class SelectPopupDialog {
+public class SelectPopupDialog {
// The currently showing popup dialog, null if none is showing.
private static SelectPopupDialog sShownDialog;
@@ -211,7 +213,7 @@ class SelectPopupDialog {
}
// The methods below are used by tests.
- static SelectPopupDialog getCurrent() {
+ public static SelectPopupDialog getCurrent() {
return sShownDialog;
}
}
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionHandleController.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectionHandleController.java
index 8c5a969..f65c6a5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectionHandleController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectionHandleController.java
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
-import android.graphics.PointF;
import android.view.View;
/**
* CursorController for selecting a range of text.
*/
-abstract class SelectionHandleController implements CursorController {
+public abstract class SelectionHandleController implements CursorController {
// The following constants match the ones in
// third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h
@@ -32,17 +31,17 @@ abstract class SelectionHandleController implements CursorController {
private int mFixedHandleX;
private int mFixedHandleY;
- SelectionHandleController(View parent) {
+ public SelectionHandleController(View parent) {
mParent = parent;
}
/** Automatically show selection anchors when text is selected. */
- void allowAutomaticShowing() {
+ public void allowAutomaticShowing() {
mAllowAutomaticShowing = true;
}
/** Hide selection anchors, and don't automatically show them. */
- void hideAndDisallowAutomaticShowing() {
+ public void hideAndDisallowAutomaticShowing() {
hide();
mAllowAutomaticShowing = false;
}
@@ -101,7 +100,7 @@ abstract class SelectionHandleController implements CursorController {
/**
* @return true iff this controller is being used to drag either the selection start or end.
*/
- boolean isDragging() {
+ public boolean isDragging() {
return (mStartHandle != null && mStartHandle.isDragging()) ||
(mEndHandle != null && mEndHandle.isDragging());
}
@@ -121,26 +120,8 @@ abstract class SelectionHandleController implements CursorController {
* @param x The start handle position X in physical pixels.
* @param y The start handle position Y in physical pixels.
*/
- void setStartHandlePosition(int x, int y) {
- mStartHandle.positionAt(x, y);
- }
-
- /**
- * Moves the start handle so that it points at the given coordinates.
- * @param x The start handle position X in physical pixels.
- * @param y The start handle position Y in physical pixels.
- */
- void setStartHandlePosition(float x, float y) {
- setStartHandlePosition((int) x, (int) y);
- }
-
- /**
- * Moves the end handle so that it points at the given coordinates.
- * @param x The end handle position X in physical pixels.
- * @param y The end handle position Y in physical pixels.
- */
- void setEndHandlePosition(int x, int y) {
- mEndHandle.positionAt(x, y);
+ public void setStartHandlePosition(float x, float y) {
+ mStartHandle.positionAt((int) x, (int) y);
}
/**
@@ -148,15 +129,15 @@ abstract class SelectionHandleController implements CursorController {
* @param x The end handle position X in physical pixels.
* @param y The end handle position Y in physical pixels.
*/
- void setEndHandlePosition(float x, float y) {
- setEndHandlePosition((int) x, (int) y);
+ public void setEndHandlePosition(float x, float y) {
+ mEndHandle.positionAt((int) x, (int) y);
}
/**
* If the handles are not visible, sets their visibility to View.VISIBLE and begins fading them
* in.
*/
- void beginHandleFadeIn() {
+ public void beginHandleFadeIn() {
mStartHandle.beginFadeIn();
mEndHandle.beginFadeIn();
}
@@ -164,7 +145,7 @@ abstract class SelectionHandleController implements CursorController {
/**
* Sets the start and end handles to the given visibility.
*/
- void setHandleVisibility(int visibility) {
+ public void setHandleVisibility(int visibility) {
mStartHandle.setVisibility(visibility);
mEndHandle.setVisibility(visibility);
}
@@ -175,7 +156,7 @@ abstract class SelectionHandleController implements CursorController {
* @param startDir Direction (left/right) of start handle.
* @param endDir Direction (left/right) of end handle.
*/
- void onSelectionChanged(int startDir, int endDir) {
+ public void onSelectionChanged(int startDir, int endDir) {
if (mAllowAutomaticShowing) {
showHandles(startDir, endDir);
}
@@ -189,7 +170,7 @@ abstract class SelectionHandleController implements CursorController {
* @param startDir Direction (left/right) of start handle.
* @param endDir Direction (left/right) of end handle.
*/
- void showHandles(int startDir, int endDir) {
+ public void showHandles(int startDir, int endDir) {
createHandlesIfNeeded(startDir, endDir);
showHandlesIfNeeded();
}
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index 76d23e7..a49cddb 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.app.Activity;
import android.content.ClipData;
@@ -20,7 +20,8 @@ import android.view.inputmethod.InputConnection;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
-import org.chromium.content.browser.ImeAdapter.AdapterInputConnection;
+import org.chromium.content.browser.ContentView;
+import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.DOMUtils;
@@ -31,8 +32,6 @@ import java.util.concurrent.Callable;
public class ImeTest extends ContentShellTestBase {
- private static final int INVALID_SELECTION = -2;
- private static final int INVALID_COMPOSITION = -2;
private static final String DATA_URL = UrlUtils.encodeHtmlDataUri(
"<html><head><meta name=\"viewport\"" +
"content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>" +
@@ -406,7 +405,7 @@ public class ImeTest extends ContentShellTestBase {
return getContentViewCore().getImeAdapterForTest();
}
- private ImeAdapter.AdapterInputConnection getAdapterInputConnection() {
+ private AdapterInputConnection getAdapterInputConnection() {
return getContentViewCore().getInputConnectionForTest();
}
@@ -419,7 +418,7 @@ public class ImeTest extends ContentShellTestBase {
}
}
- private static class TestAdapterInputConnection extends ImeAdapter.AdapterInputConnection {
+ private static class TestAdapterInputConnection extends AdapterInputConnection {
private int mSetEditableTextCallCounter = 0;
private int mUpdateSelectionCounter = 0;
private String mText;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InsertionHandleTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java
index 4f519f0..42ee232 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/InsertionHandleTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/InsertionHandleTest.java
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -14,6 +14,8 @@ import android.text.Selection;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
+import org.chromium.content.browser.ContentView;
+import org.chromium.content.browser.RenderCoordinates;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.DOMUtils;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/SelectPopupTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
index 81e03c1..7e65a25 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/SelectPopupTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
import android.test.suitebuilder.annotation.LargeTest;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.UrlUtils;
+import org.chromium.content.browser.ContentView;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.DOMUtils;