SpellCheckerService.java revision 44b75030931d9c65c9e495a86d11d71da59b4429
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 * @return Locale for this session 150 */ 151 public String getLocale() { 152 return mInternalSession.getLocale(); 153 } 154 155 /** 156 * @return Bundle for this session 157 */ 158 public Bundle getBundle() { 159 return mInternalSession.getBundle(); 160 } 161 } 162 163 // Preventing from exposing ISpellCheckerSession.aidl, create an internal class. 164 private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub { 165 private final ISpellCheckerSessionListener mListener; 166 private final Session mSession; 167 private final String mLocale; 168 private final Bundle mBundle; 169 170 public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener, 171 Bundle bundle, Session session) { 172 mListener = listener; 173 mSession = session; 174 mLocale = locale; 175 mBundle = bundle; 176 session.setInternalISpellCheckerSession(this); 177 } 178 179 @Override 180 public void onGetSuggestionsMultiple( 181 TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) { 182 try { 183 mListener.onGetSuggestions( 184 mSession.onGetSuggestionsMultiple( 185 textInfos, suggestionsLimit, sequentialWords)); 186 } catch (RemoteException e) { 187 } 188 } 189 190 @Override 191 public void onCancel() { 192 mSession.onCancel(); 193 } 194 195 public String getLocale() { 196 return mLocale; 197 } 198 199 public Bundle getBundle() { 200 return mBundle; 201 } 202 } 203 204 private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub { 205 private final WeakReference<SpellCheckerService> mInternalServiceRef; 206 207 public SpellCheckerServiceBinder(SpellCheckerService service) { 208 mInternalServiceRef = new WeakReference<SpellCheckerService>(service); 209 } 210 211 @Override 212 public ISpellCheckerSession getISpellCheckerSession( 213 String locale, ISpellCheckerSessionListener listener, Bundle bundle) { 214 final SpellCheckerService service = mInternalServiceRef.get(); 215 if (service == null) return null; 216 final Session session = service.createSession(); 217 final InternalISpellCheckerSession internalSession = 218 new InternalISpellCheckerSession(locale, listener, bundle, session); 219 session.onCreate(); 220 return internalSession; 221 } 222 } 223} 224