blob: 84f395a02dea77d54a29aa23ef1344315ad7fd6c [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");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
satokaafd9552011-08-02 15:24:00 +090017package android.view.textservice;
satok988323c2011-06-22 16:38:13 +090018
19import com.android.internal.textservice.ISpellCheckerSession;
20import com.android.internal.textservice.ISpellCheckerSessionListener;
21import com.android.internal.textservice.ITextServicesManager;
22import com.android.internal.textservice.ITextServicesSessionListener;
23
Dianne Hackborn33b8ee52011-12-13 15:08:40 -080024import android.os.Binder;
satok988323c2011-06-22 16:38:13 +090025import android.os.Handler;
Dianne Hackborn33b8ee52011-12-13 15:08:40 -080026import android.os.HandlerThread;
satok988323c2011-06-22 16:38:13 +090027import android.os.Message;
Dianne Hackborn33b8ee52011-12-13 15:08:40 -080028import android.os.Process;
satok988323c2011-06-22 16:38:13 +090029import android.os.RemoteException;
30import android.util.Log;
satok1bedd992011-07-23 11:39:55 +090031import android.view.textservice.SpellCheckerInfo;
satok988323c2011-06-22 16:38:13 +090032import android.view.textservice.SuggestionsInfo;
33import android.view.textservice.TextInfo;
34
35import java.util.LinkedList;
36import java.util.Queue;
37
38/**
39 * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService.
satok44b75032011-10-14 14:48:59 +090040 *
41 *
42 * <a name="Applications"></a>
43 * <h3>Applications</h3>
44 *
45 * <p>In most cases, applications that are using the standard
46 * {@link android.widget.TextView} or its subclasses will have little they need
47 * to do to work well with spell checker services. The main things you need to
48 * be aware of are:</p>
49 *
50 * <ul>
51 * <li> Properly set the {@link android.R.attr#inputType} in your editable
52 * text views, so that the spell checker will have enough context to help the
53 * user in editing text in them.
54 * </ul>
55 *
56 * <p>For the rare people amongst us writing client applications that use the spell checker service
57 * directly, you will need to use {@link #getSuggestions(TextInfo, int)} or
58 * {@link #getSuggestions(TextInfo[], int, boolean)} for obtaining results from the spell checker
59 * service by yourself.</p>
60 *
61 * <h3>Security</h3>
62 *
63 * <p>There are a lot of security issues associated with spell checkers,
64 * since they could monitor all the text being sent to them
65 * through, for instance, {@link android.widget.TextView}.
66 * The Android spell checker framework also allows
67 * arbitrary third party spell checkers, so care must be taken to restrict their
68 * selection and interactions.</p>
69 *
70 * <p>Here are some key points about the security architecture behind the
71 * spell checker framework:</p>
72 *
73 * <ul>
74 * <li>Only the system is allowed to directly access a spell checker framework's
75 * {@link android.service.textservice.SpellCheckerService} interface, via the
76 * {@link android.Manifest.permission#BIND_TEXT_SERVICE} permission. This is
77 * enforced in the system by not binding to a spell checker service that does
78 * not require this permission.
79 *
80 * <li>The user must explicitly enable a new spell checker in settings before
81 * they can be enabled, to confirm with the system that they know about it
82 * and want to make it available for use.
83 * </ul>
84 *
satok988323c2011-06-22 16:38:13 +090085 */
86public class SpellCheckerSession {
87 private static final String TAG = SpellCheckerSession.class.getSimpleName();
88 private static final boolean DBG = false;
satokaafd9552011-08-02 15:24:00 +090089 /**
90 * Name under which a SpellChecker service component publishes information about itself.
91 * This meta-data must reference an XML resource.
92 **/
93 public static final String SERVICE_META_DATA = "android.view.textservice.scs";
satok988323c2011-06-22 16:38:13 +090094
95 private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
satok0dc1f642011-11-18 11:27:10 +090096 private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2;
satok988323c2011-06-22 16:38:13 +090097
98 private final InternalListener mInternalListener;
99 private final ITextServicesManager mTextServicesManager;
satok1bedd992011-07-23 11:39:55 +0900100 private final SpellCheckerInfo mSpellCheckerInfo;
satok988323c2011-06-22 16:38:13 +0900101 private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
satok0dc1f642011-11-18 11:27:10 +0900102 private final SpellCheckerSubtype mSubtype;
satok988323c2011-06-22 16:38:13 +0900103
104 private boolean mIsUsed;
105 private SpellCheckerSessionListener mSpellCheckerSessionListener;
106
107 /** Handler that will execute the main tasks */
108 private final Handler mHandler = new Handler() {
109 @Override
110 public void handleMessage(Message msg) {
111 switch (msg.what) {
112 case MSG_ON_GET_SUGGESTION_MULTIPLE:
113 handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj);
114 break;
satok0dc1f642011-11-18 11:27:10 +0900115 case MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE:
satokd404fe12012-02-22 06:38:18 +0900116 handleOnGetSentenceSuggestionsMultiple((SentenceSuggestionsInfo[]) msg.obj);
satok0dc1f642011-11-18 11:27:10 +0900117 break;
satok988323c2011-06-22 16:38:13 +0900118 }
119 }
120 };
121
122 /**
123 * Constructor
124 * @hide
125 */
satok1bedd992011-07-23 11:39:55 +0900126 public SpellCheckerSession(
satok0dc1f642011-11-18 11:27:10 +0900127 SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener,
128 SpellCheckerSubtype subtype) {
satok1bedd992011-07-23 11:39:55 +0900129 if (info == null || listener == null || tsm == null) {
satok988323c2011-06-22 16:38:13 +0900130 throw new NullPointerException();
131 }
satok1bedd992011-07-23 11:39:55 +0900132 mSpellCheckerInfo = info;
satok988323c2011-06-22 16:38:13 +0900133 mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler);
Jean Chalarda80838d2011-10-20 19:33:53 +0900134 mInternalListener = new InternalListener(mSpellCheckerSessionListenerImpl);
satok988323c2011-06-22 16:38:13 +0900135 mTextServicesManager = tsm;
136 mIsUsed = true;
137 mSpellCheckerSessionListener = listener;
satok0dc1f642011-11-18 11:27:10 +0900138 mSubtype = subtype;
satok988323c2011-06-22 16:38:13 +0900139 }
140
141 /**
142 * @return true if the connection to a text service of this session is disconnected and not
143 * alive.
144 */
145 public boolean isSessionDisconnected() {
146 return mSpellCheckerSessionListenerImpl.isDisconnected();
147 }
148
149 /**
satok1bedd992011-07-23 11:39:55 +0900150 * Get the spell checker service info this spell checker session has.
151 * @return SpellCheckerInfo for the specified locale.
152 */
153 public SpellCheckerInfo getSpellChecker() {
154 return mSpellCheckerInfo;
155 }
156
157 /**
satokb4aff972011-11-03 04:12:51 +0900158 * Cancel pending and running spell check tasks
159 */
160 public void cancel() {
161 mSpellCheckerSessionListenerImpl.cancel();
162 }
163
164 /**
satok988323c2011-06-22 16:38:13 +0900165 * Finish this session and allow TextServicesManagerService to disconnect the bound spell
166 * checker.
167 */
168 public void close() {
169 mIsUsed = false;
170 try {
satok74061ff2011-11-02 11:20:33 +0900171 mSpellCheckerSessionListenerImpl.close();
satok988323c2011-06-22 16:38:13 +0900172 mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
173 } catch (RemoteException e) {
174 // do nothing
175 }
176 }
177
178 /**
satok6183cd62012-03-27 12:08:29 +0900179 * Get suggestions from the specified sentences
180 * @param textInfos an array of text metadata for a spell checker
181 * @param suggestionsLimit the maximum number of suggestions that will be returned
satok0dc1f642011-11-18 11:27:10 +0900182 */
satok6183cd62012-03-27 12:08:29 +0900183 public void getSentenceSuggestions(TextInfo[] textInfos, int suggestionsLimit) {
satokd404fe12012-02-22 06:38:18 +0900184 mSpellCheckerSessionListenerImpl.getSentenceSuggestionsMultiple(
satok6183cd62012-03-27 12:08:29 +0900185 textInfos, suggestionsLimit);
satok0dc1f642011-11-18 11:27:10 +0900186 }
187
188 /**
satok988323c2011-06-22 16:38:13 +0900189 * Get candidate strings for a substring of the specified text.
190 * @param textInfo text metadata for a spell checker
satok6183cd62012-03-27 12:08:29 +0900191 * @param suggestionsLimit the maximum number of suggestions that will be returned
satokc7ee1b92012-04-11 20:40:07 +0900192 * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
satok988323c2011-06-22 16:38:13 +0900193 */
satokc7ee1b92012-04-11 20:40:07 +0900194 @Deprecated
satok988323c2011-06-22 16:38:13 +0900195 public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
196 getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
197 }
198
199 /**
200 * A batch process of getSuggestions
201 * @param textInfos an array of text metadata for a spell checker
satok6183cd62012-03-27 12:08:29 +0900202 * @param suggestionsLimit the maximum number of suggestions that will be returned
satok988323c2011-06-22 16:38:13 +0900203 * @param sequentialWords true if textInfos can be treated as sequential words.
satokc7ee1b92012-04-11 20:40:07 +0900204 * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
satok988323c2011-06-22 16:38:13 +0900205 */
satokc7ee1b92012-04-11 20:40:07 +0900206 @Deprecated
satok988323c2011-06-22 16:38:13 +0900207 public void getSuggestions(
208 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
satok6be6d752011-07-28 20:40:38 +0900209 if (DBG) {
210 Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
211 }
satok988323c2011-06-22 16:38:13 +0900212 mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
213 textInfos, suggestionsLimit, sequentialWords);
214 }
215
216 private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) {
217 mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos);
218 }
219
satokd404fe12012-02-22 06:38:18 +0900220 private void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionInfos) {
221 mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionInfos);
satok0dc1f642011-11-18 11:27:10 +0900222 }
223
satok988323c2011-06-22 16:38:13 +0900224 private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
225 private static final int TASK_CANCEL = 1;
226 private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
satok74061ff2011-11-02 11:20:33 +0900227 private static final int TASK_CLOSE = 3;
satok0dc1f642011-11-18 11:27:10 +0900228 private static final int TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE = 4;
satok988323c2011-06-22 16:38:13 +0900229 private final Queue<SpellCheckerParams> mPendingTasks =
230 new LinkedList<SpellCheckerParams>();
satok060677f2011-11-17 09:40:56 +0900231 private Handler mHandler;
satok988323c2011-06-22 16:38:13 +0900232
233 private boolean mOpened;
234 private ISpellCheckerSession mISpellCheckerSession;
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800235 private HandlerThread mThread;
236 private Handler mAsyncHandler;
satok988323c2011-06-22 16:38:13 +0900237
238 public SpellCheckerSessionListenerImpl(Handler handler) {
239 mOpened = false;
240 mHandler = handler;
241 }
242
243 private static class SpellCheckerParams {
244 public final int mWhat;
245 public final TextInfo[] mTextInfos;
246 public final int mSuggestionsLimit;
247 public final boolean mSequentialWords;
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800248 public ISpellCheckerSession mSession;
satok988323c2011-06-22 16:38:13 +0900249 public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit,
250 boolean sequentialWords) {
251 mWhat = what;
252 mTextInfos = textInfos;
253 mSuggestionsLimit = suggestionsLimit;
254 mSequentialWords = sequentialWords;
255 }
256 }
257
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800258 private void processTask(ISpellCheckerSession session, SpellCheckerParams scp,
259 boolean async) {
260 if (async || mAsyncHandler == null) {
261 switch (scp.mWhat) {
262 case TASK_CANCEL:
263 if (DBG) {
264 Log.w(TAG, "Cancel spell checker tasks.");
265 }
266 try {
267 session.onCancel();
268 } catch (RemoteException e) {
269 Log.e(TAG, "Failed to cancel " + e);
270 }
271 break;
272 case TASK_GET_SUGGESTIONS_MULTIPLE:
273 if (DBG) {
274 Log.w(TAG, "Get suggestions from the spell checker.");
275 }
276 try {
277 session.onGetSuggestionsMultiple(scp.mTextInfos,
278 scp.mSuggestionsLimit, scp.mSequentialWords);
279 } catch (RemoteException e) {
280 Log.e(TAG, "Failed to get suggestions " + e);
281 }
282 break;
Dianne Hackbornb5052de2011-12-13 16:31:43 -0800283 case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
284 if (DBG) {
satokc7ee1b92012-04-11 20:40:07 +0900285 Log.w(TAG, "Get sentence suggestions from the spell checker.");
Dianne Hackbornb5052de2011-12-13 16:31:43 -0800286 }
Dianne Hackbornb5052de2011-12-13 16:31:43 -0800287 try {
satokd404fe12012-02-22 06:38:18 +0900288 session.onGetSentenceSuggestionsMultiple(
Dianne Hackbornb5052de2011-12-13 16:31:43 -0800289 scp.mTextInfos, scp.mSuggestionsLimit);
290 } catch (RemoteException e) {
291 Log.e(TAG, "Failed to get suggestions " + e);
292 }
293 break;
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800294 case TASK_CLOSE:
295 if (DBG) {
296 Log.w(TAG, "Close spell checker tasks.");
297 }
298 try {
299 session.onClose();
300 } catch (RemoteException e) {
301 Log.e(TAG, "Failed to close " + e);
302 }
303 break;
304 }
305 } else {
306 // The interface is to a local object, so need to execute it
307 // asynchronously.
308 scp.mSession = session;
309 mAsyncHandler.sendMessage(Message.obtain(mAsyncHandler, 1, scp));
310 }
311
312 if (scp.mWhat == TASK_CLOSE) {
313 // If we are closing, we want to clean up our state now even
314 // if it is pending as an async operation.
315 synchronized (this) {
316 mISpellCheckerSession = null;
317 mHandler = null;
318 if (mThread != null) {
319 mThread.quit();
320 }
321 mThread = null;
322 mAsyncHandler = null;
323 }
satok988323c2011-06-22 16:38:13 +0900324 }
325 }
326
327 public synchronized void onServiceConnected(ISpellCheckerSession session) {
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800328 synchronized (this) {
329 mISpellCheckerSession = session;
330 if (session.asBinder() instanceof Binder && mThread == null) {
331 // If this is a local object, we need to do our own threading
332 // to make sure we handle it asynchronously.
333 mThread = new HandlerThread("SpellCheckerSession",
334 Process.THREAD_PRIORITY_BACKGROUND);
335 mThread.start();
336 mAsyncHandler = new Handler(mThread.getLooper()) {
337 @Override public void handleMessage(Message msg) {
338 SpellCheckerParams scp = (SpellCheckerParams)msg.obj;
339 processTask(scp.mSession, scp, true);
340 }
341 };
342 }
343 mOpened = true;
344 }
satok988323c2011-06-22 16:38:13 +0900345 if (DBG)
346 Log.d(TAG, "onServiceConnected - Success");
347 while (!mPendingTasks.isEmpty()) {
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800348 processTask(session, mPendingTasks.poll(), false);
satok988323c2011-06-22 16:38:13 +0900349 }
350 }
351
satokb4aff972011-11-03 04:12:51 +0900352 public void cancel() {
353 if (DBG) {
354 Log.w(TAG, "cancel");
355 }
356 processOrEnqueueTask(new SpellCheckerParams(TASK_CANCEL, null, 0, false));
357 }
358
satok988323c2011-06-22 16:38:13 +0900359 public void getSuggestionsMultiple(
360 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
satok6be6d752011-07-28 20:40:38 +0900361 if (DBG) {
362 Log.w(TAG, "getSuggestionsMultiple");
363 }
satok988323c2011-06-22 16:38:13 +0900364 processOrEnqueueTask(
365 new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
366 suggestionsLimit, sequentialWords));
367 }
368
satokd404fe12012-02-22 06:38:18 +0900369 public void getSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) {
satok0dc1f642011-11-18 11:27:10 +0900370 if (DBG) {
satokd404fe12012-02-22 06:38:18 +0900371 Log.w(TAG, "getSentenceSuggestionsMultiple");
satok0dc1f642011-11-18 11:27:10 +0900372 }
373 processOrEnqueueTask(
374 new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE,
375 textInfos, suggestionsLimit, false));
376 }
377
satok74061ff2011-11-02 11:20:33 +0900378 public void close() {
379 if (DBG) {
380 Log.w(TAG, "close");
381 }
382 processOrEnqueueTask(new SpellCheckerParams(TASK_CLOSE, null, 0, false));
383 }
384
satok988323c2011-06-22 16:38:13 +0900385 public boolean isDisconnected() {
386 return mOpened && mISpellCheckerSession == null;
387 }
388
satok988323c2011-06-22 16:38:13 +0900389 private void processOrEnqueueTask(SpellCheckerParams scp) {
satok6be6d752011-07-28 20:40:38 +0900390 if (DBG) {
391 Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession);
392 }
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800393 ISpellCheckerSession session;
394 synchronized (this) {
395 session = mISpellCheckerSession;
396 if (session == null) {
397 SpellCheckerParams closeTask = null;
398 if (scp.mWhat == TASK_CANCEL) {
399 while (!mPendingTasks.isEmpty()) {
400 final SpellCheckerParams tmp = mPendingTasks.poll();
401 if (tmp.mWhat == TASK_CLOSE) {
satokd404fe12012-02-22 06:38:18 +0900402 // Only one close task should be processed, while we need to remove
403 // all close tasks from the queue
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800404 closeTask = tmp;
405 }
satokb4aff972011-11-03 04:12:51 +0900406 }
407 }
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800408 mPendingTasks.offer(scp);
409 if (closeTask != null) {
410 mPendingTasks.offer(closeTask);
411 }
412 return;
satokb4aff972011-11-03 04:12:51 +0900413 }
satok988323c2011-06-22 16:38:13 +0900414 }
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800415 processTask(session, scp, false);
satok0dc1f642011-11-18 11:27:10 +0900416 }
417
satok988323c2011-06-22 16:38:13 +0900418 @Override
419 public void onGetSuggestions(SuggestionsInfo[] results) {
Dianne Hackborn33b8ee52011-12-13 15:08:40 -0800420 synchronized (this) {
421 if (mHandler != null) {
422 mHandler.sendMessage(Message.obtain(mHandler,
423 MSG_ON_GET_SUGGESTION_MULTIPLE, results));
424 }
425 }
satok988323c2011-06-22 16:38:13 +0900426 }
satok0dc1f642011-11-18 11:27:10 +0900427
428 @Override
satokd404fe12012-02-22 06:38:18 +0900429 public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
Keisuke Kuroyanagibf9767c2014-05-30 19:22:43 +0900430 synchronized (this) {
431 if (mHandler != null) {
432 mHandler.sendMessage(Message.obtain(mHandler,
433 MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE, results));
434 }
435 }
satok0dc1f642011-11-18 11:27:10 +0900436 }
satok988323c2011-06-22 16:38:13 +0900437 }
438
439 /**
440 * Callback for getting results from text services
441 */
442 public interface SpellCheckerSessionListener {
443 /**
satokf6710612012-03-30 18:31:36 +0900444 * Callback for {@link SpellCheckerSession#getSuggestions(TextInfo, int)}
445 * and {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
satok6183cd62012-03-27 12:08:29 +0900446 * @param results an array of {@link SuggestionsInfo}s.
447 * These results are suggestions for {@link TextInfo}s queried by
satokf6710612012-03-30 18:31:36 +0900448 * {@link SpellCheckerSession#getSuggestions(TextInfo, int)} or
449 * {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)}
satok988323c2011-06-22 16:38:13 +0900450 */
451 public void onGetSuggestions(SuggestionsInfo[] results);
satok0dc1f642011-11-18 11:27:10 +0900452 /**
satok6183cd62012-03-27 12:08:29 +0900453 * Callback for {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)}
454 * @param results an array of {@link SentenceSuggestionsInfo}s.
455 * These results are suggestions for {@link TextInfo}s
456 * queried by {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)}.
satok0dc1f642011-11-18 11:27:10 +0900457 */
satokd404fe12012-02-22 06:38:18 +0900458 public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results);
satok988323c2011-06-22 16:38:13 +0900459 }
460
Jean Chalarda80838d2011-10-20 19:33:53 +0900461 private static class InternalListener extends ITextServicesSessionListener.Stub {
462 private final SpellCheckerSessionListenerImpl mParentSpellCheckerSessionListenerImpl;
463
464 public InternalListener(SpellCheckerSessionListenerImpl spellCheckerSessionListenerImpl) {
465 mParentSpellCheckerSessionListenerImpl = spellCheckerSessionListenerImpl;
466 }
467
satok988323c2011-06-22 16:38:13 +0900468 @Override
469 public void onServiceConnected(ISpellCheckerSession session) {
satok6be6d752011-07-28 20:40:38 +0900470 if (DBG) {
471 Log.w(TAG, "SpellCheckerSession connected.");
472 }
Jean Chalarda80838d2011-10-20 19:33:53 +0900473 mParentSpellCheckerSessionListenerImpl.onServiceConnected(session);
satok988323c2011-06-22 16:38:13 +0900474 }
475 }
476
477 @Override
478 protected void finalize() throws Throwable {
479 super.finalize();
480 if (mIsUsed) {
481 Log.e(TAG, "SpellCheckerSession was not finished properly." +
482 "You should call finishShession() when you finished to use a spell checker.");
483 close();
484 }
485 }
486
487 /**
488 * @hide
489 */
490 public ITextServicesSessionListener getTextServicesSessionListener() {
491 return mInternalListener;
492 }
493
494 /**
495 * @hide
496 */
497 public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
498 return mSpellCheckerSessionListenerImpl;
499 }
satok988323c2011-06-22 16:38:13 +0900500}