blob: 5282e610c30ec2aa6c643471b6abd5a41977d8de [file] [log] [blame]
satok988323c2011-06-22 16:38:13 +09001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package android.service.textservice;
18
19import com.android.internal.textservice.ISpellCheckerService;
20import com.android.internal.textservice.ISpellCheckerSession;
21import com.android.internal.textservice.ISpellCheckerSessionListener;
22
23import android.app.Service;
24import android.content.Intent;
satok53578062011-08-03 16:08:59 +090025import android.os.Bundle;
satok988323c2011-06-22 16:38:13 +090026import android.os.IBinder;
27import android.os.RemoteException;
satok6be6d752011-07-28 20:40:38 +090028import android.util.Log;
satok988323c2011-06-22 16:38:13 +090029import android.view.textservice.SuggestionsInfo;
30import android.view.textservice.TextInfo;
31
32import java.lang.ref.WeakReference;
33
34/**
35 * SpellCheckerService provides an abstract base class for a spell checker.
36 * This class combines a service to the system with the spell checker service interface that
37 * spell checker must implement.
satok44b75032011-10-14 14:48:59 +090038 *
39 * <p>In addition to the normal Service lifecycle methods, this class
40 * introduces a new specific callback that subclasses should override
41 * {@link #createSession()} to provide a spell checker session that is corresponding
42 * to requested language and so on. The spell checker session returned by this method
43 * should extend {@link SpellCheckerService.Session}.
44 * </p>
45 *
46 * <h3>Returning spell check results</h3>
47 *
48 * <p>{@link SpellCheckerService.Session#onGetSuggestions(TextInfo, int)}
49 * should return spell check results.
50 * It receives {@link android.view.textservice.TextInfo} and returns
51 * {@link android.view.textservice.SuggestionsInfo} for the input.
52 * You may want to override
53 * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} for
54 * better performance and quality.
55 * </p>
56 *
57 * <p>Please note that {@link SpellCheckerService.Session#getLocale()} does not return a valid
58 * locale before {@link SpellCheckerService.Session#onCreate()} </p>
59 *
satok988323c2011-06-22 16:38:13 +090060 */
61public abstract class SpellCheckerService extends Service {
62 private static final String TAG = SpellCheckerService.class.getSimpleName();
satok6be6d752011-07-28 20:40:38 +090063 private static final boolean DBG = false;
satok142d7572011-07-25 11:01:49 +090064 public static final String SERVICE_INTERFACE =
65 "android.service.textservice.SpellCheckerService";
satok988323c2011-06-22 16:38:13 +090066
67 private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
68
satok988323c2011-06-22 16:38:13 +090069
70 /**
71 * Implement to return the implementation of the internal spell checker
72 * service interface. Subclasses should not override.
73 */
74 @Override
75 public final IBinder onBind(final Intent intent) {
satok6be6d752011-07-28 20:40:38 +090076 if (DBG) {
77 Log.w(TAG, "onBind");
78 }
satok988323c2011-06-22 16:38:13 +090079 return mBinder;
80 }
81
satok53578062011-08-03 16:08:59 +090082 /**
83 * Factory method to create a spell checker session impl
84 * @return SpellCheckerSessionImpl which should be overridden by a concrete implementation.
85 */
86 public abstract Session createSession();
satok988323c2011-06-22 16:38:13 +090087
satok53578062011-08-03 16:08:59 +090088 /**
89 * This abstract class should be overridden by a concrete implementation of a spell checker.
90 */
satok117999d2011-09-02 17:55:43 +090091 public static abstract class Session {
satok53578062011-08-03 16:08:59 +090092 private InternalISpellCheckerSession mInternalSession;
93
94 /**
95 * @hide
96 */
97 public final void setInternalISpellCheckerSession(InternalISpellCheckerSession session) {
98 mInternalSession = session;
99 }
100
101 /**
102 * This is called after the class is initialized, at which point it knows it can call
103 * getLocale() etc...
104 */
105 public abstract void onCreate();
106
107 /**
108 * Get suggestions for specified text in TextInfo.
109 * This function will run on the incoming IPC thread.
110 * So, this is not called on the main thread,
111 * but will be called in series on another thread.
112 * @param textInfo the text metadata
113 * @param suggestionsLimit the number of limit of suggestions returned
satok44b75032011-10-14 14:48:59 +0900114 * @return SuggestionsInfo which contains suggestions for textInfo
satok53578062011-08-03 16:08:59 +0900115 */
116 public abstract SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit);
117
118 /**
119 * A batch process of onGetSuggestions.
120 * This function will run on the incoming IPC thread.
121 * So, this is not called on the main thread,
122 * but will be called in series on another thread.
123 * @param textInfos an array of the text metadata
124 * @param suggestionsLimit the number of limit of suggestions returned
125 * @param sequentialWords true if textInfos can be treated as sequential words.
satok44b75032011-10-14 14:48:59 +0900126 * @return an array of SuggestionsInfo of onGetSuggestions
satok53578062011-08-03 16:08:59 +0900127 */
128 public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos,
129 int suggestionsLimit, boolean sequentialWords) {
130 final int length = textInfos.length;
131 final SuggestionsInfo[] retval = new SuggestionsInfo[length];
132 for (int i = 0; i < length; ++i) {
133 retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit);
134 retval[i].setCookieAndSequence(
135 textInfos[i].getCookie(), textInfos[i].getSequence());
136 }
137 return retval;
138 }
139
140 /**
satok0dc1f642011-11-18 11:27:10 +0900141 * @hide
142 * The default implementation returns an array of SuggestionsInfo by simply calling
143 * onGetSuggestions().
144 * When you override this method, make sure that suggestionsLimit is applied to suggestions
145 * that share the same start position and length.
146 */
147 public SuggestionsInfo[] onGetSuggestionsMultipleForSentence(TextInfo[] textInfos,
148 int suggestionsLimit) {
149 final int length = textInfos.length;
150 final SuggestionsInfo[] retval = new SuggestionsInfo[length];
151 for (int i = 0; i < length; ++i) {
152 retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit);
153 retval[i].setCookieAndSequence(
154 textInfos[i].getCookie(), textInfos[i].getSequence());
155 }
156 return retval;
157 }
158
159 /**
satok53578062011-08-03 16:08:59 +0900160 * Request to abort all tasks executed in SpellChecker.
161 * This function will run on the incoming IPC thread.
162 * So, this is not called on the main thread,
163 * but will be called in series on another thread.
164 */
165 public void onCancel() {}
166
167 /**
satok74061ff2011-11-02 11:20:33 +0900168 * Request to close this session.
169 * This function will run on the incoming IPC thread.
170 * So, this is not called on the main thread,
171 * but will be called in series on another thread.
172 */
173 public void onClose() {}
174
175 /**
satok53578062011-08-03 16:08:59 +0900176 * @return Locale for this session
177 */
178 public String getLocale() {
179 return mInternalSession.getLocale();
180 }
181
182 /**
183 * @return Bundle for this session
184 */
185 public Bundle getBundle() {
186 return mInternalSession.getBundle();
187 }
188 }
189
190 // Preventing from exposing ISpellCheckerSession.aidl, create an internal class.
191 private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub {
satok74061ff2011-11-02 11:20:33 +0900192 private ISpellCheckerSessionListener mListener;
satok53578062011-08-03 16:08:59 +0900193 private final Session mSession;
194 private final String mLocale;
195 private final Bundle mBundle;
196
197 public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener,
198 Bundle bundle, Session session) {
satok988323c2011-06-22 16:38:13 +0900199 mListener = listener;
satok53578062011-08-03 16:08:59 +0900200 mSession = session;
201 mLocale = locale;
202 mBundle = bundle;
203 session.setInternalISpellCheckerSession(this);
satok988323c2011-06-22 16:38:13 +0900204 }
205
206 @Override
satok53578062011-08-03 16:08:59 +0900207 public void onGetSuggestionsMultiple(
satok988323c2011-06-22 16:38:13 +0900208 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
satok988323c2011-06-22 16:38:13 +0900209 try {
210 mListener.onGetSuggestions(
satok53578062011-08-03 16:08:59 +0900211 mSession.onGetSuggestionsMultiple(
212 textInfos, suggestionsLimit, sequentialWords));
satok988323c2011-06-22 16:38:13 +0900213 } catch (RemoteException e) {
214 }
215 }
216
217 @Override
satok0dc1f642011-11-18 11:27:10 +0900218 public void onGetSuggestionsMultipleForSentence(
219 TextInfo[] textInfos, int suggestionsLimit) {
220 try {
221 mListener.onGetSuggestionsForSentence(
222 mSession.onGetSuggestionsMultipleForSentence(textInfos, suggestionsLimit));
223 } catch (RemoteException e) {
224 }
225 }
226
227 @Override
satok53578062011-08-03 16:08:59 +0900228 public void onCancel() {
229 mSession.onCancel();
230 }
231
satok74061ff2011-11-02 11:20:33 +0900232 @Override
233 public void onClose() {
234 mSession.onClose();
235 mListener = null;
236 }
237
satok53578062011-08-03 16:08:59 +0900238 public String getLocale() {
239 return mLocale;
240 }
241
242 public Bundle getBundle() {
243 return mBundle;
satok988323c2011-06-22 16:38:13 +0900244 }
245 }
246
247 private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub {
248 private final WeakReference<SpellCheckerService> mInternalServiceRef;
249
250 public SpellCheckerServiceBinder(SpellCheckerService service) {
251 mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
252 }
253
254 @Override
255 public ISpellCheckerSession getISpellCheckerSession(
satok53578062011-08-03 16:08:59 +0900256 String locale, ISpellCheckerSessionListener listener, Bundle bundle) {
satok988323c2011-06-22 16:38:13 +0900257 final SpellCheckerService service = mInternalServiceRef.get();
258 if (service == null) return null;
satok53578062011-08-03 16:08:59 +0900259 final Session session = service.createSession();
260 final InternalISpellCheckerSession internalSession =
261 new InternalISpellCheckerSession(locale, listener, bundle, session);
262 session.onCreate();
263 return internalSession;
satok988323c2011-06-22 16:38:13 +0900264 }
265 }
266}