summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/java/android/app/ContextImpl.java6
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/java/android/provider/Settings.java12
-rw-r--r--core/java/android/service/textservice/SpellCheckerService.java140
-rw-r--r--core/java/android/service/textservice/SpellCheckerSession.java271
-rw-r--r--core/java/android/view/textservice/SpellCheckerInfo.aidl19
-rw-r--r--core/java/android/view/textservice/SpellCheckerInfo.java112
-rw-r--r--core/java/android/view/textservice/SuggestionsInfo.aidl19
-rw-r--r--core/java/android/view/textservice/SuggestionsInfo.java176
-rw-r--r--core/java/android/view/textservice/TextInfo.aidl19
-rw-r--r--core/java/android/view/textservice/TextInfo.java117
-rw-r--r--core/java/android/view/textservice/TextServicesManager.java106
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerService.aidl29
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerSession.aidl28
-rw-r--r--core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl26
-rw-r--r--core/java/com/android/internal/textservice/ITextServicesManager.aidl35
-rw-r--r--core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl29
-rw-r--r--core/res/AndroidManifest.xml7
-rwxr-xr-xcore/res/res/values/strings.xml6
19 files changed, 1163 insertions, 3 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index d2323e7..6289730 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -83,6 +83,7 @@ import android.view.ContextThemeWrapper;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
+import android.view.textservice.TextServicesManager;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.app.admin.DevicePolicyManager;
@@ -320,6 +321,11 @@ class ContextImpl extends Context {
return InputMethodManager.getInstance(ctx);
}});
+ registerService(TEXT_SERVICES_MANAGER_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return TextServicesManager.getInstance();
+ }});
+
registerService(KEYGUARD_SERVICE, new ServiceFetcher() {
public Object getService(ContextImpl ctx) {
// TODO: why isn't this caching it? It wasn't
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fed6d81..0a2253c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1612,6 +1612,15 @@ public abstract class Context {
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.view.textservice.TextServicesManager} for accessing
+ * text services.
+ *
+ * @see #getSystemService
+ */
+ public static final String TEXT_SERVICES_MANAGER_SERVICE = "textservices";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.appwidget.AppWidgetManager} for accessing AppWidgets.
*
* @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index cb87e94..1cd46de 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -16,8 +16,6 @@
package android.provider;
-
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.SearchManager;
@@ -48,7 +46,6 @@ import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
-
/**
* The Settings provider contains global system-level device preferences.
*/
@@ -3737,6 +3734,15 @@ public final class Settings {
*/
public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
+
+ /**
+ * The {@link ComponentName} string of the service to be used as the spell checker
+ * service which is one of the services managed by the text service manager.
+ *
+ * @hide
+ */
+ public static final String SPELL_CHECKER_SERVICE = "spell_checker_service";
+
/**
* What happens when the user presses the Power button while in-call
* and the screen is on.<br/>
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
new file mode 100644
index 0000000..6ac99ca
--- /dev/null
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 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.service.textservice;
+
+import com.android.internal.textservice.ISpellCheckerService;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * SpellCheckerService provides an abstract base class for a spell checker.
+ * This class combines a service to the system with the spell checker service interface that
+ * spell checker must implement.
+ */
+public abstract class SpellCheckerService extends Service {
+ private static final String TAG = SpellCheckerService.class.getSimpleName();
+ public static final String SERVICE_INTERFACE = SpellCheckerService.class.getName();
+
+ private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
+
+ /**
+ * Get suggestions for specified text in TextInfo.
+ * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+ * but will be called in series on another thread.
+ * @param textInfo the text metadata
+ * @param suggestionsLimit the number of limit of suggestions returned
+ * @param locale the locale for getting suggestions
+ * @return SuggestionInfo which contains suggestions for textInfo
+ */
+ public abstract SuggestionsInfo getSuggestions(
+ TextInfo textInfo, int suggestionsLimit, String locale);
+
+ /**
+ * A batch process of onGetSuggestions.
+ * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+ * but will be called in series on another thread.
+ * @param textInfos an array of the text metadata
+ * @param locale the locale for getting suggestions
+ * @param suggestionsLimit the number of limit of suggestions returned
+ * @param sequentialWords true if textInfos can be treated as sequential words.
+ * @return an array of SuggestionInfo of onGetSuggestions
+ */
+ public SuggestionsInfo[] getSuggestionsMultiple(
+ TextInfo[] textInfos, String locale, int suggestionsLimit, boolean sequentialWords) {
+ final int length = textInfos.length;
+ final SuggestionsInfo[] retval = new SuggestionsInfo[length];
+ for (int i = 0; i < length; ++i) {
+ retval[i] = getSuggestions(textInfos[i], suggestionsLimit, locale);
+ retval[i].setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
+ }
+ return retval;
+ }
+
+ /**
+ * Request to abort all tasks executed in SpellChecker.
+ * This function will run on the incoming IPC thread. So, this is not called on the main thread,
+ * but will be called in series on another thread.
+ */
+ public void cancel() {}
+
+ /**
+ * Implement to return the implementation of the internal spell checker
+ * service interface. Subclasses should not override.
+ */
+ @Override
+ public final IBinder onBind(final Intent intent) {
+ return mBinder;
+ }
+
+ private static class SpellCheckerSessionImpl extends ISpellCheckerSession.Stub {
+ private final WeakReference<SpellCheckerService> mInternalServiceRef;
+ private final String mLocale;
+ private final ISpellCheckerSessionListener mListener;
+
+ public SpellCheckerSessionImpl(
+ SpellCheckerService service, String locale, ISpellCheckerSessionListener listener) {
+ mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
+ mLocale = locale;
+ mListener = listener;
+ }
+
+ @Override
+ public void getSuggestionsMultiple(
+ TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+ final SpellCheckerService service = mInternalServiceRef.get();
+ if (service == null) return;
+ try {
+ mListener.onGetSuggestions(
+ service.getSuggestionsMultiple(textInfos, mLocale,
+ suggestionsLimit, sequentialWords));
+ } catch (RemoteException e) {
+ }
+ }
+
+ @Override
+ public void cancel() {
+ final SpellCheckerService service = mInternalServiceRef.get();
+ if (service == null) return;
+ service.cancel();
+ }
+ }
+
+ private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub {
+ private final WeakReference<SpellCheckerService> mInternalServiceRef;
+
+ public SpellCheckerServiceBinder(SpellCheckerService service) {
+ mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
+ }
+
+ @Override
+ public ISpellCheckerSession getISpellCheckerSession(
+ String locale, ISpellCheckerSessionListener listener) {
+ final SpellCheckerService service = mInternalServiceRef.get();
+ if (service == null) return null;
+ return new SpellCheckerSessionImpl(service, locale, listener);
+ }
+ }
+}
diff --git a/core/java/android/service/textservice/SpellCheckerSession.java b/core/java/android/service/textservice/SpellCheckerSession.java
new file mode 100644
index 0000000..a575220
--- /dev/null
+++ b/core/java/android/service/textservice/SpellCheckerSession.java
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2011 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.service.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService.
+ */
+public class SpellCheckerSession {
+ private static final String TAG = SpellCheckerSession.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
+
+ private final InternalListener mInternalListener;
+ private final ITextServicesManager mTextServicesManager;
+ private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
+
+ private boolean mIsUsed;
+ private SpellCheckerSessionListener mSpellCheckerSessionListener;
+
+ /** Handler that will execute the main tasks */
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_GET_SUGGESTION_MULTIPLE:
+ handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj);
+ break;
+ }
+ }
+ };
+
+ /**
+ * Constructor
+ * @hide
+ */
+ public SpellCheckerSession(ITextServicesManager tsm, SpellCheckerSessionListener listener) {
+ if (listener == null || tsm == null) {
+ throw new NullPointerException();
+ }
+ mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler);
+ mInternalListener = new InternalListener();
+ mTextServicesManager = tsm;
+ mIsUsed = true;
+ mSpellCheckerSessionListener = listener;
+ }
+
+ /**
+ * @return true if the connection to a text service of this session is disconnected and not
+ * alive.
+ */
+ public boolean isSessionDisconnected() {
+ return mSpellCheckerSessionListenerImpl.isDisconnected();
+ }
+
+ /**
+ * Finish this session and allow TextServicesManagerService to disconnect the bound spell
+ * checker.
+ */
+ public void close() {
+ mIsUsed = false;
+ try {
+ mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
+ } catch (RemoteException e) {
+ // do nothing
+ }
+ }
+
+ /**
+ * Get candidate strings for a substring of the specified text.
+ * @param textInfo text metadata for a spell checker
+ * @param suggestionsLimit the number of limit of suggestions returned
+ */
+ public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
+ getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
+ }
+
+ /**
+ * A batch process of getSuggestions
+ * @param textInfos an array of text metadata for a spell checker
+ * @param suggestionsLimit the number of limit of suggestions returned
+ * @param sequentialWords true if textInfos can be treated as sequential words.
+ */
+ public void getSuggestions(
+ TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+ // TODO: Handle multiple words suggestions by using WordBreakIterator
+ mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
+ textInfos, suggestionsLimit, sequentialWords);
+ }
+
+ private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) {
+ mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos);
+ }
+
+ private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
+ private static final int TASK_CANCEL = 1;
+ private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
+ private final Queue<SpellCheckerParams> mPendingTasks =
+ new LinkedList<SpellCheckerParams>();
+ private final Handler mHandler;
+
+ private boolean mOpened;
+ private ISpellCheckerSession mISpellCheckerSession;
+
+ public SpellCheckerSessionListenerImpl(Handler handler) {
+ mOpened = false;
+ mHandler = handler;
+ }
+
+ private static class SpellCheckerParams {
+ public final int mWhat;
+ public final TextInfo[] mTextInfos;
+ public final int mSuggestionsLimit;
+ public final boolean mSequentialWords;
+ public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit,
+ boolean sequentialWords) {
+ mWhat = what;
+ mTextInfos = textInfos;
+ mSuggestionsLimit = suggestionsLimit;
+ mSequentialWords = sequentialWords;
+ }
+ }
+
+ private void processTask(SpellCheckerParams scp) {
+ switch (scp.mWhat) {
+ case TASK_CANCEL:
+ processCancel();
+ break;
+ case TASK_GET_SUGGESTIONS_MULTIPLE:
+ processGetSuggestionsMultiple(scp);
+ break;
+ }
+ }
+
+ public synchronized void onServiceConnected(ISpellCheckerSession session) {
+ mISpellCheckerSession = session;
+ mOpened = true;
+ if (DBG)
+ Log.d(TAG, "onServiceConnected - Success");
+ while (!mPendingTasks.isEmpty()) {
+ processTask(mPendingTasks.poll());
+ }
+ }
+
+ public void getSuggestionsMultiple(
+ TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
+ processOrEnqueueTask(
+ new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
+ suggestionsLimit, sequentialWords));
+ }
+
+ public boolean isDisconnected() {
+ return mOpened && mISpellCheckerSession == null;
+ }
+
+ public boolean checkOpenConnection() {
+ if (mISpellCheckerSession != null) {
+ return true;
+ }
+ Log.e(TAG, "not connected to the spellchecker service.");
+ return false;
+ }
+
+ private void processOrEnqueueTask(SpellCheckerParams scp) {
+ if (mISpellCheckerSession == null) {
+ mPendingTasks.offer(scp);
+ } else {
+ processTask(scp);
+ }
+ }
+
+ private void processCancel() {
+ if (!checkOpenConnection()) {
+ return;
+ }
+ try {
+ mISpellCheckerSession.cancel();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to cancel " + e);
+ }
+ }
+
+ private void processGetSuggestionsMultiple(SpellCheckerParams scp) {
+ if (!checkOpenConnection()) {
+ return;
+ }
+ try {
+ mISpellCheckerSession.getSuggestionsMultiple(
+ scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get suggestions " + e);
+ }
+ }
+
+ @Override
+ public void onGetSuggestions(SuggestionsInfo[] results) {
+ mHandler.sendMessage(Message.obtain(mHandler, MSG_ON_GET_SUGGESTION_MULTIPLE, results));
+ }
+ }
+
+ /**
+ * Callback for getting results from text services
+ */
+ public interface SpellCheckerSessionListener {
+ /**
+ * Callback for "getSuggestions"
+ * @param results an array of results of getSuggestions
+ */
+ public void onGetSuggestions(SuggestionsInfo[] results);
+ }
+
+ private class InternalListener extends ITextServicesSessionListener.Stub {
+ @Override
+ public void onServiceConnected(ISpellCheckerSession session) {
+ mSpellCheckerSessionListenerImpl.onServiceConnected(session);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ if (mIsUsed) {
+ Log.e(TAG, "SpellCheckerSession was not finished properly." +
+ "You should call finishShession() when you finished to use a spell checker.");
+ close();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public ITextServicesSessionListener getTextServicesSessionListener() {
+ return mInternalListener;
+ }
+
+ /**
+ * @hide
+ */
+ public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
+ return mSpellCheckerSessionListenerImpl;
+ }
+}
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.aidl b/core/java/android/view/textservice/SpellCheckerInfo.aidl
new file mode 100644
index 0000000..eb5dfcc
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+parcelable SpellCheckerInfo;
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
new file mode 100644
index 0000000..1205adf
--- /dev/null
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class is used to specify meta information of an spell checker.
+ */
+public final class SpellCheckerInfo implements Parcelable {
+ private final ResolveInfo mService;
+ private final String mId;
+
+ /**
+ * Constructor.
+ * @hide
+ */
+ public SpellCheckerInfo(Context context, ResolveInfo service) {
+ mService = service;
+ ServiceInfo si = service.serviceInfo;
+ mId = new ComponentName(si.packageName, si.name).flattenToShortString();
+ }
+
+ /**
+ * Constructor.
+ * @hide
+ */
+ public SpellCheckerInfo(Parcel source) {
+ mId = source.readString();
+ mService = ResolveInfo.CREATOR.createFromParcel(source);
+ }
+
+ /**
+ * Return a unique ID for this spell checker. The ID is generated from
+ * the package and class name implementing the method.
+ */
+ public String getId() {
+ return mId;
+ }
+
+
+ /**
+ * Return the component of the service that implements.
+ */
+ public ComponentName getComponent() {
+ return new ComponentName(
+ mService.serviceInfo.packageName, mService.serviceInfo.name);
+ }
+
+ /**
+ * Return the .apk package that implements this input method.
+ */
+ public String getPackageName() {
+ return mService.serviceInfo.packageName;
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mId);
+ mService.writeToParcel(dest, flags);
+ }
+
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<SpellCheckerInfo> CREATOR
+ = new Parcelable.Creator<SpellCheckerInfo>() {
+ @Override
+ public SpellCheckerInfo createFromParcel(Parcel source) {
+ return new SpellCheckerInfo(source);
+ }
+
+ @Override
+ public SpellCheckerInfo[] newArray(int size) {
+ return new SpellCheckerInfo[size];
+ }
+ };
+
+ /**
+ * Used to make this class parcelable.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/textservice/SuggestionsInfo.aidl b/core/java/android/view/textservice/SuggestionsInfo.aidl
new file mode 100644
index 0000000..66e20d2
--- /dev/null
+++ b/core/java/android/view/textservice/SuggestionsInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+parcelable SuggestionsInfo;
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
new file mode 100644
index 0000000..e2df7b8
--- /dev/null
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains a metadata of suggestions from the text service
+ */
+public final class SuggestionsInfo implements Parcelable {
+ /**
+ * Flag of the attributes of the suggestions that can be obtained by
+ * {@link getSuggestionsAttibutes}: this tells that the requested word was found
+ * in the dictionary in the text service.
+ */
+ public static final int RESULT_ATTR_IN_THE_DICTIONARY = 0x0001;
+ /** Flag of the attributes of the suggestions that can be obtained by
+ * {@link getSuggestionsAttibutes}: this tells that there are one or more suggestions available
+ * for the requested word. This doesn't necessarily mean that the suggestions are actually in
+ * this SuggestionsInfo. For instance, the caller could have been asked to limit the maximum
+ * number of suggestions returned.
+ */
+ public static final int RESULT_ATTR_SUGGESTIONS_AVAILABLE = 0x0002;
+ /**
+ * Flag of the attributes of the suggestions that can be obtained by
+ * {@link getSuggestionsAttibutes}: this tells that the text service thinks the requested word
+ * looks a typo.
+ */
+ public static final int RESULT_ATTR_LOOKS_TYPO = 0x0004;
+ private final int mSuggestionsAttributes;
+ private final String[] mSuggestions;
+ private int mCookie;
+ private int mSequence;
+
+ /**
+ * Constructor.
+ * @param suggestionsAttributes from the text service
+ * @param suggestions from the text service
+ */
+ public SuggestionsInfo(int suggestionsAttributes, String[] suggestions) {
+ if (suggestions == null) {
+ throw new NullPointerException();
+ }
+ mSuggestionsAttributes = suggestionsAttributes;
+ mSuggestions = suggestions;
+ mCookie = 0;
+ mSequence = 0;
+ }
+
+ /**
+ * Constructor.
+ * @param suggestionsAttributes from the text service
+ * @param suggestions from the text service
+ * @param cookie the cookie of the input TextInfo
+ * @param sequence the cookie of the input TextInfo
+ */
+ public SuggestionsInfo(
+ int suggestionsAttributes, String[] suggestions, int cookie, int sequence) {
+ if (suggestions == null) {
+ throw new NullPointerException();
+ }
+ mSuggestionsAttributes = suggestionsAttributes;
+ mSuggestions = suggestions;
+ mCookie = cookie;
+ mSequence = sequence;
+ }
+
+ public SuggestionsInfo(Parcel source) {
+ mSuggestionsAttributes = source.readInt();
+ mSuggestions = source.readStringArray();
+ mCookie = source.readInt();
+ mSequence = source.readInt();
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mSuggestionsAttributes);
+ dest.writeStringArray(mSuggestions);
+ dest.writeInt(mCookie);
+ dest.writeInt(mSequence);
+ }
+
+ /**
+ * Set the cookie and the sequence of SuggestionsInfo which are set to TextInfo from a client
+ * application
+ * @param cookie the cookie of an input TextInfo
+ * @param sequence the cookie of an input TextInfo
+ */
+ public void setCookieAndSequence(int cookie, int sequence) {
+ mCookie = cookie;
+ mSequence = sequence;
+ }
+
+ /**
+ * @return the cookie which may be set by a client application
+ */
+ public int getCookie() {
+ return mCookie;
+ }
+
+ /**
+ * @return the sequence which may be set by a client application
+ */
+ public int getSequence() {
+ return mSequence;
+ }
+
+ /**
+ * @return the attributes of suggestions. This includes whether the spell checker has the word
+ * in its dictionary or not and whether the spell checker has confident suggestions for the
+ * word or not.
+ */
+ public int getSuggestionsAttributes() {
+ return mSuggestionsAttributes;
+ }
+
+ /**
+ * @return the count of suggestions
+ */
+ public int getSuggestionsCount() {
+ return mSuggestions.length;
+ }
+
+ /**
+ * @param i the id of suggestions
+ * @return the suggestion at the specified id
+ */
+ public String getSuggestionAt(int i) {
+ return mSuggestions[i];
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<SuggestionsInfo> CREATOR
+ = new Parcelable.Creator<SuggestionsInfo>() {
+ @Override
+ public SuggestionsInfo createFromParcel(Parcel source) {
+ return new SuggestionsInfo(source);
+ }
+
+ @Override
+ public SuggestionsInfo[] newArray(int size) {
+ return new SuggestionsInfo[size];
+ }
+ };
+
+ /**
+ * Used to make this class parcelable.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/textservice/TextInfo.aidl b/core/java/android/view/textservice/TextInfo.aidl
new file mode 100644
index 0000000..d231d76
--- /dev/null
+++ b/core/java/android/view/textservice/TextInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+parcelable TextInfo;
diff --git a/core/java/android/view/textservice/TextInfo.java b/core/java/android/view/textservice/TextInfo.java
new file mode 100644
index 0000000..b534eb0
--- /dev/null
+++ b/core/java/android/view/textservice/TextInfo.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * This class contains a metadata of the input of TextService
+ */
+public final class TextInfo implements Parcelable {
+ private final String mText;
+ private final int mCookie;
+ private final int mSequence;
+
+ /**
+ * Constructor.
+ * @param text the text which will be input to TextService
+ */
+ public TextInfo(String text) {
+ this(text, 0, 0);
+ }
+
+ /**
+ * Constructor.
+ * @param text the text which will be input to TextService
+ * @param cookie the cookie for this TextInfo
+ * @param sequence the sequence number for this TextInfo
+ */
+ public TextInfo(String text, int cookie, int sequence) {
+ if (TextUtils.isEmpty(text)) {
+ throw new IllegalArgumentException(text);
+ }
+ mText = text;
+ mCookie = cookie;
+ mSequence = sequence;
+ }
+
+ public TextInfo(Parcel source) {
+ mText = source.readString();
+ mCookie = source.readInt();
+ mSequence = source.readInt();
+ }
+
+ /**
+ * Used to package this object into a {@link Parcel}.
+ *
+ * @param dest The {@link Parcel} to be written.
+ * @param flags The flags used for parceling.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mText);
+ dest.writeInt(mCookie);
+ dest.writeInt(mSequence);
+ }
+
+ /**
+ * @return the text which is an input of a text service
+ */
+ public String getText() {
+ return mText;
+ }
+
+ /**
+ * @return the cookie of TextInfo
+ */
+ public int getCookie() {
+ return mCookie;
+ }
+
+ /**
+ * @return the sequence of TextInfo
+ */
+ public int getSequence() {
+ return mSequence;
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final Parcelable.Creator<TextInfo> CREATOR
+ = new Parcelable.Creator<TextInfo>() {
+ @Override
+ public TextInfo createFromParcel(Parcel source) {
+ return new TextInfo(source);
+ }
+
+ @Override
+ public TextInfo[] newArray(int size) {
+ return new TextInfo[size];
+ }
+ };
+
+ /**
+ * Used to make this class parcelable.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/view/textservice/TextServicesManager.java b/core/java/android/view/textservice/TextServicesManager.java
new file mode 100644
index 0000000..6fa7e4d
--- /dev/null
+++ b/core/java/android/view/textservice/TextServicesManager.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2011 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.textservice;
+
+import com.android.internal.textservice.ITextServicesManager;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.textservice.SpellCheckerInfo;
+import android.service.textservice.SpellCheckerSession;
+import android.service.textservice.SpellCheckerSession.SpellCheckerSessionListener;
+
+import java.util.Locale;
+
+/**
+ * System API to the overall text services, which arbitrates interaction between applications
+ * and text services. You can retrieve an instance of this interface with
+ * {@link Context#getSystemService(String) Context.getSystemService()}.
+ *
+ * The user can change the current text services in Settings. And also applications can specify
+ * the target text services.
+ */
+public final class TextServicesManager {
+ private static final String TAG = TextServicesManager.class.getSimpleName();
+
+ private static TextServicesManager sInstance;
+ private static ITextServicesManager sService;
+
+ private TextServicesManager() {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(Context.TEXT_SERVICES_MANAGER_SERVICE);
+ sService = ITextServicesManager.Stub.asInterface(b);
+ }
+ }
+
+ /**
+ * Retrieve the global TextServicesManager instance, creating it if it doesn't already exist.
+ * @hide
+ */
+ public static TextServicesManager getInstance() {
+ synchronized (TextServicesManager.class) {
+ if (sInstance != null) {
+ return sInstance;
+ }
+ sInstance = new TextServicesManager();
+ }
+ return sInstance;
+ }
+
+
+ /**
+ * Get the current spell checker service info for the specified locale.
+ * @param locale locale of a spell checker
+ * @return SpellCheckerInfo for the specified locale.
+ */
+ // TODO: Add a method to get enabled spell checkers.
+ public SpellCheckerInfo getCurrentSpellChecker(Locale locale) {
+ if (locale == null) {
+ throw new NullPointerException("locale is null");
+ }
+ try {
+ return sService.getCurrentSpellChecker(locale.toString());
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get a spell checker session for a specified spell checker
+ * @param info SpellCheckerInfo of the spell checker
+ * @param locale the locale for the spell checker
+ * @param listener a spell checker session lister for getting results from a spell checker.
+ * @return the spell checker session of the spell checker
+ */
+ public SpellCheckerSession newSpellCheckerSession(
+ SpellCheckerInfo info, Locale locale, SpellCheckerSessionListener listener) {
+ if (info == null || locale == null || listener == null) {
+ throw new NullPointerException();
+ }
+ final SpellCheckerSession session = new SpellCheckerSession(sService, listener);
+ try {
+ sService.getSpellCheckerService(
+ info, locale.toString(), session.getTextServicesSessionListener(),
+ session.getSpellCheckerSessionListener());
+ } catch (RemoteException e) {
+ return null;
+ }
+ return session;
+ }
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerService.aidl b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
new file mode 100644
index 0000000..ff00492
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerService.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 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 com.android.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+
+/**
+ * Public interface to the global spell checker.
+ * @hide
+ */
+interface ISpellCheckerService {
+ ISpellCheckerSession getISpellCheckerSession(
+ String locale, ISpellCheckerSessionListener listener);
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
new file mode 100644
index 0000000..79e43510c0
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 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 com.android.internal.textservice;
+
+import android.view.textservice.TextInfo;
+
+/**
+ * @hide
+ */
+oneway interface ISpellCheckerSession {
+ void getSuggestionsMultiple(
+ in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
+ void cancel();
+}
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
new file mode 100644
index 0000000..796b06e
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2011 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 com.android.internal.textservice;
+
+import android.view.textservice.SuggestionsInfo;
+
+/**
+ * @hide
+ */
+oneway interface ISpellCheckerSessionListener {
+ void onGetSuggestions(in SuggestionsInfo[] results);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesManager.aidl b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
new file mode 100644
index 0000000..ad0c1ff
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ITextServicesManager.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 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 com.android.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
+import android.content.ComponentName;
+import android.view.textservice.SpellCheckerInfo;
+
+/**
+ * Interface to the text service manager.
+ * @hide
+ */
+interface ITextServicesManager {
+ SpellCheckerInfo getCurrentSpellChecker(String locale);
+ oneway void getSpellCheckerService(in SpellCheckerInfo info, in String locale,
+ in ITextServicesSessionListener tsListener,
+ in ISpellCheckerSessionListener scListener);
+ oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
+}
diff --git a/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
new file mode 100644
index 0000000..ecb6cd0
--- /dev/null
+++ b/core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 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 com.android.internal.textservice;
+
+import com.android.internal.textservice.ISpellCheckerSession;
+
+import android.view.textservice.SpellCheckerInfo;
+
+/**
+ * Interface to the text service session.
+ * @hide
+ */
+interface ITextServicesSessionListener {
+ oneway void onServiceConnected(in ISpellCheckerSession spellCheckerSession);
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c67b625..91003d1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1120,6 +1120,13 @@
android:description="@string/permdesc_bindInputMethod"
android:protectionLevel="signature" />
+ <!-- Must be required by a TextService (e.g. SpellCheckerService)
+ to ensure that only the system can bind to it. -->
+ <permission android:name="android.permission.BIND_TEXT_SERVICE"
+ android:label="@string/permlab_bindTextService"
+ android:description="@string/permdesc_bindTextService"
+ android:protectionLevel="signature" />
+
<!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
to ensure that only the system can bind to it. -->
<permission android:name="android.permission.BIND_WALLPAPER"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5b25e2d..feac38d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -705,6 +705,12 @@
interface of an input method. Should never be needed for normal applications.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_bindTextService">bind to a text service</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
+ interface of a text service(e.g. SpellCheckerService). Should never be needed for normal applications.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_bindWallpaper">bind to a wallpaper</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level