summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmith Yamasani <yamasani@google.com>2010-08-27 12:14:46 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2010-08-27 12:14:46 -0700
commitf956fd6d1325fcb2e5ce9b8dac95a9a40824ead8 (patch)
treef2cf912dc82e332dc448f9eb741fe608adf7d2a1
parent93637d3ee7b2346426b315627c8fcaf9b4782f93 (diff)
parent4b4114d155b4f3d5cc4179934cb6403b1776261d (diff)
downloadframeworks_base-f956fd6d1325fcb2e5ce9b8dac95a9a40824ead8.zip
frameworks_base-f956fd6d1325fcb2e5ce9b8dac95a9a40824ead8.tar.gz
frameworks_base-f956fd6d1325fcb2e5ce9b8dac95a9a40824ead8.tar.bz2
am 4b4114d1: am a90b7f01: Add methods to InputConnection: setComposingRegion() to select a region of text for correction, and getSelectedText() to return the selected text.
Merge commit '4b4114d155b4f3d5cc4179934cb6403b1776261d' * commit '4b4114d155b4f3d5cc4179934cb6403b1776261d': Add methods to InputConnection: setComposingRegion() to select a region of text for correction, and getSelectedText()
-rw-r--r--api/current.xml84
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java125
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java27
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java8
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java39
-rw-r--r--core/java/com/android/internal/view/IInputContext.aidl4
-rw-r--r--core/java/com/android/internal/view/IInputContextCallback.aidl1
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java45
8 files changed, 299 insertions, 34 deletions
diff --git a/api/current.xml b/api/current.xml
index 41d87c4..158e251 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -208193,6 +208193,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"
@@ -208303,6 +208316,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"
@@ -209297,6 +209325,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"
@@ -209394,6 +209435,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"
@@ -209586,6 +209642,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"
@@ -209683,6 +209752,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"
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 6ac1633..3801948 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -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);
}
@@ -312,6 +318,31 @@ public class BaseInputConnection implements InputConnection {
}
/**
+ * 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 {
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 8b6831e..3b8a364 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -80,6 +80,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
* {@link android.text.TextUtils#getCapsMode TextUtils.getCapsMode} for
@@ -162,6 +177,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
* composing styling or other state that was around it. The cursor
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 210559a..b73f9bb 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -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();
}
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index a765e38..986ba38 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -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
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 02cb9e4..333fc82 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -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);
}
diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl
index 9b8c43c..661066b 100644
--- a/core/java/com/android/internal/view/IInputContextCallback.aidl
+++ b/core/java/com/android/internal/view/IInputContextCallback.aidl
@@ -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);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 3c44e58..08c3026 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -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);