diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:44:00 -0800 |
commit | d24b8183b93e781080b2c16c487e60d51c12da31 (patch) | |
tree | fbb89154858984eb8e41556da7e9433040d55cd4 /core/java/android/view/inputmethod | |
parent | f1e484acb594a726fb57ad0ae4cfe902c7f35858 (diff) | |
download | frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.zip frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.gz frameworks_base-d24b8183b93e781080b2c16c487e60d51c12da31.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'core/java/android/view/inputmethod')
10 files changed, 761 insertions, 543 deletions
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index a6ce293..56c6c92 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -17,35 +17,365 @@ package android.view.inputmethod; import android.content.Context; +import android.content.res.TypedArray; +import android.os.Bundle; import android.os.Handler; -import android.os.Message; +import android.os.SystemClock; +import android.text.Editable; +import android.text.NoCopySpan; +import android.text.Selection; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.MetaKeyKeyListener; +import android.util.Log; +import android.util.LogPrinter; +import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.View; import android.view.ViewRoot; +class ComposingText implements NoCopySpan { +} + /** * Base class for implementors of the InputConnection interface, taking care - * of implementing common system-oriented parts of the functionality. + * of most of the common behavior for providing a connection to an Editable. + * Implementors of this class will want to be sure to implement + * {@link #getEditable} to provide access to their own editable object. */ -public abstract class BaseInputConnection implements InputConnection { +public class BaseInputConnection implements InputConnection { + private static final boolean DEBUG = false; + private static final String TAG = "BaseInputConnection"; + static final Object COMPOSING = new ComposingText(); + final InputMethodManager mIMM; final Handler mH; final View mTargetView; + final boolean mDummyMode; + + private Object[] mDefaultComposingSpans; + + Editable mEditable; + KeyCharacterMap mKeyCharacterMap; - BaseInputConnection(InputMethodManager mgr) { + BaseInputConnection(InputMethodManager mgr, boolean dummyMode) { mIMM = mgr; mTargetView = null; mH = null; + mDummyMode = dummyMode; } - public BaseInputConnection(View targetView) { + public BaseInputConnection(View targetView, boolean dummyMode) { mIMM = (InputMethodManager)targetView.getContext().getSystemService( Context.INPUT_METHOD_SERVICE); mH = targetView.getHandler(); mTargetView = targetView; + mDummyMode = dummyMode; + } + + public static final void removeComposingSpans(Spannable text) { + text.removeSpan(COMPOSING); + Object[] sps = text.getSpans(0, text.length(), Object.class); + if (sps != null) { + for (int i=sps.length-1; i>=0; i--) { + Object o = sps[i]; + if ((text.getSpanFlags(o)&Spanned.SPAN_COMPOSING) != 0) { + text.removeSpan(o); + } + } + } + } + + public static void setComposingSpans(Spannable text) { + final Object[] sps = text.getSpans(0, text.length(), Object.class); + if (sps != null) { + for (int i=sps.length-1; i>=0; i--) { + final Object o = sps[i]; + if (o == COMPOSING) { + text.removeSpan(o); + continue; + } + final int fl = text.getSpanFlags(o); + if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK)) + != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) { + text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o), + (fl&Spanned.SPAN_POINT_MARK_MASK) + | Spanned.SPAN_COMPOSING + | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + + text.setSpan(COMPOSING, 0, text.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING); + } + + public static int getComposingSpanStart(Spannable text) { + return text.getSpanStart(COMPOSING); + } + + public static int getComposingSpanEnd(Spannable text) { + return text.getSpanEnd(COMPOSING); + } + + /** + * Return the target of edit operations. The default implementation + * returns its own fake editable that is just used for composing text; + * subclasses that are real text editors should override this and + * supply their own. + */ + public Editable getEditable() { + if (mEditable == null) { + mEditable = Editable.Factory.getInstance().newEditable(""); + Selection.setSelection(mEditable, 0); + } + return mEditable; } /** + * Default implementation does nothing. + */ + public boolean beginBatchEdit() { + return false; + } + + /** + * Default implementation does nothing. + */ + public boolean endBatchEdit() { + return false; + } + + /** + * Default implementation uses + * {@link MetaKeyKeyListener#clearMetaKeyState(long, int) + * MetaKeyKeyListener.clearMetaKeyState(long, int)} to clear the state. + */ + public boolean clearMetaKeyStates(int states) { + final Editable content = getEditable(); + if (content == null) return false; + MetaKeyKeyListener.clearMetaKeyState(content, states); + return true; + } + + /** + * Default implementation does nothing. + */ + public boolean commitCompletion(CompletionInfo text) { + return false; + } + + /** + * Default implementation replaces any existing composing text with + * the given text. In addition, only if dummy mode, a key event is + * sent for the new text and the current editable buffer cleared. + */ + public boolean commitText(CharSequence text, int newCursorPosition) { + if (DEBUG) Log.v(TAG, "commitText " + text); + replaceText(text, newCursorPosition, false); + sendCurrentText(); + return true; + } + + /** + * The default implementation performs the deletion around the current + * selection position of the editable text. + */ + public boolean deleteSurroundingText(int leftLength, int rightLength) { + if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength + + " / " + rightLength); + final Editable content = getEditable(); + if (content == null) return false; + + beginBatchEdit(); + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + // ignore the composing text. + int ca = getComposingSpanStart(content); + int cb = getComposingSpanEnd(content); + if (cb < ca) { + int tmp = ca; + ca = cb; + cb = tmp; + } + if (ca != -1 && cb != -1) { + if (ca < a) a = ca; + if (cb > b) b = cb; + } + + int deleted = 0; + + if (leftLength > 0) { + int start = a - leftLength; + if (start < 0) start = 0; + content.delete(start, a); + deleted = a - start; + } + + if (rightLength > 0) { + b = b - deleted; + + int end = b + rightLength; + if (end > content.length()) end = content.length(); + + content.delete(b, end); + } + + endBatchEdit(); + + return true; + } + + /** + * The default implementation removes the composing state from the + * current editable text. In addition, only if dummy mode, a key event is + * sent for the new text and the current editable buffer cleared. + */ + public boolean finishComposingText() { + if (DEBUG) Log.v(TAG, "finishComposingText"); + final Editable content = getEditable(); + if (content != null) { + beginBatchEdit(); + removeComposingSpans(content); + endBatchEdit(); + sendCurrentText(); + } + return true; + } + + /** + * The default implementation uses TextUtils.getCapsMode to get the + * cursor caps mode for the current selection position in the editable + * text, unless in dummy mode in which case 0 is always returned. + */ + public int getCursorCapsMode(int reqModes) { + if (mDummyMode) return 0; + + final Editable content = getEditable(); + if (content == null) return 0; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + return TextUtils.getCapsMode(content, a, reqModes); + } + + /** + * The default implementation always returns null. + */ + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { + return null; + } + + /** + * The default implementation returns the given amount of text from the + * current cursor position in the buffer. + */ + public CharSequence getTextBeforeCursor(int length, int flags) { + final Editable content = getEditable(); + if (content == null) return null; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + if (length > a) { + length = a; + } + + if ((flags&GET_TEXT_WITH_STYLES) != 0) { + return content.subSequence(a - length, a); + } + return TextUtils.substring(content, a - length, a); + } + + /** + * The default implementation returns the given amount of text from the + * current cursor position in the buffer. + */ + public CharSequence getTextAfterCursor(int length, int flags) { + final Editable content = getEditable(); + if (content == null) return null; + + int a = Selection.getSelectionStart(content); + int b = Selection.getSelectionEnd(content); + + if (a > b) { + int tmp = a; + a = b; + b = tmp; + } + + if (b + length > content.length()) { + length = content.length() - b; + } + + + if ((flags&GET_TEXT_WITH_STYLES) != 0) { + return content.subSequence(b, b + length); + } + return TextUtils.substring(content, b, b + length); + } + + /** + * The default implementation does nothing. + */ + public boolean performContextMenuAction(int id) { + return false; + } + + /** + * The default implementation does nothing. + */ + public boolean performPrivateCommand(String action, Bundle data) { + return false; + } + + /** + * The default implementation places the given text into the editable, + * replacing any existing composing text. The new text is marked as + * in a composing state with the composing style. + */ + public boolean setComposingText(CharSequence text, int newCursorPosition) { + if (DEBUG) Log.v(TAG, "setComposingText " + text); + replaceText(text, newCursorPosition, true); + return true; + } + + /** + * The default implementation changes the selection position in the + * current editable text. + */ + public boolean setSelection(int start, int end) { + if (DEBUG) Log.v(TAG, "setSelection " + start + ", " + end); + final Editable content = getEditable(); + if (content == null) return false; + Selection.setSelection(content, start, end); + return true; + } + + /** * Provides standard implementation for sending a key event to the window * attached to the input connection's view. */ @@ -82,4 +412,144 @@ public abstract class BaseInputConnection implements InputConnection { mIMM.updateStatusIcon(resId, packageName); return true; } + + private void sendCurrentText() { + if (!mDummyMode) { + return; + } + + Editable content = getEditable(); + if (content != null) { + if (content.length() == 1) { + // If it's 1 character, we have a chance of being + // able to generate normal key events... + if (mKeyCharacterMap == null) { + mKeyCharacterMap = KeyCharacterMap.load( + KeyCharacterMap.BUILT_IN_KEYBOARD); + } + char[] chars = new char[1]; + content.getChars(0, 1, chars, 0); + KeyEvent[] events = mKeyCharacterMap.getEvents(chars); + if (events != null) { + for (int i=0; i<events.length; i++) { + if (DEBUG) Log.v(TAG, "Sending: " + events[i]); + sendKeyEvent(events[i]); + } + content.clear(); + return; + } + } + + // Otherwise, revert to the special key event containing + // the actual characters. + KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), + content.toString(), KeyCharacterMap.BUILT_IN_KEYBOARD, 0); + sendKeyEvent(event); + content.clear(); + } + } + + private void replaceText(CharSequence text, int newCursorPosition, + boolean composing) { + final Editable content = getEditable(); + if (content == null) { + return; + } + + beginBatchEdit(); + + // delete composing text set previously. + int a = getComposingSpanStart(content); + int b = getComposingSpanEnd(content); + + if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b); + + if (b < a) { + int tmp = a; + a = b; + b = tmp; + } + + if (a != -1 && b != -1) { + removeComposingSpans(content); + } else { + a = Selection.getSelectionStart(content); + b = Selection.getSelectionEnd(content); + if (a >=0 && b>= 0 && a != b) { + if (b < a) { + int tmp = a; + a = b; + b = tmp; + } + } + } + + if (composing) { + Spannable sp = null; + if (!(text instanceof Spannable)) { + sp = new SpannableStringBuilder(text); + text = sp; + if (mDefaultComposingSpans == null) { + Context context; + if (mTargetView != null) { + context = mTargetView.getContext(); + } else if (mIMM.mServedView != null) { + context = mIMM.mServedView.getContext(); + } else { + context = null; + } + if (context != null) { + TypedArray ta = context.getTheme() + .obtainStyledAttributes(new int[] { + com.android.internal.R.attr.candidatesTextStyleSpans + }); + CharSequence style = ta.getText(0); + ta.recycle(); + if (style != null && style instanceof Spanned) { + mDefaultComposingSpans = ((Spanned)style).getSpans( + 0, style.length(), Object.class); + } + } + } + if (mDefaultComposingSpans != null) { + for (int i = 0; i < mDefaultComposingSpans.length; ++i) { + sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } else { + sp = (Spannable)text; + } + setComposingSpans(sp); + } + + // Adjust newCursorPosition to be relative the start of the text. + newCursorPosition += a; + + if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \"" + + text + "\", composing=" + composing + + ", type=" + text.getClass().getCanonicalName()); + + if (DEBUG) { + LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG); + lp.println("Current text:"); + TextUtils.dumpSpans(content, lp, " "); + lp.println("Composing text:"); + TextUtils.dumpSpans(text, lp, " "); + } + + content.replace(a, b, text); + if (newCursorPosition < 0) newCursorPosition = 0; + if (newCursorPosition > content.length()) + newCursorPosition = content.length(); + Selection.setSelection(content, newCursorPosition); + + if (DEBUG) { + LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG); + lp.println("Final text:"); + TextUtils.dumpSpans(content, lp, " "); + } + + endBatchEdit(); + } } diff --git a/core/java/android/view/inputmethod/DefaultInputMethod.java b/core/java/android/view/inputmethod/DefaultInputMethod.java deleted file mode 100644 index 073b01c..0000000 --- a/core/java/android/view/inputmethod/DefaultInputMethod.java +++ /dev/null @@ -1,239 +0,0 @@ -package android.view.inputmethod; - -import android.graphics.Rect; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; - -import com.android.internal.view.IInputContext; -import com.android.internal.view.IInputMethod; -import com.android.internal.view.IInputMethodCallback; -import com.android.internal.view.IInputMethodSession; -import com.android.internal.view.InputConnectionWrapper; - -/** - * This is the default input method that runs in the same context of the - * application that requests text input. It does nothing but returns false for - * any key events, so that all key events will be processed by the key listener - * of the focused text box. - * {@hide} - */ -public class DefaultInputMethod implements InputMethod, InputMethodSession { - private static IInputMethod sInstance = new SimpleInputMethod( - new DefaultInputMethod()); - - private static InputMethodInfo sProperty = new InputMethodInfo( - "android.text.inputmethod", DefaultInputMethod.class.getName(), - "Default", "android.text.inputmethod.defaultImeSettings"); - - private InputConnection mInputConnection; - - public static IInputMethod getInstance() { - return sInstance; - } - - public static InputMethodInfo getMetaInfo() { - return sProperty; - } - - public void bindInput(InputBinding binding) { - mInputConnection = binding.getConnection(); - } - - public void unbindInput() { - } - - public void createSession(SessionCallback callback) { - callback.sessionCreated(this); - } - - public void setSessionEnabled(InputMethodSession session, boolean enabled) { - } - - public void revokeSession(InputMethodSession session) { - } - - public void finishInput() { - mInputConnection.hideStatusIcon(); - } - - public void displayCompletions(CompletionInfo[] completions) { - } - - public void updateExtractedText(int token, ExtractedText text) { - } - - public void updateSelection(int oldSelStart, int oldSelEnd, - int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) { - } - - public void updateCursor(Rect newCursor) { - } - - public void dispatchKeyEvent(int seq, KeyEvent event, EventCallback callback) { - callback.finishedEvent(seq, false); - } - - public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback) { - callback.finishedEvent(seq, false); - } - - public void restartInput(EditorInfo attribute) { - } - - public void attachToken(IBinder token) { - } - - public void startInput(EditorInfo attribute) { - mInputConnection - .showStatusIcon("android", com.android.internal.R.drawable.ime_qwerty); - } - - public void appPrivateCommand(String action, Bundle data) { - } - - public void hideSoftInput() { - } - - public void showSoftInput(int flags) { - } -} - -// ---------------------------------------------------------------------- - -class SimpleInputMethod extends IInputMethod.Stub { - final InputMethod mInputMethod; - - static class Session extends IInputMethodSession.Stub { - final InputMethodSession mSession; - - Session(InputMethodSession session) { - mSession = session; - } - - public void finishInput() { - mSession.finishInput(); - } - - public void updateSelection(int oldSelStart, int oldSelEnd, - int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) { - mSession.updateSelection(oldSelStart, oldSelEnd, - newSelStart, newSelEnd, candidatesStart, candidatesEnd); - } - - public void updateCursor(Rect newCursor) { - mSession.updateCursor(newCursor); - } - - static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback { - final IInputMethodCallback mCb; - InputMethodEventCallbackWrapper(IInputMethodCallback cb) { - mCb = cb; - } - public void finishedEvent(int seq, boolean handled) { - try { - mCb.finishedEvent(seq, handled); - } catch (RemoteException e) { - } - } - } - - public void dispatchKeyEvent(int seq, KeyEvent event, IInputMethodCallback callback) { - mSession.dispatchKeyEvent(seq, event, - new InputMethodEventCallbackWrapper(callback)); - } - - public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallback callback) { - mSession.dispatchTrackballEvent(seq, event, - new InputMethodEventCallbackWrapper(callback)); - } - - public void displayCompletions(CompletionInfo[] completions) { - mSession.displayCompletions(completions); - } - - public void updateExtractedText(int token, ExtractedText text) { - mSession.updateExtractedText(token, text); - } - - public void appPrivateCommand(String action, Bundle data) { - mSession.appPrivateCommand(action, data); - } - } - - public SimpleInputMethod(InputMethod inputMethod) { - mInputMethod = inputMethod; - } - - public InputMethod getInternalInputMethod() { - return mInputMethod; - } - - public void attachToken(IBinder token) { - mInputMethod.attachToken(token); - } - - public void bindInput(InputBinding binding) { - InputConnectionWrapper ic = new InputConnectionWrapper( - IInputContext.Stub.asInterface(binding.getConnectionToken())); - InputBinding nu = new InputBinding(ic, binding); - mInputMethod.bindInput(nu); - } - - public void unbindInput() { - mInputMethod.unbindInput(); - } - - public void restartInput(EditorInfo attribute) { - mInputMethod.restartInput(attribute); - } - - public void startInput(EditorInfo attribute) { - mInputMethod.startInput(attribute); - } - - static class InputMethodSessionCallbackWrapper implements InputMethod.SessionCallback { - final IInputMethodCallback mCb; - InputMethodSessionCallbackWrapper(IInputMethodCallback cb) { - mCb = cb; - } - - public void sessionCreated(InputMethodSession session) { - try { - mCb.sessionCreated(new Session(session)); - } catch (RemoteException e) { - } - } - } - - public void createSession(IInputMethodCallback callback) throws RemoteException { - mInputMethod.createSession(new InputMethodSessionCallbackWrapper(callback)); - } - - public void setSessionEnabled(IInputMethodSession session, boolean enabled) throws RemoteException { - try { - InputMethodSession ls = ((Session)session).mSession; - mInputMethod.setSessionEnabled(ls, enabled); - } catch (ClassCastException e) { - Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e); - } - } - - public void revokeSession(IInputMethodSession session) throws RemoteException { - try { - InputMethodSession ls = ((Session)session).mSession; - mInputMethod.revokeSession(ls); - } catch (ClassCastException e) { - Log.w("SimpleInputMethod", "Incoming session not of correct type: " + session, e); - } - } - - public void showSoftInput(boolean blah) { - } - - public void hideSoftInput() { - } -} diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index c050691..b2f26d7 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -5,6 +5,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.InputType; import android.text.TextUtils; +import android.util.Printer; /** * An EditorInfo describes several attributes of a text editing object @@ -21,7 +22,7 @@ public class EditorInfo implements InputType, Parcelable { * @see #TYPE_MASK_VARIATION * @see #TYPE_MASK_FLAGS */ - public int inputType = TYPE_CLASS_TEXT; + public int inputType = TYPE_NULL; /** * A string supplying additional information about the content type that @@ -71,6 +72,26 @@ public class EditorInfo implements InputType, Parcelable { public CharSequence label; /** + * Name of the package that owns this editor. + */ + public String packageName; + + /** + * Identifier for the editor's field. This is optional, and may be + * 0. By default it is filled in with the result of + * {@link android.view.View#getId() View.getId()} on the View that + * is being edited. + */ + public int fieldId; + + /** + * Additional name for the editor's field. This can supply additional + * name information for the field. By default it is null. The actual + * contents have no meaning. + */ + public String fieldName; + + /** * Any extra data to supply to the input method. This is for extended * communication with specific input methods; the name fields in the * bundle should be scoped (such as "com.mydomain.im.SOME_FIELD") so @@ -81,6 +102,24 @@ public class EditorInfo implements InputType, Parcelable { public Bundle extras; /** + * Write debug output of this object. + */ + public void dump(Printer pw, String prefix) { + pw.println(prefix + "inputType=0x" + Integer.toHexString(inputType) + + " privateContentType=" + privateContentType); + pw.println(prefix + "initialSelStart=" + initialSelStart + + " initialSelEnd=" + initialSelEnd + + " initialCapsMode=0x" + + Integer.toHexString(initialCapsMode)); + pw.println(prefix + "hintText=" + hintText + + " label=" + label); + pw.println(prefix + "packageName=" + packageName + + " fieldId=" + fieldId + + " fieldName=" + fieldName); + pw.println(prefix + "extras=" + extras); + } + + /** * Used to package this object into a {@link Parcel}. * * @param dest The {@link Parcel} to be written. @@ -94,6 +133,9 @@ public class EditorInfo implements InputType, Parcelable { dest.writeInt(initialCapsMode); TextUtils.writeToParcel(hintText, dest, flags); TextUtils.writeToParcel(label, dest, flags); + dest.writeString(packageName); + dest.writeInt(fieldId); + dest.writeString(fieldName); dest.writeBundle(extras); } @@ -110,6 +152,9 @@ public class EditorInfo implements InputType, Parcelable { res.initialCapsMode = source.readInt(); res.hintText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); res.label = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); + res.packageName = source.readString(); + res.fieldId = source.readInt(); + res.fieldName = source.readString(); res.extras = source.readBundle(); return res; } diff --git a/core/java/android/view/inputmethod/ExtractedText.java b/core/java/android/view/inputmethod/ExtractedText.java index 0ca3c79..e5d3cae 100644 --- a/core/java/android/view/inputmethod/ExtractedText.java +++ b/core/java/android/view/inputmethod/ExtractedText.java @@ -19,6 +19,22 @@ public class ExtractedText implements Parcelable { public int startOffset; /** + * If the content is a report of a partial text change, this is the + * offset where the change starts and it runs until + * {@link #partialEndOffset}. If the content is the full text, this + * field is -1. + */ + public int partialStartOffset; + + /** + * If the content is a report of a partial text change, this is the offset + * where the change ends. Note that the actual text may be larger or + * smaller than the difference between this and {@link #partialEndOffset}, + * meaning a reduction or increase, respectively, in the total text. + */ + public int partialEndOffset; + + /** * The offset where the selection currently starts within the extracted * text. The real selection start position is at * <var>startOffset</var>+<var>selectionStart</var>. @@ -52,6 +68,8 @@ public class ExtractedText implements Parcelable { public void writeToParcel(Parcel dest, int flags) { TextUtils.writeToParcel(text, dest, flags); dest.writeInt(startOffset); + dest.writeInt(partialStartOffset); + dest.writeInt(partialEndOffset); dest.writeInt(selectionStart); dest.writeInt(selectionEnd); dest.writeInt(flags); @@ -65,6 +83,8 @@ public class ExtractedText implements Parcelable { ExtractedText res = new ExtractedText(); res.text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); res.startOffset = source.readInt(); + res.partialStartOffset = source.readInt(); + res.partialEndOffset = source.readInt(); res.selectionStart = source.readInt(); res.selectionEnd = source.readInt(); res.flags = source.readInt(); diff --git a/core/java/android/view/inputmethod/ExtractedTextRequest.java b/core/java/android/view/inputmethod/ExtractedTextRequest.java index d962329..e84b094 100644 --- a/core/java/android/view/inputmethod/ExtractedTextRequest.java +++ b/core/java/android/view/inputmethod/ExtractedTextRequest.java @@ -16,6 +16,13 @@ public class ExtractedTextRequest implements Parcelable { public int token; /** + * Additional request flags, having the same possible values as the + * flags parameter of {@link InputConnection#getTextBeforeCursor + * InputConnection.getTextBeforeCursor()}. + */ + public int flags; + + /** * Hint for the maximum number of lines to return. */ public int hintMaxLines; @@ -33,6 +40,7 @@ public class ExtractedTextRequest implements Parcelable { */ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(token); + dest.writeInt(this.flags); dest.writeInt(hintMaxLines); dest.writeInt(hintMaxChars); } @@ -45,6 +53,7 @@ public class ExtractedTextRequest implements Parcelable { public ExtractedTextRequest createFromParcel(Parcel source) { ExtractedTextRequest res = new ExtractedTextRequest(); res.token = source.readInt(); + res.flags = source.readInt(); res.hintMaxLines = source.readInt(); res.hintMaxChars = source.readInt(); return res; diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java index bd7b050..8c30d3f 100644 --- a/core/java/android/view/inputmethod/InputConnection.java +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -32,6 +32,21 @@ import android.view.KeyEvent; */ public interface InputConnection { /** + * Flag for use with {@link #getTextAfterCursor} and + * {@link #getTextBeforeCursor} to have style information returned along + * with the text. If not set, you will receive only the raw text. If + * set, you may receive a complex CharSequence of both text and style + * spans. + */ + static final int GET_TEXT_WITH_STYLES = 0x0001; + + /** + * Flag for use with {@link #getExtractedText} to indicate you would + * like to receive updates when the extracted text changes. + */ + public static final int GET_EXTRACTED_TEXT_MONITOR = 0x0001; + + /** * Get <var>n</var> characters of text before the current cursor position. * * <p>This method may fail either if the input connection has become invalid @@ -40,11 +55,13 @@ public interface InputConnection { * In either case, a null is returned. * * @param n The expected length of the text. + * @param flags Supplies additional options controlling how the text is + * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}. * * @return Returns the text before the cursor position; the length of the * returned text might be less than <var>n</var>. */ - public CharSequence getTextBeforeCursor(int n); + public CharSequence getTextBeforeCursor(int n, int flags); /** * Get <var>n</var> characters of text after the current cursor position. @@ -55,11 +72,13 @@ public interface InputConnection { * In either case, a null is returned. * * @param n The expected length of the text. + * @param flags Supplies additional options controlling how the text is + * returned. May be either 0 or {@link #GET_TEXT_WITH_STYLES}. * * @return Returns the text after the cursor position; the length of the * returned text might be less than <var>n</var>. */ - public CharSequence getTextAfterCursor(int n); + public CharSequence getTextAfterCursor(int n, int flags); /** * Retrieve the current capitalization mode in effect at the current @@ -82,8 +101,6 @@ public interface InputConnection { */ public int getCursorCapsMode(int reqModes); - public static final int EXTRACTED_TEXT_MONITOR = 0x0001; - /** * Retrieve the current text in the input connection's editor, and monitor * for any changes to it. This function returns with the current text, @@ -97,7 +114,7 @@ public interface InputConnection { * * @param request Description of how the text should be returned. * @param flags Additional options to control the client, either 0 or - * {@link #EXTRACTED_TEXT_MONITOR}. + * {@link #GET_EXTRACTED_TEXT_MONITOR}. * * @return Returns an ExtractedText object describing the state of the * text view and containing the extracted text itself. @@ -141,7 +158,7 @@ public interface InputConnection { /** * Have the text editor finish whatever composing text is currently - * active. This simple leaves the text as-is, removing any special + * active. This simply leaves the text as-is, removing any special * composing styling or other state that was around it. The cursor * position remains unchanged. */ @@ -177,6 +194,22 @@ public interface InputConnection { public boolean commitCompletion(CompletionInfo text); /** + * Set the selection of the text editor. To set the cursor position, + * start and end should have the same value. + */ + public boolean setSelection(int start, int end); + + /** + * Perform a context menu action on the field. The given id may be one of: + * {@link android.R.id#selectAll}, + * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText}, + * {@link android.R.id#cut}, {@link android.R.id#copy}, + * {@link android.R.id#paste}, {@link android.R.id#copyUrl}, + * or {@link android.R.id#switchInputMethod} + */ + public boolean performContextMenuAction(int id); + + /** * Tell the editor that you are starting a batch of editor operations. * The editor will try to avoid sending you updates about its state * until {@link #endBatchEdit} is called. diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java deleted file mode 100644 index f65b2a1..0000000 --- a/core/java/android/view/inputmethod/InputConnectionWrapper.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2007-2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package android.view.inputmethod; - -import android.os.Bundle; -import android.view.KeyEvent; - -/** - * Wrapper around InputConnection interface, calling through to another - * implementation of it. - */ -public class InputConnectionWrapper implements InputConnection { - InputConnection mBase; - - /** - * Create a new wrapper around an existing InputConnection implementation. - */ - public InputConnectionWrapper(InputConnection base) { - mBase = base; - } - - /** - * Return the base InputConnection that this class is wrapping. - */ - InputConnection getBase() { - return mBase; - } - - public CharSequence getTextBeforeCursor(int n) { - return mBase.getTextBeforeCursor(n); - } - - public CharSequence getTextAfterCursor(int n) { - return mBase.getTextAfterCursor(n); - } - - public int getCursorCapsMode(int reqModes) { - return mBase.getCursorCapsMode(reqModes); - } - - public ExtractedText getExtractedText(ExtractedTextRequest request, - int flags) { - return mBase.getExtractedText(request, flags); - } - - public boolean deleteSurroundingText(int leftLength, int rightLength) { - return mBase.deleteSurroundingText(leftLength, rightLength); - } - - public boolean setComposingText(CharSequence text, int newCursorPosition) { - return mBase.setComposingText(text, newCursorPosition); - } - - public boolean finishComposingText() { - return mBase.finishComposingText(); - } - - public boolean commitText(CharSequence text, int newCursorPosition) { - return mBase.commitText(text, newCursorPosition); - } - - public boolean commitCompletion(CompletionInfo text) { - return mBase.commitCompletion(text); - } - - public boolean beginBatchEdit() { - return mBase.beginBatchEdit(); - } - - public boolean endBatchEdit() { - return mBase.endBatchEdit(); - } - - public boolean sendKeyEvent(KeyEvent event) { - return mBase.sendKeyEvent(event); - } - - public boolean clearMetaKeyStates(int states) { - return mBase.clearMetaKeyStates(states); - } - - public boolean performPrivateCommand(String action, Bundle data) { - return mBase.performPrivateCommand(action, data); - } - - public boolean showStatusIcon(String packageName, int resId) { - return mBase.showStatusIcon(packageName, resId); - } - - public boolean hideStatusIcon() { - return mBase.hideStatusIcon(); - } -} diff --git a/core/java/android/view/inputmethod/InputMethod.java b/core/java/android/view/inputmethod/InputMethod.java index c0e6590..740dca8 100644 --- a/core/java/android/view/inputmethod/InputMethod.java +++ b/core/java/android/view/inputmethod/InputMethod.java @@ -113,12 +113,15 @@ public interface InputMethod { * is ready for this input method to process received events and send result * text back to the application. * - * @param attribute The attribute of the text box (typically, a EditText) + * @param inputConnection Optional specific input connection for + * communicating with the text box; if null, you should use the generic + * bound input connection. + * @param info Information about the text box (typically, an EditText) * that requests input. * * @see EditorInfo */ - public void startInput(EditorInfo attribute); + public void startInput(InputConnection inputConnection, EditorInfo info); /** * This method is called when the state of this input method needs to be @@ -128,12 +131,15 @@ public interface InputMethod { * Typically, this method is called when the input focus is moved from one * text box to another. * + * @param inputConnection Optional specific input connection for + * communicating with the text box; if null, you should use the generic + * bound input connection. * @param attribute The attribute of the text box (typically, a EditText) * that requests input. * * @see EditorInfo */ - public void restartInput(EditorInfo attribute); + public void restartInput(InputConnection inputConnection, EditorInfo attribute); /** * Create a new {@link InputMethodSession} that can be handed to client @@ -173,6 +179,13 @@ public interface InputMethod { public static final int SHOW_EXPLICIT = 0x00001; /** + * Flag for {@link #showSoftInput(int)}: this show has been forced to + * happen by the user. If set, the input method should remain visible + * until deliberated dismissed by the user in its UI. + */ + public static final int SHOW_FORCED = 0x00002; + + /** * Request that any soft input part of the input method be shown to the user. * * @param flags Provide additional information about the show request. diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index a9a9594..99d5aa5 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -26,11 +26,14 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import android.util.PrintWriterPrinter; +import android.util.Printer; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewRoot; +import com.android.internal.os.HandlerCaller; import com.android.internal.view.IInputConnectionWrapper; import com.android.internal.view.IInputContext; import com.android.internal.view.IInputMethodCallback; @@ -39,7 +42,11 @@ import com.android.internal.view.IInputMethodManager; import com.android.internal.view.IInputMethodSession; import com.android.internal.view.InputBindResult; +import java.io.FileDescriptor; +import java.io.PrintWriter; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; /** * Central system API to the overall input method framework (IMF) architecture, @@ -199,8 +206,7 @@ public final class InputMethodManager { // global lock. final H mH; - // The currently active input connection. - final MutableInputConnectionWrapper mInputConnectionWrapper; + // Our generic input connection if the current target does not have its own. final IInputContext mIInputContext; /** @@ -208,11 +214,6 @@ public final class InputMethodManager { */ boolean mActive = false; - /** - * The current base input connection, used when mActive is true. - */ - InputConnection mCurrentInputConnection; - // ----------------------------------------------------------- /** @@ -270,7 +271,7 @@ public final class InputMethodManager { // ----------------------------------------------------------- - static final int MSG_CHECK_FOCUS = 1; + static final int MSG_DUMP = 1; class H extends Handler { H(Looper looper) { @@ -280,85 +281,55 @@ public final class InputMethodManager { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_CHECK_FOCUS: - checkFocus(); + case MSG_DUMP: { + HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj; + try { + doDump((FileDescriptor)args.arg1, + (PrintWriter)args.arg2, (String[])args.arg3); + } catch (RuntimeException e) { + ((PrintWriter)args.arg2).println("Exception: " + e); + } + synchronized (args.arg4) { + ((CountDownLatch)args.arg4).countDown(); + } return; + } } } } - static class NoOpInputConnection implements InputConnection { - - public boolean clearMetaKeyStates(int states) { - return false; - } - - public boolean beginBatchEdit() { - return false; - } - - public boolean endBatchEdit() { - return false; - } - - public boolean commitCompletion(CompletionInfo text) { - return false; - } - - public boolean commitText(CharSequence text, int newCursorPosition) { - return false; - } - - public boolean deleteSurroundingText(int leftLength, int rightLength) { - return false; - } - - public int getCursorCapsMode(int reqModes) { - return 0; - } - - public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) { - return null; - } - - public CharSequence getTextAfterCursor(int n) { - return null; + class ControlledInputConnectionWrapper extends IInputConnectionWrapper { + public ControlledInputConnectionWrapper(Looper mainLooper, InputConnection conn) { + super(mainLooper, conn); } - public CharSequence getTextBeforeCursor(int n) { - return null; - } - - public boolean hideStatusIcon() { - return false; - } - - public boolean performPrivateCommand(String action, Bundle data) { - return false; - } - - public boolean sendKeyEvent(KeyEvent event) { - return false; - } - - public boolean setComposingText(CharSequence text, int newCursorPosition) { - return false; - } - - public boolean finishComposingText() { - return false; - } - - public boolean showStatusIcon(String packageName, int resId) { - return false; + public boolean isActive() { + return mActive; } } - final NoOpInputConnection mNoOpInputConnection = new NoOpInputConnection(); - final IInputMethodClient.Stub mClient = new IInputMethodClient.Stub() { - public void setUsingInputMethod(boolean state) { + @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { + // No need to check for dump permission, since we only give this + // interface to the system. + CountDownLatch latch = new CountDownLatch(1); + HandlerCaller.SomeArgs sargs = new HandlerCaller.SomeArgs(); + sargs.arg1 = fd; + sargs.arg2 = fout; + sargs.arg3 = args; + sargs.arg4 = latch; + mH.sendMessage(mH.obtainMessage(MSG_DUMP, sargs)); + try { + if (!latch.await(5, TimeUnit.SECONDS)) { + fout.println("Timeout waiting for dump"); + } + } catch (InterruptedException e) { + fout.println("Interrupted waiting for dump"); + } + } + + public void setUsingInputMethod(boolean state) { } public void onBindMethod(InputBindResult res) { @@ -403,62 +374,17 @@ public final class InputMethodManager { public void setActive(boolean active) { mActive = active; - mInputConnectionWrapper.setBaseInputConnection(active - ? mCurrentInputConnection : mNoOpInputConnection); } }; - final InputConnection mDummyInputConnection = new BaseInputConnection(this) { - public boolean beginBatchEdit() { - return false; - } - public boolean endBatchEdit() { - return false; - } - public boolean commitText(CharSequence text, int newCursorPosition) { - return false; - } - public boolean commitCompletion(CompletionInfo text) { - return false; - } - public boolean deleteSurroundingText(int leftLength, int rightLength) { - return false; - } - public ExtractedText getExtractedText(ExtractedTextRequest request, - int flags) { - return null; - } - public CharSequence getTextAfterCursor(int n) { - return null; - } - public CharSequence getTextBeforeCursor(int n) { - return null; - } - public int getCursorCapsMode(int reqModes) { - return 0; - } - public boolean clearMetaKeyStates(int states) { - return false; - } - public boolean performPrivateCommand(String action, Bundle data) { - return false; - } - public boolean setComposingText(CharSequence text, int newCursorPosition) { - return false; - } - public boolean finishComposingText() { - return false; - } - }; + final InputConnection mDummyInputConnection = new BaseInputConnection(this, true); InputMethodManager(IInputMethodManager service, Looper looper) { mService = service; mMainLooper = looper; mH = new H(looper); - mInputConnectionWrapper = new MutableInputConnectionWrapper(mNoOpInputConnection); - mIInputContext = new IInputConnectionWrapper(looper, - mInputConnectionWrapper); - setCurrentInputConnection(mDummyInputConnection); + mIInputContext = new ControlledInputConnectionWrapper(looper, + mDummyInputConnection); if (mInstance == null) { mInstance = this; @@ -563,22 +489,12 @@ public final class InputMethodManager { } /** - * Record the desired input connection, but only set it if mActive is true. - */ - void setCurrentInputConnection(InputConnection connection) { - mCurrentInputConnection = connection; - mInputConnectionWrapper.setBaseInputConnection(mActive - ? connection : mNoOpInputConnection); - } - - /** * Reset all of the state associated with a served view being connected * to an input method */ void clearConnectionLocked() { mCurrentTextBoxAttribute = null; mServedInputConnection = null; - setCurrentInputConnection(mDummyInputConnection); } /** @@ -659,13 +575,20 @@ public final class InputMethodManager { } /** - * Flag for {@link #showSoftInput} to indicate that the this is an implicit + * Flag for {@link #showSoftInput} to indicate that this is an implicit * request to show the input window, not as the result of a direct request * by the user. The window may not be shown in this case. */ public static final int SHOW_IMPLICIT = 0x0001; /** + * Flag for {@link #showSoftInput} to indicate that the user has forced + * the input method open (such as by long-pressing menu) so it should + * not be closed until they explicitly do so. + */ + public static final int SHOW_FORCED = 0x0002; + + /** * Explicitly request that the current input method's soft input area be * shown to the user, if needed. Call this if the user interacts with * your view in such a way that they have expressed they would like to @@ -689,6 +612,14 @@ public final class InputMethodManager { } } + /** @hide */ + public void showSoftInputUnchecked(int flags) { + try { + mService.showSoftInput(mClient, flags); + } catch (RemoteException e) { + } + } + /** * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft * input window should only be hidden if it was not explicitly shown @@ -697,6 +628,13 @@ public final class InputMethodManager { public static final int HIDE_IMPLICIT_ONLY = 0x0001; /** + * Flag for {@link #hideSoftInputFromWindow} to indicate that the soft + * input window should normally be hidden, unless it was originally + * shown with {@link #SHOW_FORCED}. + */ + public static final int HIDE_NOT_ALWAYS = 0x0002; + + /** * Request to hide the soft input window from the context of the window * that is currently accepting input. This should be called as a result * of the user doing some actually than fairly explicitly requests to @@ -779,6 +717,8 @@ public final class InputMethodManager { // do its stuff. // Life is good: let's hook everything up! EditorInfo tba = new EditorInfo(); + tba.packageName = view.getContext().getPackageName(); + tba.fieldId = view.getId(); InputConnection ic = view.onCreateInputConnection(tba); if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic); @@ -801,22 +741,23 @@ public final class InputMethodManager { mCurrentTextBoxAttribute = tba; mServedConnecting = false; mServedInputConnection = ic; + IInputContext servedContext; if (ic != null) { mCursorSelStart = tba.initialSelStart; mCursorSelEnd = tba.initialSelEnd; mCursorCandStart = -1; mCursorCandEnd = -1; mCursorRect.setEmpty(); - setCurrentInputConnection(ic); + servedContext = new ControlledInputConnectionWrapper(vh.getLooper(), ic); } else { - setCurrentInputConnection(mDummyInputConnection); + servedContext = null; } try { if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic=" + ic + " tba=" + tba + " initial=" + initial); - InputBindResult res = mService.startInput(mClient, tba, initial, - mCurMethod == null); + InputBindResult res = mService.startInput(mClient, + servedContext, tba, initial, mCurMethod == null); if (DEBUG) Log.v(TAG, "Starting input: Bind result=" + res); if (res != null) { if (res.id != null) { @@ -885,10 +826,20 @@ public final class InputMethodManager { + " winFocus=" + view.hasWindowFocus()); if (mServedView == view) { ic = mServedInputConnection; - if (view.hasWindowFocus()) { + // The following code would auto-hide the IME if we end up + // with no more views with focus. This can happen, however, + // whenever we go into touch mode, so it ends up hiding + // at times when we don't really want it to. For now it + // seems better to just turn it all off. + if (false && view.hasWindowFocus()) { mLastServedView = view; - mH.removeMessages(MSG_CHECK_FOCUS); - mH.sendEmptyMessage(MSG_CHECK_FOCUS); + Handler vh = view.getHandler(); + if (vh != null) { + // This will result in a call to checkFocus() below. + vh.removeMessages(ViewRoot.CHECK_FOCUS); + vh.sendMessage(vh.obtainMessage(ViewRoot.CHECK_FOCUS, + view)); + } } } } @@ -898,8 +849,14 @@ public final class InputMethodManager { } } - void checkFocus() { + /** + * @hide + */ + public void checkFocus(View view) { synchronized (mH) { + if (view != mLastServedView) { + return; + } if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView + " last=" + mLastServedView); if (mServedView == mLastServedView) { @@ -915,7 +872,7 @@ public final class InputMethodManager { void closeCurrentInput() { try { - mService.hideSoftInput(mClient, 0); + mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS); } catch (RemoteException e) { } } @@ -1006,6 +963,32 @@ public final class InputMethodManager { } /** + * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) + * InputMethodSession.appPrivateCommand()} on the current Input Method. + * @param view Optional View that is sending the command, or null if + * you want to send the command regardless of the view that is attached + * to the input method. + * @param action Name of the command to be performed. This <em>must</em> + * be a scoped name, i.e. prefixed with a package name you own, so that + * different developers will not create conflicting commands. + * @param data Any data to include with the command. + */ + public void sendAppPrivateCommand(View view, String action, Bundle data) { + synchronized (mH) { + if ((view != null && mServedView != view) + || mCurrentTextBoxAttribute == null || mCurMethod == null) { + return; + } + try { + if (DEBUG) Log.v(TAG, "APP PRIVATE COMMAND " + action + ": " + data); + mCurMethod.appPrivateCommand(action, data); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + + /** * Force switch to a new input method component. This can only be called * from the currently active input method, as validated by the given token. * @param token Supplies the identifying token given to an input method @@ -1048,7 +1031,7 @@ public final class InputMethodManager { synchronized (mH) { if (DEBUG) Log.d(TAG, "dispatchKeyEvent"); - if (mCurMethod == null || mCurrentTextBoxAttribute == null) { + if (mCurMethod == null) { try { callback.finishedEvent(seq, false); } catch (RemoteException e) { @@ -1116,4 +1099,33 @@ public final class InputMethodManager { } } } + + void doDump(FileDescriptor fd, PrintWriter fout, String[] args) { + final Printer p = new PrintWriterPrinter(fout); + p.println("Input method client state for " + this + ":"); + + p.println(" mService=" + mService); + p.println(" mMainLooper=" + mMainLooper); + p.println(" mIInputContext=" + mIInputContext); + p.println(" mActive=" + mActive + + " mBindSequence=" + mBindSequence + + " mCurId=" + mCurId); + p.println(" mCurMethod=" + mCurMethod); + p.println(" mServedView=" + mServedView); + p.println(" mLastServedView=" + mLastServedView); + p.println(" mServedConnecting=" + mServedConnecting); + if (mCurrentTextBoxAttribute != null) { + p.println(" mCurrentTextBoxAttribute:"); + mCurrentTextBoxAttribute.dump(p, " "); + } else { + p.println(" mCurrentTextBoxAttribute: null"); + } + p.println(" mServedInputConnection=" + mServedInputConnection); + p.println(" mCompletions=" + mCompletions); + p.println(" mCursorRect=" + mCursorRect); + p.println(" mCursorSelStart=" + mCursorSelStart + + " mCursorSelEnd=" + mCursorSelEnd + + " mCursorCandStart=" + mCursorCandStart + + " mCursorCandEnd=" + mCursorCandEnd); + } } diff --git a/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java b/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java deleted file mode 100644 index 025a059..0000000 --- a/core/java/android/view/inputmethod/MutableInputConnectionWrapper.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007-2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package android.view.inputmethod; - - -/** - * Special version of {@link InputConnectionWrapper} that allows the base - * input connection to be modified after it is initially set. - */ -public class MutableInputConnectionWrapper extends InputConnectionWrapper { - public MutableInputConnectionWrapper(InputConnection base) { - super(base); - } - - /** - * Change the base InputConnection for this wrapper. All calls will then be - * delegated to the base input connection. - * - * @param base The new base InputConnection for this wrapper. - */ - public void setBaseInputConnection(InputConnection base) { - mBase = base; - } -} |