SpellCheckerService.java revision 74061ff90453c79ddbde468f630a41425da07710
1988323c57bd25a58f05dfa492d9b9c8ab62c5153satok/* 2988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Copyright (C) 2011 The Android Open Source Project 3988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 4988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * use this file except in compliance with the License. You may obtain a copy of 6988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * the License at 7988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 8988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * http://www.apache.org/licenses/LICENSE-2.0 9988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 10988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Unless required by applicable law or agreed to in writing, software 11988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * License for the specific language governing permissions and limitations under 14988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * the License. 15988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 16988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 17988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpackage android.service.textservice; 18988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 19988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerService; 20988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSession; 21988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSessionListener; 22988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 23988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.app.Service; 24988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.content.Intent; 255357806980269d846a15c845a6fcc0384fb18860satokimport android.os.Bundle; 26988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.IBinder; 27988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.RemoteException; 286be6d7548fb7c29a4d46dc985318ab2adf69f95fsatokimport android.util.Log; 29988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.SuggestionsInfo; 30988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.TextInfo; 31988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 32988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.lang.ref.WeakReference; 33988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 34988323c57bd25a58f05dfa492d9b9c8ab62c5153satok/** 35988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * SpellCheckerService provides an abstract base class for a spell checker. 36988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * This class combines a service to the system with the spell checker service interface that 37988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * spell checker must implement. 3844b75030931d9c65c9e495a86d11d71da59b4429satok * 3944b75030931d9c65c9e495a86d11d71da59b4429satok * <p>In addition to the normal Service lifecycle methods, this class 4044b75030931d9c65c9e495a86d11d71da59b4429satok * introduces a new specific callback that subclasses should override 4144b75030931d9c65c9e495a86d11d71da59b4429satok * {@link #createSession()} to provide a spell checker session that is corresponding 4244b75030931d9c65c9e495a86d11d71da59b4429satok * to requested language and so on. The spell checker session returned by this method 4344b75030931d9c65c9e495a86d11d71da59b4429satok * should extend {@link SpellCheckerService.Session}. 4444b75030931d9c65c9e495a86d11d71da59b4429satok * </p> 4544b75030931d9c65c9e495a86d11d71da59b4429satok * 4644b75030931d9c65c9e495a86d11d71da59b4429satok * <h3>Returning spell check results</h3> 4744b75030931d9c65c9e495a86d11d71da59b4429satok * 4844b75030931d9c65c9e495a86d11d71da59b4429satok * <p>{@link SpellCheckerService.Session#onGetSuggestions(TextInfo, int)} 4944b75030931d9c65c9e495a86d11d71da59b4429satok * should return spell check results. 5044b75030931d9c65c9e495a86d11d71da59b4429satok * It receives {@link android.view.textservice.TextInfo} and returns 5144b75030931d9c65c9e495a86d11d71da59b4429satok * {@link android.view.textservice.SuggestionsInfo} for the input. 5244b75030931d9c65c9e495a86d11d71da59b4429satok * You may want to override 5344b75030931d9c65c9e495a86d11d71da59b4429satok * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} for 5444b75030931d9c65c9e495a86d11d71da59b4429satok * better performance and quality. 5544b75030931d9c65c9e495a86d11d71da59b4429satok * </p> 5644b75030931d9c65c9e495a86d11d71da59b4429satok * 5744b75030931d9c65c9e495a86d11d71da59b4429satok * <p>Please note that {@link SpellCheckerService.Session#getLocale()} does not return a valid 5844b75030931d9c65c9e495a86d11d71da59b4429satok * locale before {@link SpellCheckerService.Session#onCreate()} </p> 5944b75030931d9c65c9e495a86d11d71da59b4429satok * 60988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 61988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpublic abstract class SpellCheckerService extends Service { 62988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final String TAG = SpellCheckerService.class.getSimpleName(); 636be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok private static final boolean DBG = false; 64142d7575b52d03d46246e3b142e22ebc32d45a84satok public static final String SERVICE_INTERFACE = 65142d7575b52d03d46246e3b142e22ebc32d45a84satok "android.service.textservice.SpellCheckerService"; 66988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 67988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this); 68988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 69988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 70988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 715357806980269d846a15c845a6fcc0384fb18860satok * Implement to return the implementation of the internal spell checker 725357806980269d846a15c845a6fcc0384fb18860satok * service interface. Subclasses should not override. 73988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 745357806980269d846a15c845a6fcc0384fb18860satok @Override 755357806980269d846a15c845a6fcc0384fb18860satok public final IBinder onBind(final Intent intent) { 765357806980269d846a15c845a6fcc0384fb18860satok if (DBG) { 775357806980269d846a15c845a6fcc0384fb18860satok Log.w(TAG, "onBind"); 78988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 795357806980269d846a15c845a6fcc0384fb18860satok return mBinder; 80988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 81988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 82988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 835357806980269d846a15c845a6fcc0384fb18860satok * Factory method to create a spell checker session impl 845357806980269d846a15c845a6fcc0384fb18860satok * @return SpellCheckerSessionImpl which should be overridden by a concrete implementation. 85988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 865357806980269d846a15c845a6fcc0384fb18860satok public abstract Session createSession(); 87988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 88988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 895357806980269d846a15c845a6fcc0384fb18860satok * This abstract class should be overridden by a concrete implementation of a spell checker. 90988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 91117999d1f44ec3423369385495ae207898b7b73esatok public static abstract class Session { 925357806980269d846a15c845a6fcc0384fb18860satok private InternalISpellCheckerSession mInternalSession; 935357806980269d846a15c845a6fcc0384fb18860satok 945357806980269d846a15c845a6fcc0384fb18860satok /** 955357806980269d846a15c845a6fcc0384fb18860satok * @hide 965357806980269d846a15c845a6fcc0384fb18860satok */ 975357806980269d846a15c845a6fcc0384fb18860satok public final void setInternalISpellCheckerSession(InternalISpellCheckerSession session) { 985357806980269d846a15c845a6fcc0384fb18860satok mInternalSession = session; 995357806980269d846a15c845a6fcc0384fb18860satok } 1005357806980269d846a15c845a6fcc0384fb18860satok 1015357806980269d846a15c845a6fcc0384fb18860satok /** 1025357806980269d846a15c845a6fcc0384fb18860satok * This is called after the class is initialized, at which point it knows it can call 1035357806980269d846a15c845a6fcc0384fb18860satok * getLocale() etc... 1045357806980269d846a15c845a6fcc0384fb18860satok */ 1055357806980269d846a15c845a6fcc0384fb18860satok public abstract void onCreate(); 1065357806980269d846a15c845a6fcc0384fb18860satok 1075357806980269d846a15c845a6fcc0384fb18860satok /** 1085357806980269d846a15c845a6fcc0384fb18860satok * Get suggestions for specified text in TextInfo. 1095357806980269d846a15c845a6fcc0384fb18860satok * This function will run on the incoming IPC thread. 1105357806980269d846a15c845a6fcc0384fb18860satok * So, this is not called on the main thread, 1115357806980269d846a15c845a6fcc0384fb18860satok * but will be called in series on another thread. 1125357806980269d846a15c845a6fcc0384fb18860satok * @param textInfo the text metadata 1135357806980269d846a15c845a6fcc0384fb18860satok * @param suggestionsLimit the number of limit of suggestions returned 11444b75030931d9c65c9e495a86d11d71da59b4429satok * @return SuggestionsInfo which contains suggestions for textInfo 1155357806980269d846a15c845a6fcc0384fb18860satok */ 1165357806980269d846a15c845a6fcc0384fb18860satok public abstract SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit); 1175357806980269d846a15c845a6fcc0384fb18860satok 1185357806980269d846a15c845a6fcc0384fb18860satok /** 1195357806980269d846a15c845a6fcc0384fb18860satok * A batch process of onGetSuggestions. 1205357806980269d846a15c845a6fcc0384fb18860satok * This function will run on the incoming IPC thread. 1215357806980269d846a15c845a6fcc0384fb18860satok * So, this is not called on the main thread, 1225357806980269d846a15c845a6fcc0384fb18860satok * but will be called in series on another thread. 1235357806980269d846a15c845a6fcc0384fb18860satok * @param textInfos an array of the text metadata 1245357806980269d846a15c845a6fcc0384fb18860satok * @param suggestionsLimit the number of limit of suggestions returned 1255357806980269d846a15c845a6fcc0384fb18860satok * @param sequentialWords true if textInfos can be treated as sequential words. 12644b75030931d9c65c9e495a86d11d71da59b4429satok * @return an array of SuggestionsInfo of onGetSuggestions 1275357806980269d846a15c845a6fcc0384fb18860satok */ 1285357806980269d846a15c845a6fcc0384fb18860satok public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos, 1295357806980269d846a15c845a6fcc0384fb18860satok int suggestionsLimit, boolean sequentialWords) { 1305357806980269d846a15c845a6fcc0384fb18860satok final int length = textInfos.length; 1315357806980269d846a15c845a6fcc0384fb18860satok final SuggestionsInfo[] retval = new SuggestionsInfo[length]; 1325357806980269d846a15c845a6fcc0384fb18860satok for (int i = 0; i < length; ++i) { 1335357806980269d846a15c845a6fcc0384fb18860satok retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit); 1345357806980269d846a15c845a6fcc0384fb18860satok retval[i].setCookieAndSequence( 1355357806980269d846a15c845a6fcc0384fb18860satok textInfos[i].getCookie(), textInfos[i].getSequence()); 1365357806980269d846a15c845a6fcc0384fb18860satok } 1375357806980269d846a15c845a6fcc0384fb18860satok return retval; 1385357806980269d846a15c845a6fcc0384fb18860satok } 1395357806980269d846a15c845a6fcc0384fb18860satok 1405357806980269d846a15c845a6fcc0384fb18860satok /** 1415357806980269d846a15c845a6fcc0384fb18860satok * Request to abort all tasks executed in SpellChecker. 1425357806980269d846a15c845a6fcc0384fb18860satok * This function will run on the incoming IPC thread. 1435357806980269d846a15c845a6fcc0384fb18860satok * So, this is not called on the main thread, 1445357806980269d846a15c845a6fcc0384fb18860satok * but will be called in series on another thread. 1455357806980269d846a15c845a6fcc0384fb18860satok */ 1465357806980269d846a15c845a6fcc0384fb18860satok public void onCancel() {} 1475357806980269d846a15c845a6fcc0384fb18860satok 1485357806980269d846a15c845a6fcc0384fb18860satok /** 14974061ff90453c79ddbde468f630a41425da07710satok * Request to close this session. 15074061ff90453c79ddbde468f630a41425da07710satok * This function will run on the incoming IPC thread. 15174061ff90453c79ddbde468f630a41425da07710satok * So, this is not called on the main thread, 15274061ff90453c79ddbde468f630a41425da07710satok * but will be called in series on another thread. 15374061ff90453c79ddbde468f630a41425da07710satok */ 15474061ff90453c79ddbde468f630a41425da07710satok public void onClose() {} 15574061ff90453c79ddbde468f630a41425da07710satok 15674061ff90453c79ddbde468f630a41425da07710satok /** 1575357806980269d846a15c845a6fcc0384fb18860satok * @return Locale for this session 1585357806980269d846a15c845a6fcc0384fb18860satok */ 1595357806980269d846a15c845a6fcc0384fb18860satok public String getLocale() { 1605357806980269d846a15c845a6fcc0384fb18860satok return mInternalSession.getLocale(); 1615357806980269d846a15c845a6fcc0384fb18860satok } 1625357806980269d846a15c845a6fcc0384fb18860satok 1635357806980269d846a15c845a6fcc0384fb18860satok /** 1645357806980269d846a15c845a6fcc0384fb18860satok * @return Bundle for this session 1655357806980269d846a15c845a6fcc0384fb18860satok */ 1665357806980269d846a15c845a6fcc0384fb18860satok public Bundle getBundle() { 1675357806980269d846a15c845a6fcc0384fb18860satok return mInternalSession.getBundle(); 1686be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 169988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 170988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 1715357806980269d846a15c845a6fcc0384fb18860satok // Preventing from exposing ISpellCheckerSession.aidl, create an internal class. 1725357806980269d846a15c845a6fcc0384fb18860satok private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub { 17374061ff90453c79ddbde468f630a41425da07710satok private ISpellCheckerSessionListener mListener; 1745357806980269d846a15c845a6fcc0384fb18860satok private final Session mSession; 1755357806980269d846a15c845a6fcc0384fb18860satok private final String mLocale; 1765357806980269d846a15c845a6fcc0384fb18860satok private final Bundle mBundle; 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 1785357806980269d846a15c845a6fcc0384fb18860satok public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener, 1795357806980269d846a15c845a6fcc0384fb18860satok Bundle bundle, Session session) { 180988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mListener = listener; 1815357806980269d846a15c845a6fcc0384fb18860satok mSession = session; 1825357806980269d846a15c845a6fcc0384fb18860satok mLocale = locale; 1835357806980269d846a15c845a6fcc0384fb18860satok mBundle = bundle; 1845357806980269d846a15c845a6fcc0384fb18860satok session.setInternalISpellCheckerSession(this); 185988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 186988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 187988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 1885357806980269d846a15c845a6fcc0384fb18860satok public void onGetSuggestionsMultiple( 189988323c57bd25a58f05dfa492d9b9c8ab62c5153satok TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { 190988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 191988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mListener.onGetSuggestions( 1925357806980269d846a15c845a6fcc0384fb18860satok mSession.onGetSuggestionsMultiple( 1935357806980269d846a15c845a6fcc0384fb18860satok textInfos, suggestionsLimit, sequentialWords)); 194988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch (RemoteException e) { 195988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 196988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 197988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 198988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 1995357806980269d846a15c845a6fcc0384fb18860satok public void onCancel() { 2005357806980269d846a15c845a6fcc0384fb18860satok mSession.onCancel(); 2015357806980269d846a15c845a6fcc0384fb18860satok } 2025357806980269d846a15c845a6fcc0384fb18860satok 20374061ff90453c79ddbde468f630a41425da07710satok @Override 20474061ff90453c79ddbde468f630a41425da07710satok public void onClose() { 20574061ff90453c79ddbde468f630a41425da07710satok mSession.onClose(); 20674061ff90453c79ddbde468f630a41425da07710satok mListener = null; 20774061ff90453c79ddbde468f630a41425da07710satok } 20874061ff90453c79ddbde468f630a41425da07710satok 2095357806980269d846a15c845a6fcc0384fb18860satok public String getLocale() { 2105357806980269d846a15c845a6fcc0384fb18860satok return mLocale; 2115357806980269d846a15c845a6fcc0384fb18860satok } 2125357806980269d846a15c845a6fcc0384fb18860satok 2135357806980269d846a15c845a6fcc0384fb18860satok public Bundle getBundle() { 2145357806980269d846a15c845a6fcc0384fb18860satok return mBundle; 215988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 216988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 217988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 218988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub { 219988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final WeakReference<SpellCheckerService> mInternalServiceRef; 220988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 221988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerServiceBinder(SpellCheckerService service) { 222988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mInternalServiceRef = new WeakReference<SpellCheckerService>(service); 223988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 224988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 225988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 226988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public ISpellCheckerSession getISpellCheckerSession( 2275357806980269d846a15c845a6fcc0384fb18860satok String locale, ISpellCheckerSessionListener listener, Bundle bundle) { 228988323c57bd25a58f05dfa492d9b9c8ab62c5153satok final SpellCheckerService service = mInternalServiceRef.get(); 229988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (service == null) return null; 2305357806980269d846a15c845a6fcc0384fb18860satok final Session session = service.createSession(); 2315357806980269d846a15c845a6fcc0384fb18860satok final InternalISpellCheckerSession internalSession = 2325357806980269d846a15c845a6fcc0384fb18860satok new InternalISpellCheckerSession(locale, listener, bundle, session); 2335357806980269d846a15c845a6fcc0384fb18860satok session.onCreate(); 2345357806980269d846a15c845a6fcc0384fb18860satok return internalSession; 235988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 236988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 237988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 238