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"; 94988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 95988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1; 960dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2; 97988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 98988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final InternalListener mInternalListener; 99988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final ITextServicesManager mTextServicesManager; 1001bedd99761e3d2acdac947d641e7fee5db556141satok private final SpellCheckerInfo mSpellCheckerInfo; 101988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl; 1020dc1f648a09b46c45190ba1ce7daecf7fada4347satok private final SpellCheckerSubtype mSubtype; 103988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 104988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mIsUsed; 105988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private SpellCheckerSessionListener mSpellCheckerSessionListener; 106988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 107988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** Handler that will execute the main tasks */ 108988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Handler mHandler = new Handler() { 109988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 110988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void handleMessage(Message msg) { 111988323c57bd25a58f05dfa492d9b9c8ab62c5153satok switch (msg.what) { 112988323c57bd25a58f05dfa492d9b9c8ab62c5153satok case MSG_ON_GET_SUGGESTION_MULTIPLE: 113988323c57bd25a58f05dfa492d9b9c8ab62c5153satok handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj); 114988323c57bd25a58f05dfa492d9b9c8ab62c5153satok break; 1150dc1f648a09b46c45190ba1ce7daecf7fada4347satok case MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE: 116d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok handleOnGetSentenceSuggestionsMultiple((SentenceSuggestionsInfo[]) msg.obj); 1170dc1f648a09b46c45190ba1ce7daecf7fada4347satok break; 118988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 119988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 120988323c57bd25a58f05dfa492d9b9c8ab62c5153satok }; 121988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 122988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 123988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Constructor 124988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @hide 125988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 1261bedd99761e3d2acdac947d641e7fee5db556141satok public SpellCheckerSession( 1270dc1f648a09b46c45190ba1ce7daecf7fada4347satok SpellCheckerInfo info, ITextServicesManager tsm, SpellCheckerSessionListener listener, 1280dc1f648a09b46c45190ba1ce7daecf7fada4347satok SpellCheckerSubtype subtype) { 1291bedd99761e3d2acdac947d641e7fee5db556141satok if (info == null || listener == null || tsm == null) { 130988323c57bd25a58f05dfa492d9b9c8ab62c5153satok throw new NullPointerException(); 131988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 1321bedd99761e3d2acdac947d641e7fee5db556141satok mSpellCheckerInfo = info; 133988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler); 134a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard mInternalListener = new InternalListener(mSpellCheckerSessionListenerImpl); 135988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTextServicesManager = tsm; 136988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mIsUsed = true; 137988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListener = listener; 1380dc1f648a09b46c45190ba1ce7daecf7fada4347satok mSubtype = subtype; 139988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 140988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 141988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 142988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @return true if the connection to a text service of this session is disconnected and not 143988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * alive. 144988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 145988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public boolean isSessionDisconnected() { 146988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerSessionListenerImpl.isDisconnected(); 147988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 148988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 149988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 1501bedd99761e3d2acdac947d641e7fee5db556141satok * Get the spell checker service info this spell checker session has. 1511bedd99761e3d2acdac947d641e7fee5db556141satok * @return SpellCheckerInfo for the specified locale. 1521bedd99761e3d2acdac947d641e7fee5db556141satok */ 1531bedd99761e3d2acdac947d641e7fee5db556141satok public SpellCheckerInfo getSpellChecker() { 1541bedd99761e3d2acdac947d641e7fee5db556141satok return mSpellCheckerInfo; 1551bedd99761e3d2acdac947d641e7fee5db556141satok } 1561bedd99761e3d2acdac947d641e7fee5db556141satok 1571bedd99761e3d2acdac947d641e7fee5db556141satok /** 158b4aff97c85e730857893742f73a082f6b8d139casatok * Cancel pending and running spell check tasks 159b4aff97c85e730857893742f73a082f6b8d139casatok */ 160b4aff97c85e730857893742f73a082f6b8d139casatok public void cancel() { 161b4aff97c85e730857893742f73a082f6b8d139casatok mSpellCheckerSessionListenerImpl.cancel(); 162b4aff97c85e730857893742f73a082f6b8d139casatok } 163b4aff97c85e730857893742f73a082f6b8d139casatok 164b4aff97c85e730857893742f73a082f6b8d139casatok /** 165988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Finish this session and allow TextServicesManagerService to disconnect the bound spell 166988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * checker. 167988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 168988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void close() { 169988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mIsUsed = false; 170988323c57bd25a58f05dfa492d9b9c8ab62c5153satok try { 17174061ff90453c79ddbde468f630a41425da07710satok mSpellCheckerSessionListenerImpl.close(); 172988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl); 173988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } catch (RemoteException e) { 174988323c57bd25a58f05dfa492d9b9c8ab62c5153satok // do nothing 175988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 176988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 177988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 178988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 1796183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * Get suggestions from the specified sentences 1806183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * @param textInfos an array of text metadata for a spell checker 1816183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * @param suggestionsLimit the maximum number of suggestions that will be returned 1820dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 1836183cd64a98a69ea247813c9ba0a07326c4bc1aesatok public void getSentenceSuggestions(TextInfo[] textInfos, int suggestionsLimit) { 184d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok mSpellCheckerSessionListenerImpl.getSentenceSuggestionsMultiple( 1856183cd64a98a69ea247813c9ba0a07326c4bc1aesatok textInfos, suggestionsLimit); 1860dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 1870dc1f648a09b46c45190ba1ce7daecf7fada4347satok 1880dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 189988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * Get candidate strings for a substring of the specified text. 190988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param textInfo text metadata for a spell checker 1916183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * @param suggestionsLimit the maximum number of suggestions that will be returned 192c7ee1b9369ffd7c21a70738056a82dc4238e7fc1satok * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead 193988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 194c7ee1b9369ffd7c21a70738056a82dc4238e7fc1satok @Deprecated 195988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void getSuggestions(TextInfo textInfo, int suggestionsLimit) { 196988323c57bd25a58f05dfa492d9b9c8ab62c5153satok getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false); 197988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 198988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 199988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 200988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * A batch process of getSuggestions 201988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param textInfos an array of text metadata for a spell checker 2026183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * @param suggestionsLimit the maximum number of suggestions that will be returned 203988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @param sequentialWords true if textInfos can be treated as sequential words. 204c7ee1b9369ffd7c21a70738056a82dc4238e7fc1satok * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead 205988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 206c7ee1b9369ffd7c21a70738056a82dc4238e7fc1satok @Deprecated 207988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void getSuggestions( 208988323c57bd25a58f05dfa492d9b9c8ab62c5153satok TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { 2096be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 2106be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId()); 2116be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 212988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListenerImpl.getSuggestionsMultiple( 213988323c57bd25a58f05dfa492d9b9c8ab62c5153satok textInfos, suggestionsLimit, sequentialWords); 214988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 215988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 216988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private void handleOnGetSuggestionsMultiple(SuggestionsInfo[] suggestionInfos) { 217988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos); 218988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 219988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 220d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok private void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionInfos) { 221d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionInfos); 2220dc1f648a09b46c45190ba1ce7daecf7fada4347satok } 2230dc1f648a09b46c45190ba1ce7daecf7fada4347satok 224988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub { 225988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final int TASK_CANCEL = 1; 226988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2; 22774061ff90453c79ddbde468f630a41425da07710satok private static final int TASK_CLOSE = 3; 2280dc1f648a09b46c45190ba1ce7daecf7fada4347satok private static final int TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE = 4; 229988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private final Queue<SpellCheckerParams> mPendingTasks = 230988323c57bd25a58f05dfa492d9b9c8ab62c5153satok new LinkedList<SpellCheckerParams>(); 231060677f4686a93d92117d7d472e754423a368bdbsatok private Handler mHandler; 232988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 233988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private boolean mOpened; 234988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private ISpellCheckerSession mISpellCheckerSession; 23533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn private HandlerThread mThread; 23633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn private Handler mAsyncHandler; 237988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 238988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerSessionListenerImpl(Handler handler) { 239988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mOpened = false; 240988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mHandler = handler; 241988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 242988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 243988323c57bd25a58f05dfa492d9b9c8ab62c5153satok private static class SpellCheckerParams { 244988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final int mWhat; 245988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final TextInfo[] mTextInfos; 246988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final int mSuggestionsLimit; 247988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public final boolean mSequentialWords; 24833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn public ISpellCheckerSession mSession; 249988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public SpellCheckerParams(int what, TextInfo[] textInfos, int suggestionsLimit, 250988323c57bd25a58f05dfa492d9b9c8ab62c5153satok boolean sequentialWords) { 251988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mWhat = what; 252988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mTextInfos = textInfos; 253988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSuggestionsLimit = suggestionsLimit; 254988323c57bd25a58f05dfa492d9b9c8ab62c5153satok mSequentialWords = sequentialWords; 255988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 256988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 257988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 25833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn private void processTask(ISpellCheckerSession session, SpellCheckerParams scp, 25933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn boolean async) { 26033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (async || mAsyncHandler == null) { 26133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn switch (scp.mWhat) { 26233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn case TASK_CANCEL: 26333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (DBG) { 26433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.w(TAG, "Cancel spell checker tasks."); 26533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 26633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn try { 26733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn session.onCancel(); 26833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } catch (RemoteException e) { 26933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.e(TAG, "Failed to cancel " + e); 27033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 27133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn break; 27233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn case TASK_GET_SUGGESTIONS_MULTIPLE: 27333b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn if (DBG) { 27433b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.w(TAG, "Get suggestions from the spell checker."); 27533b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 27633b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn try { 27733b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn session.onGetSuggestionsMultiple(scp.mTextInfos, 27833b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn scp.mSuggestionsLimit, scp.mSequentialWords); 27933b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } catch (RemoteException e) { 28033b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn Log.e(TAG, "Failed to get suggestions " + e); 28133b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn } 28233b8ee509f36a0168c8ce5a9091b57ab936f4c13Dianne Hackborn break; 283b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE: 284b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn if (DBG) { 285c7ee1b9369ffd7c21a70738056a82dc4238e7fc1satok Log.w(TAG, "Get sentence suggestions from the spell checker."); 286b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn } 287b5052de75736527549d7e537632777c6fec2e4f0Dianne Hackborn try { 288d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok session.onGetSentenceSuggestionsMultiple( 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 369d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok public void getSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) { 3700dc1f648a09b46c45190ba1ce7daecf7fada4347satok if (DBG) { 371d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok Log.w(TAG, "getSentenceSuggestionsMultiple"); 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) { 402d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok // Only one close task should be processed, while we need to remove 403d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok // all 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 429d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] 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 /** 440f6710615c6cc1746d1ecc7aebc9afed457dcca41satok * Callback for {@link SpellCheckerSession#getSuggestions(TextInfo, int)} 441f6710615c6cc1746d1ecc7aebc9afed457dcca41satok * and {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)} 4426183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * @param results an array of {@link SuggestionsInfo}s. 4436183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * These results are suggestions for {@link TextInfo}s queried by 444f6710615c6cc1746d1ecc7aebc9afed457dcca41satok * {@link SpellCheckerSession#getSuggestions(TextInfo, int)} or 445f6710615c6cc1746d1ecc7aebc9afed457dcca41satok * {@link SpellCheckerSession#getSuggestions(TextInfo[], int, boolean)} 446988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 447988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onGetSuggestions(SuggestionsInfo[] results); 4480dc1f648a09b46c45190ba1ce7daecf7fada4347satok /** 4496183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * Callback for {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} 4506183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * @param results an array of {@link SentenceSuggestionsInfo}s. 4516183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * These results are suggestions for {@link TextInfo}s 4526183cd64a98a69ea247813c9ba0a07326c4bc1aesatok * queried by {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)}. 4530dc1f648a09b46c45190ba1ce7daecf7fada4347satok */ 454d404fe110558bd2e1960b428db6a2ee8bfd040cdsatok public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results); 455988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 456988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 457a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard private static class InternalListener extends ITextServicesSessionListener.Stub { 458a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard private final SpellCheckerSessionListenerImpl mParentSpellCheckerSessionListenerImpl; 459a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard 460a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard public InternalListener(SpellCheckerSessionListenerImpl spellCheckerSessionListenerImpl) { 461a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard mParentSpellCheckerSessionListenerImpl = spellCheckerSessionListenerImpl; 462a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard } 463a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard 464988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 465988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public void onServiceConnected(ISpellCheckerSession session) { 4666be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok if (DBG) { 4676be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok Log.w(TAG, "SpellCheckerSession connected."); 4686be6d7548fb7c29a4d46dc985318ab2adf69f95fsatok } 469a80838d9d63fcc9a83a9e7c99884e5b50316d4f0Jean Chalard mParentSpellCheckerSessionListenerImpl.onServiceConnected(session); 470988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 471988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 472988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 473988323c57bd25a58f05dfa492d9b9c8ab62c5153satok @Override 474988323c57bd25a58f05dfa492d9b9c8ab62c5153satok protected void finalize() throws Throwable { 475988323c57bd25a58f05dfa492d9b9c8ab62c5153satok super.finalize(); 476988323c57bd25a58f05dfa492d9b9c8ab62c5153satok if (mIsUsed) { 477988323c57bd25a58f05dfa492d9b9c8ab62c5153satok Log.e(TAG, "SpellCheckerSession was not finished properly." + 478988323c57bd25a58f05dfa492d9b9c8ab62c5153satok "You should call finishShession() when you finished to use a spell checker."); 479988323c57bd25a58f05dfa492d9b9c8ab62c5153satok close(); 480988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 481988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 482988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 483988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 484988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @hide 485988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 486988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public ITextServicesSessionListener getTextServicesSessionListener() { 487988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mInternalListener; 488988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 489988323c57bd25a58f05dfa492d9b9c8ab62c5153satok 490988323c57bd25a58f05dfa492d9b9c8ab62c5153satok /** 491988323c57bd25a58f05dfa492d9b9c8ab62c5153satok * @hide 492988323c57bd25a58f05dfa492d9b9c8ab62c5153satok */ 493988323c57bd25a58f05dfa492d9b9c8ab62c5153satok public ISpellCheckerSessionListener getSpellCheckerSessionListener() { 494988323c57bd25a58f05dfa492d9b9c8ab62c5153satok return mSpellCheckerSessionListenerImpl; 495988323c57bd25a58f05dfa492d9b9c8ab62c5153satok } 496988323c57bd25a58f05dfa492d9b9c8ab62c5153satok} 497