am a90b7f01: Add methods to InputConnection: setComposingRegion() to select a region of text for correction, and getSelectedText() to return the selected text.
Merge commit 'a90b7f0125389b9e1040d2be82aad4ef74ea6071' into gingerbread-plus-aosp * commit 'a90b7f0125389b9e1040d2be82aad4ef74ea6071': Add methods to InputConnection: setComposingRegion() to select a region of text for correction, and getSelectedText()
This commit is contained in:
@@ -198082,6 +198082,19 @@
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getSelectedText"
|
||||
return="java.lang.CharSequence"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getTextAfterCursor"
|
||||
return="java.lang.CharSequence"
|
||||
abstract="false"
|
||||
@@ -198192,6 +198205,21 @@
|
||||
<parameter name="event" type="android.view.KeyEvent">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setComposingRegion"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="start" type="int">
|
||||
</parameter>
|
||||
<parameter name="end" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setComposingSpans"
|
||||
return="void"
|
||||
abstract="false"
|
||||
@@ -199186,6 +199214,19 @@
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getSelectedText"
|
||||
return="java.lang.CharSequence"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getTextAfterCursor"
|
||||
return="java.lang.CharSequence"
|
||||
abstract="true"
|
||||
@@ -199283,6 +199324,21 @@
|
||||
<parameter name="event" type="android.view.KeyEvent">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setComposingRegion"
|
||||
return="boolean"
|
||||
abstract="true"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="start" type="int">
|
||||
</parameter>
|
||||
<parameter name="end" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setComposingText"
|
||||
return="boolean"
|
||||
abstract="true"
|
||||
@@ -199475,6 +199531,19 @@
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getSelectedText"
|
||||
return="java.lang.CharSequence"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="flags" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getTextAfterCursor"
|
||||
return="java.lang.CharSequence"
|
||||
abstract="false"
|
||||
@@ -199572,6 +199641,21 @@
|
||||
<parameter name="event" type="android.view.KeyEvent">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setComposingRegion"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="start" type="int">
|
||||
</parameter>
|
||||
<parameter name="end" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="setComposingText"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
|
||||
@@ -84,9 +84,14 @@ public class BaseInputConnection implements InputConnection {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void setComposingSpans(Spannable text) {
|
||||
final Object[] sps = text.getSpans(0, text.length(), Object.class);
|
||||
setComposingSpans(text, 0, text.length());
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static void setComposingSpans(Spannable text, int start, int end) {
|
||||
final Object[] sps = text.getSpans(start, end, Object.class);
|
||||
if (sps != null) {
|
||||
for (int i=sps.length-1; i>=0; i--) {
|
||||
final Object o = sps[i];
|
||||
@@ -94,18 +99,19 @@ public class BaseInputConnection implements InputConnection {
|
||||
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)
|
||||
(fl & ~Spanned.SPAN_POINT_MARK_MASK)
|
||||
| Spanned.SPAN_COMPOSING
|
||||
| Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
text.setSpan(COMPOSING, 0, text.length(),
|
||||
|
||||
text.setSpan(COMPOSING, start, end,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
|
||||
}
|
||||
|
||||
@@ -311,6 +317,31 @@ public class BaseInputConnection implements InputConnection {
|
||||
return TextUtils.substring(content, a - length, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation returns the text currently selected, or null if none is
|
||||
* selected.
|
||||
*/
|
||||
public CharSequence getSelectedText(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 (a == b) return null;
|
||||
|
||||
if ((flags&GET_TEXT_WITH_STYLES) != 0) {
|
||||
return content.subSequence(a, b);
|
||||
}
|
||||
return TextUtils.substring(content, a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation returns the given amount of text from the
|
||||
* current cursor position in the buffer.
|
||||
@@ -385,6 +416,38 @@ public class BaseInputConnection implements InputConnection {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean setComposingRegion(int start, int end) {
|
||||
final Editable content = getEditable();
|
||||
if (content != null) {
|
||||
beginBatchEdit();
|
||||
removeComposingSpans(content);
|
||||
int a = start;
|
||||
int b = end;
|
||||
if (a > b) {
|
||||
int tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
if (a < 0) a = 0;
|
||||
if (b > content.length()) b = content.length();
|
||||
|
||||
ensureDefaultComposingSpans();
|
||||
if (mDefaultComposingSpans != null) {
|
||||
for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
|
||||
content.setSpan(mDefaultComposingSpans[i], a, b,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
|
||||
}
|
||||
}
|
||||
|
||||
content.setSpan(COMPOSING, a, b,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
|
||||
|
||||
endBatchEdit();
|
||||
sendCurrentText();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation changes the selection position in the
|
||||
* current editable text.
|
||||
@@ -479,7 +542,32 @@ public class BaseInputConnection implements InputConnection {
|
||||
content.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ensureDefaultComposingSpans() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void replaceText(CharSequence text, int newCursorPosition,
|
||||
boolean composing) {
|
||||
final Editable content = getEditable();
|
||||
@@ -520,32 +608,11 @@ public class BaseInputConnection implements InputConnection {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
ensureDefaultComposingSpans();
|
||||
if (mDefaultComposingSpans != null) {
|
||||
for (int i = 0; i < mDefaultComposingSpans.length; ++i) {
|
||||
sp.setSpan(mDefaultComposingSpans[i], 0, sp.length(),
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -79,6 +79,21 @@ public interface InputConnection {
|
||||
*/
|
||||
public CharSequence getTextAfterCursor(int n, int flags);
|
||||
|
||||
/**
|
||||
* Gets the selected text, if any.
|
||||
*
|
||||
* <p>This method may fail if either the input connection has become
|
||||
* invalid (such as its process crashing) or the client is taking too
|
||||
* long to respond with the text (it is given a couple of seconds to return).
|
||||
* In either case, a null is returned.
|
||||
*
|
||||
* @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 that is currently selected, if any, or null if
|
||||
* no text is selected.
|
||||
*/
|
||||
public CharSequence getSelectedText(int flags);
|
||||
|
||||
/**
|
||||
* Retrieve the current capitalization mode in effect at the current
|
||||
* cursor position in the text. See
|
||||
@@ -161,6 +176,18 @@ public interface InputConnection {
|
||||
*/
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition);
|
||||
|
||||
/**
|
||||
* Mark a certain region of text as composing text. Any composing text set
|
||||
* previously will be removed automatically. The default style for composing
|
||||
* text is used.
|
||||
*
|
||||
* @param start the position in the text at which the composing region begins
|
||||
* @param end the position in the text at which the composing region ends
|
||||
* @return Returns true on success, false if the input connection is no longer
|
||||
* valid.
|
||||
*/
|
||||
public boolean setComposingRegion(int start, int end);
|
||||
|
||||
/**
|
||||
* Have the text editor finish whatever composing text is currently
|
||||
* active. This simply leaves the text as-is, removing any special
|
||||
|
||||
@@ -50,6 +50,10 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
return mTarget.getTextAfterCursor(n, flags);
|
||||
}
|
||||
|
||||
public CharSequence getSelectedText(int flags) {
|
||||
return mTarget.getSelectedText(flags);
|
||||
}
|
||||
|
||||
public int getCursorCapsMode(int reqModes) {
|
||||
return mTarget.getCursorCapsMode(reqModes);
|
||||
}
|
||||
@@ -67,6 +71,10 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
return mTarget.setComposingText(text, newCursorPosition);
|
||||
}
|
||||
|
||||
public boolean setComposingRegion(int start, int end) {
|
||||
return mTarget.setComposingRegion(start, end);
|
||||
}
|
||||
|
||||
public boolean finishComposingText() {
|
||||
return mTarget.finishComposingText();
|
||||
}
|
||||
|
||||
@@ -31,9 +31,10 @@ import java.lang.ref.WeakReference;
|
||||
|
||||
public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
static final String TAG = "IInputConnectionWrapper";
|
||||
|
||||
|
||||
private static final int DO_GET_TEXT_AFTER_CURSOR = 10;
|
||||
private static final int DO_GET_TEXT_BEFORE_CURSOR = 20;
|
||||
private static final int DO_GET_SELECTED_TEXT = 25;
|
||||
private static final int DO_GET_CURSOR_CAPS_MODE = 30;
|
||||
private static final int DO_GET_EXTRACTED_TEXT = 40;
|
||||
private static final int DO_COMMIT_TEXT = 50;
|
||||
@@ -42,6 +43,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
private static final int DO_PERFORM_EDITOR_ACTION = 58;
|
||||
private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59;
|
||||
private static final int DO_SET_COMPOSING_TEXT = 60;
|
||||
private static final int DO_SET_COMPOSING_REGION = 63;
|
||||
private static final int DO_FINISH_COMPOSING_TEXT = 65;
|
||||
private static final int DO_SEND_KEY_EVENT = 70;
|
||||
private static final int DO_DELETE_SURROUNDING_TEXT = 80;
|
||||
@@ -50,7 +52,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
private static final int DO_REPORT_FULLSCREEN_MODE = 100;
|
||||
private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
|
||||
private static final int DO_CLEAR_META_KEY_STATES = 130;
|
||||
|
||||
|
||||
private WeakReference<InputConnection> mInputConnection;
|
||||
|
||||
private Looper mMainLooper;
|
||||
@@ -92,6 +94,10 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
dispatchMessage(obtainMessageIISC(DO_GET_TEXT_BEFORE_CURSOR, length, flags, seq, callback));
|
||||
}
|
||||
|
||||
public void getSelectedText(int flags, int seq, IInputContextCallback callback) {
|
||||
dispatchMessage(obtainMessageISC(DO_GET_SELECTED_TEXT, flags, seq, callback));
|
||||
}
|
||||
|
||||
public void getCursorCapsMode(int reqModes, int seq, IInputContextCallback callback) {
|
||||
dispatchMessage(obtainMessageISC(DO_GET_CURSOR_CAPS_MODE, reqModes, seq, callback));
|
||||
}
|
||||
@@ -122,6 +128,10 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0));
|
||||
}
|
||||
|
||||
public void setComposingRegion(int start, int end) {
|
||||
dispatchMessage(obtainMessageII(DO_SET_COMPOSING_REGION, start, end));
|
||||
}
|
||||
|
||||
public void setComposingText(CharSequence text, int newCursorPosition) {
|
||||
dispatchMessage(obtainMessageIO(DO_SET_COMPOSING_TEXT, newCursorPosition, text));
|
||||
}
|
||||
@@ -206,6 +216,22 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DO_GET_SELECTED_TEXT: {
|
||||
SomeArgs args = (SomeArgs)msg.obj;
|
||||
try {
|
||||
InputConnection ic = mInputConnection.get();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "getSelectedText on inactive InputConnection");
|
||||
args.callback.setSelectedText(null, args.seq);
|
||||
return;
|
||||
}
|
||||
args.callback.setSelectedText(ic.getSelectedText(
|
||||
msg.arg1), args.seq);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Got RemoteException calling setSelectedText", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DO_GET_CURSOR_CAPS_MODE: {
|
||||
SomeArgs args = (SomeArgs)msg.obj;
|
||||
try {
|
||||
@@ -292,6 +318,15 @@ public class IInputConnectionWrapper extends IInputContext.Stub {
|
||||
ic.setComposingText((CharSequence)msg.obj, msg.arg1);
|
||||
return;
|
||||
}
|
||||
case DO_SET_COMPOSING_REGION: {
|
||||
InputConnection ic = mInputConnection.get();
|
||||
if (ic == null || !isActive()) {
|
||||
Log.w(TAG, "setComposingRegion on inactive InputConnection");
|
||||
return;
|
||||
}
|
||||
ic.setComposingRegion(msg.arg1, msg.arg2);
|
||||
return;
|
||||
}
|
||||
case DO_FINISH_COMPOSING_TEXT: {
|
||||
InputConnection ic = mInputConnection.get();
|
||||
// Note we do NOT check isActive() here, because this is safe
|
||||
|
||||
@@ -65,4 +65,8 @@ import com.android.internal.view.IInputContextCallback;
|
||||
void clearMetaKeyStates(int states);
|
||||
|
||||
void performPrivateCommand(String action, in Bundle data);
|
||||
|
||||
void setComposingRegion(int start, int end);
|
||||
|
||||
void getSelectedText(int flags, int seq, IInputContextCallback callback);
|
||||
}
|
||||
|
||||
@@ -26,4 +26,5 @@ oneway interface IInputContextCallback {
|
||||
void setTextAfterCursor(CharSequence textAfterCursor, int seq);
|
||||
void setCursorCapsMode(int capsMode, int seq);
|
||||
void setExtractedText(in ExtractedText extractedText, int seq);
|
||||
void setSelectedText(CharSequence selectedText, int seq);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.internal.view;
|
||||
|
||||
import com.android.internal.view.IInputContext;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
@@ -38,6 +36,7 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
public boolean mHaveValue;
|
||||
public CharSequence mTextBeforeCursor;
|
||||
public CharSequence mTextAfterCursor;
|
||||
public CharSequence mSelectedText;
|
||||
public ExtractedText mExtractedText;
|
||||
public int mCursorCapsMode;
|
||||
|
||||
@@ -114,6 +113,19 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectedText(CharSequence selectedText, int seq) {
|
||||
synchronized (this) {
|
||||
if (seq == mSeq) {
|
||||
mSelectedText = selectedText;
|
||||
mHaveValue = true;
|
||||
notifyAll();
|
||||
} else {
|
||||
Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
|
||||
+ ") in setSelectedText, ignoring.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setCursorCapsMode(int capsMode, int seq) {
|
||||
synchronized (this) {
|
||||
if (seq == mSeq) {
|
||||
@@ -203,6 +215,24 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
return value;
|
||||
}
|
||||
|
||||
public CharSequence getSelectedText(int flags) {
|
||||
CharSequence value = null;
|
||||
try {
|
||||
InputContextCallback callback = InputContextCallback.getInstance();
|
||||
mIInputContext.getSelectedText(flags, callback.mSeq, callback);
|
||||
synchronized (callback) {
|
||||
callback.waitForResultLocked();
|
||||
if (callback.mHaveValue) {
|
||||
value = callback.mSelectedText;
|
||||
}
|
||||
}
|
||||
callback.dispose();
|
||||
} catch (RemoteException e) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getCursorCapsMode(int reqModes) {
|
||||
int value = 0;
|
||||
try {
|
||||
@@ -283,7 +313,16 @@ public class InputConnectionWrapper implements InputConnection {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean setComposingRegion(int start, int end) {
|
||||
try {
|
||||
mIInputContext.setComposingRegion(start, end);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setComposingText(CharSequence text, int newCursorPosition) {
|
||||
try {
|
||||
mIInputContext.setComposingText(text, newCursorPosition);
|
||||
|
||||
Reference in New Issue
Block a user