summaryrefslogtreecommitdiffstats
path: root/core/java/android/inputmethodservice
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:33 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:33 -0800
commit3dec7d563a2f3e1eb967ce2054a00b6620e3558c (patch)
treeaa3b0365c47cb3c1607c0dc76c8d32b4046fc287 /core/java/android/inputmethodservice
parent15ab3eae2ec3d73b3e8aa60b33ae41445bf83f4b (diff)
downloadframeworks_base-3dec7d563a2f3e1eb967ce2054a00b6620e3558c.zip
frameworks_base-3dec7d563a2f3e1eb967ce2054a00b6620e3558c.tar.gz
frameworks_base-3dec7d563a2f3e1eb967ce2054a00b6620e3558c.tar.bz2
auto import from //depot/cupcake/@137055
Diffstat (limited to 'core/java/android/inputmethodservice')
-rw-r--r--core/java/android/inputmethodservice/ExtractEditText.java7
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java266
-rwxr-xr-xcore/java/android/inputmethodservice/KeyboardView.java22
3 files changed, 278 insertions, 17 deletions
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 52f8209..0295f69 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -98,6 +98,13 @@ public class ExtractEditText extends EditText {
}
/**
+ * Return true if the edit text is currently showing a scroll bar.
+ */
+ public boolean hasVerticalScrollBar() {
+ return computeVerticalScrollRange() > computeVerticalScrollExtent();
+ }
+
+ /**
* Pretend like the window this view is in always has focus, so its
* highlight and cursor will be displayed.
*/
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 4be1fc7..1e2e2f3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -26,7 +26,9 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.SystemClock;
import android.provider.Settings;
+import android.text.InputType;
import android.text.Layout;
import android.text.Spannable;
import android.text.method.MovementMethod;
@@ -49,6 +51,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
import android.widget.FrameLayout;
import java.io.FileDescriptor;
@@ -241,6 +244,8 @@ public class InputMethodService extends AbstractInputMethodService {
boolean mIsFullscreen;
View mExtractView;
ExtractEditText mExtractEditText;
+ ViewGroup mExtractAccessories;
+ Button mExtractAction;
ExtractedText mExtractedText;
int mExtractedToken;
@@ -271,6 +276,21 @@ public class InputMethodService extends AbstractInputMethodService {
}
};
+ final View.OnClickListener mActionClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ final EditorInfo ei = getCurrentInputEditorInfo();
+ final InputConnection ic = getCurrentInputConnection();
+ if (ei != null && ic != null) {
+ if (ei.actionId != 0) {
+ ic.performEditorAction(ei.actionId);
+ } else if ((ei.imeOptions&EditorInfo.IME_MASK_ACTION)
+ != EditorInfo.IME_ACTION_NONE) {
+ ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
+ }
+ }
+ }
+ };
+
/**
* Concrete implementation of
* {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides
@@ -522,6 +542,8 @@ public class InputMethodService extends AbstractInputMethodService {
mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea);
mExtractView = null;
mExtractEditText = null;
+ mExtractAccessories = null;
+ mExtractAction = null;
mFullscreenApplied = false;
mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea);
@@ -703,7 +725,7 @@ public class InputMethodService extends AbstractInputMethodService {
setExtractView(v);
}
}
- startExtractingText();
+ startExtractingText(false);
}
}
@@ -907,9 +929,17 @@ public class InputMethodService extends AbstractInputMethodService {
mExtractEditText = (ExtractEditText)view.findViewById(
com.android.internal.R.id.inputExtractEditText);
mExtractEditText.setIME(this);
- startExtractingText();
+ mExtractAction = (Button)view.findViewById(
+ com.android.internal.R.id.inputExtractAction);
+ if (mExtractAction != null) {
+ mExtractAccessories = (ViewGroup)view.findViewById(
+ com.android.internal.R.id.inputExtractAccessories);
+ }
+ startExtractingText(false);
} else {
mExtractEditText = null;
+ mExtractAccessories = null;
+ mExtractAction = null;
}
}
@@ -1166,7 +1196,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
if (doShowInput) {
- startExtractingText();
+ startExtractingText(false);
}
if (!wasVisible) {
@@ -1276,7 +1306,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (DEBUG) Log.v(TAG, "CALL: onStartInputView");
mInputViewStarted = true;
onStartInputView(mInputEditorInfo, restarting);
- startExtractingText();
+ startExtractingText(true);
} else if (mCandidatesVisibility == View.VISIBLE) {
if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView");
mCandidatesViewStarted = true;
@@ -1453,6 +1483,25 @@ public class InputMethodService extends AbstractInputMethodService {
static final int MOVEMENT_DOWN = -1;
static final int MOVEMENT_UP = -2;
+ void reportExtractedMovement(int keyCode, int count) {
+ int dx = 0, dy = 0;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ dx = -count;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ dx = count;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ dy = -count;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ dy = count;
+ break;
+ }
+ onExtractedCursorMovement(dx, dy);
+ }
+
boolean doMovementKey(int keyCode, KeyEvent event, int count) {
final ExtractEditText eet = mExtractEditText;
if (isFullscreenMode() && isInputViewShown() && eet != null) {
@@ -1467,6 +1516,7 @@ public class InputMethodService extends AbstractInputMethodService {
if (count == MOVEMENT_DOWN) {
if (movement.onKeyDown(eet,
(Spannable)eet.getText(), keyCode, event)) {
+ reportExtractedMovement(keyCode, 1);
return true;
}
} else if (count == MOVEMENT_UP) {
@@ -1475,7 +1525,9 @@ public class InputMethodService extends AbstractInputMethodService {
return true;
}
} else {
- if (!movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+ if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) {
+ reportExtractedMovement(keyCode, count);
+ } else {
KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN);
if (movement.onKeyDown(eet,
(Spannable)eet.getText(), keyCode, down)) {
@@ -1488,6 +1540,7 @@ public class InputMethodService extends AbstractInputMethodService {
movement.onKeyUp(eet,
(Spannable)eet.getText(), keyCode, up);
}
+ reportExtractedMovement(keyCode, count);
}
}
}
@@ -1507,6 +1560,97 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Send the given key event code (as defined by {@link KeyEvent}) to the
+ * current input connection is a key down + key up event pair. The sent
+ * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD}
+ * set, so that the recipient can identify them as coming from a software
+ * input method, and
+ * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so
+ * that they don't impact the current touch mode of the UI.
+ *
+ * @param keyEventCode The raw key code to send, as defined by
+ * {@link KeyEvent}.
+ */
+ public void sendDownUpKeyEvents(int keyEventCode) {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic == null) return;
+ long eventTime = SystemClock.uptimeMillis();
+ ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
+ KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
+ ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
+ KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
+ }
+
+ /**
+ * Ask the input target to execute its default action via
+ * {@link InputConnection#performEditorAction
+ * InputConnection.performEditorAction()}.
+ *
+ * @param fromEnterKey If true, this will be executed as if the user had
+ * pressed an enter key on the keyboard, that is it will <em>not</em>
+ * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION
+ * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be
+ * sent regardless of how the editor has set that flag.
+ *
+ * @return Returns a boolean indicating whether an action has been sent.
+ * If false, either the editor did not specify a default action or it
+ * does not want an action from the enter key. If true, the action was
+ * sent (or there was no input connection at all).
+ */
+ public boolean sendDefaultEditorAction(boolean fromEnterKey) {
+ EditorInfo ei = getCurrentInputEditorInfo();
+ if (ei != null &&
+ (!fromEnterKey || (ei.imeOptions &
+ EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) &&
+ (ei.imeOptions & EditorInfo.IME_MASK_ACTION) !=
+ EditorInfo.IME_ACTION_NONE) {
+ // If the enter key was pressed, and the editor has a default
+ // action associated with pressing enter, then send it that
+ // explicit action instead of the key event.
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Send the given UTF-16 character to the current input connection. Most
+ * characters will be delivered simply by calling
+ * {@link InputConnection#commitText InputConnection.commitText()} with
+ * the character; some, however, may be handled different. In particular,
+ * the enter character ('\n') will either be delivered as an action code
+ * or a raw key event, as appropriate.
+ *
+ * @param charCode The UTF-16 character code to send.
+ */
+ public void sendKeyChar(char charCode) {
+ switch (charCode) {
+ case '\n': // Apps may be listening to an enter key to perform an action
+ if (!sendDefaultEditorAction(true)) {
+ sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER);
+ }
+ break;
+ default:
+ // Make sure that digits go through any text watcher on the client side.
+ if (charCode >= '0' && charCode <= '9') {
+ sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0);
+ } else {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.commitText(String.valueOf((char) charCode), 1);
+ }
+ }
+ break;
+ }
+ }
+
+ /**
* This is called when the user has moved the cursor in the extracted
* text view, when running in fullsreen mode. The default implementation
* performs the corresponding selection change on the underlying text
@@ -1522,11 +1666,36 @@ public class InputMethodService extends AbstractInputMethodService {
/**
* This is called when the user has clicked on the extracted text view,
* when running in fullscreen mode. The default implementation hides
- * the candidates view when this happens. Re-implement this to provide
- * whatever behavior you want.
+ * the candidates view when this happens, but only if the extracted text
+ * editor has a vertical scroll bar because its text doesn't fit.
+ * Re-implement this to provide whatever behavior you want.
*/
public void onExtractedTextClicked() {
- setCandidatesViewShown(false);
+ if (mExtractEditText == null) {
+ return;
+ }
+ if (mExtractEditText.hasVerticalScrollBar()) {
+ setCandidatesViewShown(false);
+ }
+ }
+
+ /**
+ * This is called when the user has performed a cursor movement in the
+ * extracted text view, when it is running in fullscreen mode. The default
+ * implementation hides the candidates view when a vertical movement
+ * happens, but only if the extracted text editor has a vertical scroll bar
+ * because its text doesn't fit.
+ * Re-implement this to provide whatever behavior you want.
+ * @param dx The amount of cursor movement in the x dimension.
+ * @param dy The amount of cursor movement in the y dimension.
+ */
+ public void onExtractedCursorMovement(int dx, int dy) {
+ if (mExtractEditText == null || dy == 0) {
+ return;
+ }
+ if (mExtractEditText.hasVerticalScrollBar()) {
+ setCandidatesViewShown(false);
+ }
}
/**
@@ -1545,7 +1714,74 @@ public class InputMethodService extends AbstractInputMethodService {
return true;
}
- void startExtractingText() {
+ /**
+ * Return text that can be used as a button label for the given
+ * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null
+ * if there is no action requested. Note that there is no guarantee that
+ * the returned text will be relatively short, so you probably do not
+ * want to use it as text on a soft keyboard key label.
+ *
+ * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}.
+ *
+ * @return Returns a label to use, or null if there is no action.
+ */
+ public CharSequence getTextForImeAction(int imeOptions) {
+ switch (imeOptions&EditorInfo.IME_MASK_ACTION) {
+ case EditorInfo.IME_ACTION_NONE:
+ return null;
+ case EditorInfo.IME_ACTION_GO:
+ return getText(com.android.internal.R.string.ime_action_go);
+ case EditorInfo.IME_ACTION_SEARCH:
+ return getText(com.android.internal.R.string.ime_action_search);
+ case EditorInfo.IME_ACTION_SEND:
+ return getText(com.android.internal.R.string.ime_action_send);
+ case EditorInfo.IME_ACTION_NEXT:
+ return getText(com.android.internal.R.string.ime_action_next);
+ default:
+ return getText(com.android.internal.R.string.ime_action_default);
+ }
+ }
+
+ /**
+ * Called when it is time to update the actions available from a full-screen
+ * IME. You do not need to deal with this if you are using the standard
+ * full screen extract UI. If replacing it, you will need to re-implement
+ * this to put the action in your own UI and handle it.
+ */
+ public void onUpdateExtractingAccessories(EditorInfo ei) {
+ if (mExtractAccessories == null) {
+ return;
+ }
+ final boolean hasAction = ei.actionLabel != null || (
+ (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE &&
+ (ei.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0);
+ if (hasAction) {
+ mExtractAccessories.setVisibility(View.VISIBLE);
+ if (ei.actionLabel != null) {
+ mExtractAction.setText(ei.actionLabel);
+ } else {
+ mExtractAction.setText(getTextForImeAction(ei.imeOptions));
+ }
+ mExtractAction.setOnClickListener(mActionClickListener);
+ } else {
+ mExtractAccessories.setVisibility(View.GONE);
+ mExtractAction.setOnClickListener(null);
+ }
+ }
+
+ /**
+ * This is called when, while currently displayed in extract mode, the
+ * current input target changes. The default implementation will
+ * auto-hide the IME if the new target is not a full editor, since this
+ * can be an confusing experience for the user.
+ */
+ public void onExtractingInputChanged(EditorInfo ei) {
+ if (ei.inputType == InputType.TYPE_NULL) {
+ dismissSoftInput(InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ }
+
+ void startExtractingText(boolean inputChanged) {
final ExtractEditText eet = mExtractEditText;
if (eet != null && getCurrentInputStarted()
&& isFullscreenMode()) {
@@ -1557,9 +1793,13 @@ public class InputMethodService extends AbstractInputMethodService {
req.hintMaxChars = 10000;
mExtractedText = getCurrentInputConnection().getExtractedText(req,
InputConnection.GET_EXTRACTED_TEXT_MONITOR);
+
+ final EditorInfo ei = getCurrentInputEditorInfo();
+
try {
eet.startInternalChanges();
- int inputType = getCurrentInputEditorInfo().inputType;
+ onUpdateExtractingAccessories(ei);
+ int inputType = ei.inputType;
if ((inputType&EditorInfo.TYPE_MASK_CLASS)
== EditorInfo.TYPE_CLASS_TEXT) {
if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) {
@@ -1567,7 +1807,7 @@ public class InputMethodService extends AbstractInputMethodService {
}
}
eet.setInputType(inputType);
- eet.setHint(mInputEditorInfo.hintText);
+ eet.setHint(ei.hintText);
if (mExtractedText != null) {
eet.setEnabled(true);
eet.setExtractedText(mExtractedText);
@@ -1578,6 +1818,10 @@ public class InputMethodService extends AbstractInputMethodService {
} finally {
eet.finishInternalChanges();
}
+
+ if (inputChanged) {
+ onExtractingInputChanged(ei);
+ }
}
}
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 886e688..c838779 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -74,7 +74,6 @@ public class KeyboardView extends View implements View.OnClickListener {
* For keys that repeat, this is only called once.
* @param primaryCode the unicode of the key being pressed. If the touch is not on a valid
* key, the value will be zero.
- * @hide Pending API Council approval
*/
void onPress(int primaryCode);
@@ -82,7 +81,6 @@ public class KeyboardView extends View implements View.OnClickListener {
* Called when the user releases a key. This is sent after the {@link #onKey} is called.
* For keys that repeat, this is only called once.
* @param primaryCode the code of the key that was released
- * @hide Pending API Council approval
*/
void onRelease(int primaryCode);
@@ -99,6 +97,12 @@ public class KeyboardView extends View implements View.OnClickListener {
void onKey(int primaryCode, int[] keyCodes);
/**
+ * Sends a sequence of characters to the listener.
+ * @param text the sequence of characters to be displayed.
+ */
+ void onText(CharSequence text);
+
+ /**
* Called when the user quickly moves the finger from right to left.
*/
void swipeLeft();
@@ -394,6 +398,7 @@ public class KeyboardView extends View implements View.OnClickListener {
requestLayout();
invalidate();
computeProximityThreshold(keyboard);
+ mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
}
/**
@@ -699,9 +704,7 @@ public class KeyboardView extends View implements View.OnClickListener {
if (index != NOT_A_KEY && index < mKeys.length) {
final Key key = mKeys[index];
if (key.text != null) {
- for (int i = 0; i < key.text.length(); i++) {
- mKeyboardActionListener.onKey(key.text.charAt(i), key.codes);
- }
+ mKeyboardActionListener.onText(key.text);
mKeyboardActionListener.onRelease(NOT_A_KEY);
} else {
int code = key.codes[0];
@@ -792,7 +795,7 @@ public class KeyboardView extends View implements View.OnClickListener {
mPreviewText.setCompoundDrawables(null, null, null, null);
mPreviewText.setText(getPreviewText(key));
if (key.label.length() > 1 && key.codes.length < 2) {
- mPreviewText.setTextSize(mLabelTextSize);
+ mPreviewText.setTextSize(mKeyTextSize);
mPreviewText.setTypeface(Typeface.DEFAULT_BOLD);
} else {
mPreviewText.setTextSize(mPreviewTextSizeLarge);
@@ -896,6 +899,11 @@ public class KeyboardView extends View implements View.OnClickListener {
dismissPopupKeyboard();
}
+ public void onText(CharSequence text) {
+ mKeyboardActionListener.onText(text);
+ dismissPopupKeyboard();
+ }
+
public void swipeLeft() { }
public void swipeRight() { }
public void swipeUp() { }
@@ -1102,6 +1110,8 @@ public class KeyboardView extends View implements View.OnClickListener {
mHandler.removeMessages(MSG_SHOW_PREVIEW);
dismissPopupKeyboard();
+
+ mMiniKeyboardCache.clear();
}
@Override