SpellCheckerSession.java revision b5052de75736527549d7e537632777c6fec2e4f0
1988323c57bd25a58f05dfa492d9b9c8ab62c5153satok/* 2988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Copyright (C) 2011 The Android Open Source Project 3988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * 4988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Licensed under the Apache License, Version 2.0 (the "License"); 5988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * you may not use this file except in compliance with the License. 6988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * You may obtain a copy of 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, 12988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * See the License for the specific language governing permissions and 14988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * limitations under the License. 15988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 16988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 17aafd955fa8f5c31c511763c0f826b6d7acf15b9csatokpackage android.view.textservice; 18988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 19988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSession; 20988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ISpellCheckerSessionListener; 21988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ITextServicesManager; 22988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport com.android.internal.textservice.ITextServicesSessionListener; 23988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 2433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackbornimport android.os.Binder; 25988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.Handler; 2633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackbornimport android.os.HandlerThread; 27988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.Message; 2833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackbornimport android.os.Process; 29988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.os.RemoteException; 30988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.util.Log; 311bedd99761e3d2acdac947d641e7fee5db556141satokimport android.view.textservice.SpellCheckerInfo; 32988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.SuggestionsInfo; 33988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport android.view.textservice.TextInfo; 34988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 35988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.LinkedList; 36988323c57bd25a58f05dfa492d9b9c8ab62c5153satokimport java.util.Queue; 37988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 38988323c57bd25a58f05dfa492d9b9c8ab62c5153satok/** 39988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * The SpellCheckerSession interface provides the per client functionality of SpellCheckerService. 4044b75030931d9c65c9e495a86d11d71da59b4429satok * 4144b75030931d9c65c9e495a86d11d71da59b4429satok * 4244b75030931d9c65c9e495a86d11d71da59b4429satok * <a name="Applications"></a> 4344b75030931d9c65c9e495a86d11d71da59b4429satok * <h3>Applications</h3> 4444b75030931d9c65c9e495a86d11d71da59b4429satok * 4544b75030931d9c65c9e495a86d11d71da59b4429satok * <p>In most cases, applications that are using the standard 4644b75030931d9c65c9e495a86d11d71da59b4429satok * {@link android.widget.TextView} or its subclasses will have little they need 4744b75030931d9c65c9e495a86d11d71da59b4429satok * to do to work well with spell checker services. The main things you need to 4844b75030931d9c65c9e495a86d11d71da59b4429satok * be aware of are:</p> 4944b75030931d9c65c9e495a86d11d71da59b4429satok * 5044b75030931d9c65c9e495a86d11d71da59b4429satok * <ul> 5144b75030931d9c65c9e495a86d11d71da59b4429satok * <li> Properly set the {@link android.R.attr#inputType} in your editable 5244b75030931d9c65c9e495a86d11d71da59b4429satok * text views, so that the spell checker will have enough context to help the 5344b75030931d9c65c9e495a86d11d71da59b4429satok * user in editing text in them. 5444b75030931d9c65c9e495a86d11d71da59b4429satok * </ul> 5544b75030931d9c65c9e495a86d11d71da59b4429satok * 5644b75030931d9c65c9e495a86d11d71da59b4429satok * <p>For the rare people amongst us writing client applications that use the spell checker service 5744b75030931d9c65c9e495a86d11d71da59b4429satok * directly, you will need to use {@link #getSuggestions(TextInfo, int)} or 5844b75030931d9c65c9e495a86d11d71da59b4429satok * {@link #getSuggestions(TextInfo[], int, boolean)} for obtaining results from the spell checker 5944b75030931d9c65c9e495a86d11d71da59b4429satok * service by yourself.</p> 6044b75030931d9c65c9e495a86d11d71da59b4429satok * 6144b75030931d9c65c9e495a86d11d71da59b4429satok * <h3>Security</h3> 6244b75030931d9c65c9e495a86d11d71da59b4429satok * 6344b75030931d9c65c9e495a86d11d71da59b4429satok * <p>There are a lot of security issues associated with spell checkers, 6444b75030931d9c65c9e495a86d11d71da59b4429satok * since they could monitor all the text being sent to them 6544b75030931d9c65c9e495a86d11d71da59b4429satok * through, for instance, {@link android.widget.TextView}. 6644b75030931d9c65c9e495a86d11d71da59b4429satok * The Android spell checker framework also allows 6744b75030931d9c65c9e495a86d11d71da59b4429satok * arbitrary third party spell checkers, so care must be taken to restrict their 6844b75030931d9c65c9e495a86d11d71da59b4429satok * selection and interactions.</p> 6944b75030931d9c65c9e495a86d11d71da59b4429satok * 7044b75030931d9c65c9e495a86d11d71da59b4429satok * <p>Here are some key points about the security architecture behind the 7144b75030931d9c65c9e495a86d11d71da59b4429satok * spell checker framework:</p> 7244b75030931d9c65c9e495a86d11d71da59b4429satok * 7344b75030931d9c65c9e495a86d11d71da59b4429satok * <ul> 7444b75030931d9c65c9e495a86d11d71da59b4429satok * <li>Only the system is allowed to directly access a spell checker framework's 7544b75030931d9c65c9e495a86d11d71da59b4429satok * {@link android.service.textservice.SpellCheckerService} interface, via the 7644b75030931d9c65c9e495a86d11d71da59b4429satok * {@link android.Manifest.permission#BIND_TEXT_SERVICE} permission. This is 7744b75030931d9c65c9e495a86d11d71da59b4429satok * enforced in the system by not binding to a spell checker service that does 7844b75030931d9c65c9e495a86d11d71da59b4429satok * not require this permission. 7944b75030931d9c65c9e495a86d11d71da59b4429satok * 8044b75030931d9c65c9e495a86d11d71da59b4429satok * <li>The user must explicitly enable a new spell checker in settings before 8144b75030931d9c65c9e495a86d11d71da59b4429satok * they can be enabled, to confirm with the system that they know about it 8244b75030931d9c65c9e495a86d11d71da59b4429satok * and want to make it available for use. 8344b75030931d9c65c9e495a86d11d71da59b4429satok * </ul> 8444b75030931d9c65c9e495a86d11d71da59b4429satok * 85988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 86988323c57bd25a58f05dfa492d9b9c8ab62c5153satokpublic class SpellCheckerSession { 87988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final String TAG = SpellCheckerSession.class.getSimpleName(); 88988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final boolean DBG = false; 89aafd955fa8f5c31c511763c0f826b6d7acf15b9csatok /** 90aafd955fa8f5c31c511763c0f826b6d7acf15b9csatok * Name under which a SpellChecker service component publishes information about itself. 91aafd955fa8f5c31c511763c0f826b6d7acf15b9csatok * This meta-data must reference an XML resource. 92aafd955fa8f5c31c511763c0f826b6d7acf15b9csatok **/ 93aafd955fa8f5c31c511763c0f826b6d7acf15b9csatok public static final String SERVICE_META_DATA = "android.view.textservice.scs"; 940dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final String SUPPORT_SENTENCE_SPELL_CHECK = "SupportSentenceSpellCheck"; 95aafd955fa8f5c31c511763c0f826b6d7acf15b9csatok 96988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 97988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1; 980dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2; 99988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 100988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final InternalListener mInternalListener; 101988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ITextServicesManager mTextServicesManager; 1021bedd99761e3d2acdac947d641e7fee5db556141satok private final SpellCheckerInfo mSpellCheckerInfo; 103988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl; 1040dc1f648a09b46c45190ba1ce7daecf7fada4347satok private final SpellCheckerSubtype mSubtype; 105988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 106988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mIsUsed; 107988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private SpellCheckerSessionListener mSpellCheckerSessionListener; 108988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 109988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** Handler that will execute the main tasks */ 110988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Handler mHandler = new Handler() { 111988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 112988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void handleMessage(Message msg) { 113988323c57bd25a58f05dfa492d9b9c8ab62c5153satok switch (msg.what) { 114988323c57bd25a58f05dfa492d9b9c8ab62c5153satok case MSG_ON_GET_SUGGESTION_MULTIPLE: 115988323c57bd25a58f05dfa492d9b9c8ab62c5153satok handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj); 116988323c57bd25a58f05dfa492d9b9c8ab62c5153satok break; 1170dc1f648a09b46c45190ba1ce7daecf7fada4347satok case MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE: 1180dc1f648a09b46c45190ba1ce7daecf7fada4347satok handleOnGetSuggestionsMultipleForSentence((SuggestionsInfo[]) msg.obj); 1190dc1f648a09b46c45190ba1ce7daecf7fada4347satok break; 120988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 121988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 122988323c57bd25a58f05dfa492d9b9c8ab62c5153satok }; 123988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 124988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 125988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Constructor 126988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @hide 127988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 1281bedd99761e3d2acdac947d641e7fee5db556141satok public SpellCheckerSession( 1290dc1f648a09b46c45190ba1ce7daecf7fada4347satok SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener, 1300dc1f648a09b46c45190ba1ce7daecf7fada4347satok SpellCheckerSubtype subtype) { 1311bedd99761e3d2acdac947d641e7fee5db556141satok if (info == null || listener == null || tsm == null) { 132988323c57bd25a58f05dfa492d9b9c8ab62c5153satok throw new NullPointerException(); 133988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 1341bedd99761e3d2acdac947d641e7fee5db556141satok mSpellCheckerInfo = info; 135988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler); 136a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard mInternalListener = new InternalListener(mSpellCheckerSessionListenerImpl); 137988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTextServicesManager = tsm; 138988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mIsUsed = true; 139988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListener = listener; 1400dc1f648a09b46c45190ba1ce7daecf7fada4347satok mSubtype = subtype; 141988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 142988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 143988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 144988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @return true if the connection to a text service of this session is disconnected and not 145988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * alive. 146988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 147988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean isSessionDisconnected() { 148988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerSessionListenerImpl.isDisconnected(); 149988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 150988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 151988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 1521bedd99761e3d2acdac947d641e7fee5db556141satok * Get the spell checker service info this spell checker session has. 1531bedd99761e3d2acdac947d641e7fee5db556141satok * @return SpellCheckerInfo for the specified locale. 1541bedd99761e3d2acdac947d641e7fee5db556141satok */ 1551bedd99761e3d2acdac947d641e7fee5db556141satok public SpellCheckerInfo getSpellChecker() { 1561bedd99761e3d2acdac947d641e7fee5db556141satok return mSpellCheckerInfo; 1571bedd99761e3d2acdac947d641e7fee5db556141satok } 1581bedd99761e3d2acdac947d641e7fee5db556141satok 1591bedd99761e3d2acdac947d641e7fee5db556141satok /** 160b4aff97c85e730857893742f73a082f6b8d139casatok * Cancel pending and running spell check tasks 161b4aff97c85e730857893742f73a082f6b8d139casatok */ 162b4aff97c85e730857893742f73a082f6b8d139casatok public void cancel() { 163b4aff97c85e730857893742f73a082f6b8d139casatok mSpellCheckerSessionListenerImpl.cancel(); 164b4aff97c85e730857893742f73a082f6b8d139casatok } 165b4aff97c85e730857893742f73a082f6b8d139casatok 166b4aff97c85e730857893742f73a082f6b8d139casatok /** 167988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Finish this session and allow TextServicesManagerService to disconnect the bound spell 168988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * checker. 169988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 170988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void close() { 171988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mIsUsed = false; 172988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 17374061ff90453c79ddbde468f630a41425da07710satok mSpellCheckerSessionListenerImpl.close(); 174988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl); 175988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch (RemoteException e) { 176988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do nothing 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 178988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 179988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 180988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 1810dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @hide 1820dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 1830dc1f648a09b46c45190ba1ce7daecf7fada4347satok public void getSuggestionsForSentence(TextInfo textInfo, int suggestionsLimit) { 1840dc1f648a09b46c45190ba1ce7daecf7fada4347satok mSpellCheckerSessionListenerImpl.getSuggestionsMultipleForSentence( 1850dc1f648a09b46c45190ba1ce7daecf7fada4347satok new TextInfo[] {textInfo}, suggestionsLimit); 1860dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1870dc1f648a09b46c45190ba1ce7daecf7fada4347satok 1880dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 189988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Get candidate strings for a substring of the specified text. 190988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param textInfo text metadata for a spell checker 191988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param suggestionsLimit the number of limit of suggestions returned 192988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 193988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void getSuggestions(TextInfo textInfo, int suggestionsLimit) { 194988323c57bd25a58f05dfa492d9b9c8ab62c5153satok getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false); 195988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 196988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 197988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 198988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * A batch process of getSuggestions 199988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param textInfos an array of text metadata for a spell checker 200988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param suggestionsLimit the number of limit of suggestions returned 201988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param sequentialWords true if textInfos can be treated as sequential words. 202988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 203988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void getSuggestions( 204988323c57bd25a58f05dfa492d9b9c8ab62c5153satok TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { 2056be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 2066be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId()); 2076be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 208988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // TODO: Handle multiple words suggestions by using WordBreakIterator 209988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListenerImpl.getSuggestionsMultiple( 210988323c57bd25a58f05dfa492d9b9c8ab62c5153satok textInfos, suggestionsLimit, sequentialWords); 211988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 212988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 213988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) { 214988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos); 215988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 216988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 2170dc1f648a09b46c45190ba1ce7daecf7fada4347satok private void handleOnGetSuggestionsMultipleForSentence(SuggestionsInfo[] suggestionInfos) { 2180dc1f648a09b46c45190ba1ce7daecf7fada4347satok mSpellCheckerSessionListener.onGetSuggestionsForSentence(suggestionInfos); 2190dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 2200dc1f648a09b46c45190ba1ce7daecf7fada4347satok 221988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub { 222988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final int TASK_CANCEL = 1; 223988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2; 22474061ff90453c79ddbde468f630a41425da07710satok private static final int TASK_CLOSE = 3; 2250dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final int TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE = 4; 226988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Queue<SpellCheckerParams> mPendingTasks = 227988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new LinkedList<SpellCheckerParams>(); 228060677f4686a93d92117d7d472e754423a368bdbsatok private Handler mHandler; 229988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 230988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mOpened; 231988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private ISpellCheckerSession mISpellCheckerSession; 23233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn private HandlerThread mThread; 23333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn private Handler mAsyncHandler; 234988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 235988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerSessionListenerImpl(Handler handler) { 236988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mOpened = false; 237988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mHandler = handler; 238988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 239988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 240988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static class SpellCheckerParams { 241988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final int mWhat; 242988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final TextInfo[] mTextInfos; 243988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final int mSuggestionsLimit; 244988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final boolean mSequentialWords; 24533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn public ISpellCheckerSession mSession; 246988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit, 247988323c57bd25a58f05dfa492d9b9c8ab62c5153satok boolean sequentialWords) { 248988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mWhat = what; 249988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTextInfos = textInfos; 250988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSuggestionsLimit = suggestionsLimit; 251988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSequentialWords = sequentialWords; 252988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 253988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 254988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 25533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn private void processTask(ISpellCheckerSession session, SpellCheckerParams scp, 25633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn boolean async) { 25733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (async || mAsyncHandler == null) { 25833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn switch (scp.mWhat) { 25933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn case TASK_CANCEL: 26033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (DBG) { 26133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.w(TAG, "Cancel spell checker tasks."); 26233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 26333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn try { 26433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn session.onCancel(); 26533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } catch (RemoteException e) { 26633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.e(TAG, "Failed to cancel " + e); 26733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 26833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn break; 26933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn case TASK_GET_SUGGESTIONS_MULTIPLE: 27033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (DBG) { 27133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.w(TAG, "Get suggestions from the spell checker."); 27233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 27333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn try { 27433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn session.onGetSuggestionsMultiple(scp.mTextInfos, 27533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn scp.mSuggestionsLimit, scp.mSequentialWords); 27633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } catch (RemoteException e) { 27733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.e(TAG, "Failed to get suggestions " + e); 27833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 27933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn break; 280b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE: 281b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn if (DBG) { 282b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn Log.w(TAG, "Get suggestions from the spell checker."); 283b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn } 284b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn if (scp.mTextInfos.length != 1) { 285b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn throw new IllegalArgumentException(); 286b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn } 287b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn try { 288b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn session.onGetSuggestionsMultipleForSentence( 289b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn scp.mTextInfos, scp.mSuggestionsLimit); 290b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn } catch (RemoteException e) { 291b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn Log.e(TAG, "Failed to get suggestions " + e); 292b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn } 293b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn break; 29433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn case TASK_CLOSE: 29533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (DBG) { 29633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.w(TAG, "Close spell checker tasks."); 29733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 29833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn try { 29933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn session.onClose(); 30033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } catch (RemoteException e) { 30133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.e(TAG, "Failed to close " + e); 30233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 30333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn break; 30433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 30533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } else { 30633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // The interface is to a local object, so need to execute it 30733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // asynchronously. 30833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn scp.mSession = session; 30933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mAsyncHandler.sendMessage(Message.obtain(mAsyncHandler, 1, scp)); 31033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 31133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn 31233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (scp.mWhat == TASK_CLOSE) { 31333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // If we are closing, we want to clean up our state now even 31433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // if it is pending as an async operation. 31533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn synchronized (this) { 31633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mISpellCheckerSession = null; 31733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mHandler = null; 31833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (mThread != null) { 31933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mThread.quit(); 32033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 32133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mThread = null; 32233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mAsyncHandler = null; 32333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 324988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 325988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 326988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 327988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public synchronized void onServiceConnected(ISpellCheckerSession session) { 32833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn synchronized (this) { 32933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mISpellCheckerSession = session; 33033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (session.asBinder() instanceof Binder && mThread == null) { 33133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // If this is a local object, we need to do our own threading 33233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // to make sure we handle it asynchronously. 33333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mThread = new HandlerThread("SpellCheckerSession", 33433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Process.THREAD_PRIORITY_BACKGROUND); 33533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mThread.start(); 33633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mAsyncHandler = new Handler(mThread.getLooper()) { 33733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn @Override public void handleMessage(Message msg) { 33833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn SpellCheckerParams scp = (SpellCheckerParams)msg.obj; 33933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn processTask(scp.mSession, scp, true); 34033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 34133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn }; 34233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 34333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mOpened = true; 34433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 345988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (DBG) 346988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Log.d(TAG, "onServiceConnected - Success"); 347988323c57bd25a58f05dfa492d9b9c8ab62c5153satok while (!mPendingTasks.isEmpty()) { 34833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn processTask(session, mPendingTasks.poll(), false); 349988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 350988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 351988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 352b4aff97c85e730857893742f73a082f6b8d139casatok public void cancel() { 353b4aff97c85e730857893742f73a082f6b8d139casatok if (DBG) { 354b4aff97c85e730857893742f73a082f6b8d139casatok Log.w(TAG, "cancel"); 355b4aff97c85e730857893742f73a082f6b8d139casatok } 356b4aff97c85e730857893742f73a082f6b8d139casatok processOrEnqueueTask(new SpellCheckerParams(TASK_CANCEL, null, 0, false)); 357b4aff97c85e730857893742f73a082f6b8d139casatok } 358b4aff97c85e730857893742f73a082f6b8d139casatok 359988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void getSuggestionsMultiple( 360988323c57bd25a58f05dfa492d9b9c8ab62c5153satok TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { 3616be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 3626be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Log.w(TAG, "getSuggestionsMultiple"); 3636be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 364988323c57bd25a58f05dfa492d9b9c8ab62c5153satok processOrEnqueueTask( 365988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos, 366988323c57bd25a58f05dfa492d9b9c8ab62c5153satok suggestionsLimit, sequentialWords)); 367988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 368988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 3690dc1f648a09b46c45190ba1ce7daecf7fada4347satok public void getSuggestionsMultipleForSentence(TextInfo[] textInfos, int suggestionsLimit) { 3700dc1f648a09b46c45190ba1ce7daecf7fada4347satok if (DBG) { 3710dc1f648a09b46c45190ba1ce7daecf7fada4347satok Log.w(TAG, "getSuggestionsMultipleForSentence"); 3720dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 3730dc1f648a09b46c45190ba1ce7daecf7fada4347satok processOrEnqueueTask( 3740dc1f648a09b46c45190ba1ce7daecf7fada4347satok new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE, 3750dc1f648a09b46c45190ba1ce7daecf7fada4347satok textInfos, suggestionsLimit, false)); 3760dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 3770dc1f648a09b46c45190ba1ce7daecf7fada4347satok 37874061ff90453c79ddbde468f630a41425da07710satok public void close() { 37974061ff90453c79ddbde468f630a41425da07710satok if (DBG) { 38074061ff90453c79ddbde468f630a41425da07710satok Log.w(TAG, "close"); 38174061ff90453c79ddbde468f630a41425da07710satok } 38274061ff90453c79ddbde468f630a41425da07710satok processOrEnqueueTask(new SpellCheckerParams(TASK_CLOSE, null, 0, false)); 38374061ff90453c79ddbde468f630a41425da07710satok } 38474061ff90453c79ddbde468f630a41425da07710satok 385988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean isDisconnected() { 386988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mOpened && mISpellCheckerSession == null; 387988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 388988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 389988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void processOrEnqueueTask(SpellCheckerParams scp) { 3906be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 3916be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession); 3926be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 39333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn ISpellCheckerSession session; 39433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn synchronized (this) { 39533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn session = mISpellCheckerSession; 39633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (session == null) { 39733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn SpellCheckerParams closeTask = null; 39833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (scp.mWhat == TASK_CANCEL) { 39933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn while (!mPendingTasks.isEmpty()) { 40033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn final SpellCheckerParams tmp = mPendingTasks.poll(); 40133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (tmp.mWhat == TASK_CLOSE) { 40233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // Only one close task should be processed, while we need to remove all 40333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn // close tasks from the queue 40433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn closeTask = tmp; 40533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 406b4aff97c85e730857893742f73a082f6b8d139casatok } 407b4aff97c85e730857893742f73a082f6b8d139casatok } 40833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mPendingTasks.offer(scp); 40933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (closeTask != null) { 41033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mPendingTasks.offer(closeTask); 41133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 41233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn return; 413b4aff97c85e730857893742f73a082f6b8d139casatok } 4140dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 41533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn processTask(session, scp, false); 4160dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 4170dc1f648a09b46c45190ba1ce7daecf7fada4347satok 418988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 419988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onGetSuggestions(SuggestionsInfo[] results) { 42033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn synchronized (this) { 42133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (mHandler != null) { 42233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn mHandler.sendMessage(Message.obtain(mHandler, 42333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn MSG_ON_GET_SUGGESTION_MULTIPLE, results)); 42433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 42533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 426988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4270dc1f648a09b46c45190ba1ce7daecf7fada4347satok 4280dc1f648a09b46c45190ba1ce7daecf7fada4347satok @Override 4290dc1f648a09b46c45190ba1ce7daecf7fada4347satok public void onGetSuggestionsForSentence(SuggestionsInfo[] results) { 4300dc1f648a09b46c45190ba1ce7daecf7fada4347satok mHandler.sendMessage( 4310dc1f648a09b46c45190ba1ce7daecf7fada4347satok Message.obtain(mHandler, MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE, results)); 4320dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 433988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 434988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 435988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 436988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Callback for getting results from text services 437988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 438988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public interface SpellCheckerSessionListener { 439988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 440988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Callback for "getSuggestions" 441988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param results an array of results of getSuggestions 442988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 443988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onGetSuggestions(SuggestionsInfo[] results); 4440dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 4450dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @hide 4460dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 4470dc1f648a09b46c45190ba1ce7daecf7fada4347satok public void onGetSuggestionsForSentence(SuggestionsInfo[] results); 448988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 449988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 450a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard private static class InternalListener extends ITextServicesSessionListener.Stub { 451a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard private final SpellCheckerSessionListenerImpl mParentSpellCheckerSessionListenerImpl; 452a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard 453a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard public InternalListener(SpellCheckerSessionListenerImpl spellCheckerSessionListenerImpl) { 454a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard mParentSpellCheckerSessionListenerImpl = spellCheckerSessionListenerImpl; 455a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard } 456a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard 457988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 458988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ISpellCheckerSession session) { 4596be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 4606be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Log.w(TAG, "SpellCheckerSession connected."); 4616be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 462a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard mParentSpellCheckerSessionListenerImpl.onServiceConnected(session); 463988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 464988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 465988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 466988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 467988323c57bd25a58f05dfa492d9b9c8ab62c5153satok protected void finalize() throws Throwable { 468988323c57bd25a58f05dfa492d9b9c8ab62c5153satok super.finalize(); 469988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mIsUsed) { 470988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Log.e(TAG, "SpellCheckerSession was not finished properly." + 471988323c57bd25a58f05dfa492d9b9c8ab62c5153satok "You should call finishShession() when you finished to use a spell checker."); 472988323c57bd25a58f05dfa492d9b9c8ab62c5153satok close(); 473988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 474988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 475988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 476988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 477988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @hide 478988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 479988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public ITextServicesSessionListener getTextServicesSessionListener() { 480988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mInternalListener; 481988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 482988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 483988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 484988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @hide 485988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 486988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public ISpellCheckerSessionListener getSpellCheckerSessionListener() { 487988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerSessionListenerImpl; 488988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 4890dc1f648a09b46c45190ba1ce7daecf7fada4347satok 4900dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 4910dc1f648a09b46c45190ba1ce7daecf7fada4347satok * @hide 4920dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 4930dc1f648a09b46c45190ba1ce7daecf7fada4347satok public boolean isSentenceSpellCheckSupported() { 4940dc1f648a09b46c45190ba1ce7daecf7fada4347satok return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK); 4950dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 496988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 497