SpellCheckerService.java revision 74061ff90453c79ddbde468f630a41425da07710
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17package android.service.textservice; 18 19import com.android.internal.textservice.ISpellCheckerService; 20import com.android.internal.textservice.ISpellCheckerSession; 21import com.android.internal.textservice.ISpellCheckerSessionListener; 22 23import android.app.Service; 24import android.content.Intent; 25import android.os.Bundle; 26import android.os.IBinder; 27import android.os.RemoteException; 28import android.util.Log; 29import android.view.textservice.SuggestionsInfo; 30import android.view.textservice.TextInfo; 31 32import java.lang.ref.WeakReference; 33 34/** 35 * SpellCheckerService provides an abstract base class for a spell checker. 36 * This class combines a service to the system with the spell checker service interface that 37 * spell checker must implement. 38 * 39 * <p>In addition to the normal Service lifecycle methods, this class 40 * introduces a new specific callback that subclasses should override 41 * {@link #createSession()} to provide a spell checker session that is corresponding 42 * to requested language and so on. The spell checker session returned by this method 43 * should extend {@link SpellCheckerService.Session}. 44 * </p> 45 * 46 * <h3>Returning spell check results</h3> 47 * 48 * <p>{@link SpellCheckerService.Session#onGetSuggestions(TextInfo, int)} 49 * should return spell check results. 50 * It receives {@link android.view.textservice.TextInfo} and returns 51 * {@link android.view.textservice.SuggestionsInfo} for the input. 52 * You may want to override 53 * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)} for 54 * better performance and quality. 55 * </p> 56 * 57 * <p>Please note that {@link SpellCheckerService.Session#getLocale()} does not return a valid 58 * locale before {@link SpellCheckerService.Session#onCreate()} </p> 59 * 60 */ 61public abstract class SpellCheckerService extends Service { 62 private static final String TAG = SpellCheckerService.class.getSimpleName(); 63 private static final boolean DBG = false; 64 public static final String SERVICE_INTERFACE = 65 "android.service.textservice.SpellCheckerService"; 66 67 private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this); 68 69 70 /** 71 * Implement to return the implementation of the internal spell checker 72 * service interface. Subclasses should not override. 73 */ 74 @Override 75 public final IBinder onBind(final Intent intent) { 76 if (DBG) { 77 Log.w(TAG, "onBind"); 78 } 79 return mBinder; 80 } 81 82 /** 83 * Factory method to create a spell checker session impl 84 * @return SpellCheckerSessionImpl which should be overridden by a concrete implementation. 85 */ 86 public abstract Session createSession(); 87 88 /** 89 * This abstract class should be overridden by a concrete implementation of a spell checker. 90 */ 91 public static abstract class Session { 92 private InternalISpellCheckerSession mInternalSession; 93 94 /** 95 * @hide 96 */ 97 public final void setInternalISpellCheckerSession(InternalISpellCheckerSession session) { 98 mInternalSession = session; 99 } 100 101 /** 102 * This is called after the class is initialized, at which point it knows it can call 103 * getLocale() etc... 104 */ 105 public abstract void onCreate(); 106 107 /** 108 * Get suggestions for specified text in TextInfo. 109 * This function will run on the incoming IPC thread. 110 * So, this is not called on the main thread, 111 * but will be called in series on another thread. 112 * @param textInfo the text metadata 113 * @param suggestionsLimit the number of limit of suggestions returned 114 * @return SuggestionsInfo which contains suggestions for textInfo 115 */ 116 public abstract SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit); 117 118 /** 119 * A batch process of onGetSuggestions. 120 * This function will run on the incoming IPC thread. 121 * So, this is not called on the main thread, 122 * but will be called in series on another thread. 123 * @param textInfos an array of the text metadata 124 * @param suggestionsLimit the number of limit of suggestions returned 125 * @param sequentialWords true if textInfos can be treated as sequential words. 126 * @return an array of SuggestionsInfo of onGetSuggestions 127 */ 128 public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos, 129 int suggestionsLimit, boolean sequentialWords) { 130 final int length = textInfos.length; 131 final SuggestionsInfo[] retval = new SuggestionsInfo[length]; 132 for (int i = 0; i < length; ++i) { 133 retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit); 134 retval[i].setCookieAndSequence( 135 textInfos[i].getCookie(), textInfos[i].getSequence()); 136 } 137 return retval; 138 } 139 140 /** 141 * Request to abort all tasks executed in SpellChecker. 142 * This function will run on the incoming IPC thread. 143 * So, this is not called on the main thread, 144 * but will be called in series on another thread. 145 */ 146 public void onCancel() {} 147 148 /** 149 * Request to close this session. 150 * This function will run on the incoming IPC thread. 151 * So, this is not called on the main thread, 152 * but will be called in series on another thread. 153 */ 154 public void onClose() {} 155 156 /** 157 * @return Locale for this session 158 */ 159 public String getLocale() { 160 return mInternalSession.getLocale(); 161 } 162 163 /** 164 * @return Bundle for this session 165 */ 166 public Bundle getBundle() { 167 return mInternalSession.getBundle(); 168 } 169 } 170 171 // Preventing from exposing ISpellCheckerSession.aidl, create an internal class. 172 private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub { 173 private ISpellCheckerSessionListener mListener; 174 private final Session mSession; 175 private final String mLocale; 176 private final Bundle mBundle; 177 178 public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener, 179 Bundle bundle, Session session) { 180 mListener = listener; 181 mSession = session; 182 mLocale = locale; 183 mBundle = bundle; 184 session.setInternalISpellCheckerSession(this); 185 } 186 187 @Override 188 public void onGetSuggestionsMultiple( 189 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { 190 try { 191 mListener.onGetSuggestions( 192 mSession.onGetSuggestionsMultiple( 193 textInfos, suggestionsLimit, sequentialWords)); 194 } catch (RemoteException e) { 195 } 196 } 197 198 @Override 199 public void onCancel() { 200 mSession.onCancel(); 201 } 202 203 @Override 204 public void onClose() { 205 mSession.onClose(); 206 mListener = null; 207 } 208 209 public String getLocale() { 210 return mLocale; 211 } 212 213 public Bundle getBundle() { 214 return mBundle; 215 } 216 } 217 218 private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub { 219 private final WeakReference<SpellCheckerService> mInternalServiceRef; 220 221 public SpellCheckerServiceBinder(SpellCheckerService service) { 222 mInternalServiceRef = new WeakReference<SpellCheckerService>(service); 223 } 224 225 @Override 226 public ISpellCheckerSession getISpellCheckerSession( 227 String locale, ISpellCheckerSessionListener listener, Bundle bundle) { 228 final SpellCheckerService service = mInternalServiceRef.get(); 229 if (service == null) return null; 230 final Session session = service.createSession(); 231 final InternalISpellCheckerSession internalSession = 232 new InternalISpellCheckerSession(locale, listener, bundle, session); 233 session.onCreate(); 234 return internalSession; 235 } 236 } 237} 238