SpellCheckerService.java revision 5357806980269d846a15c845a6fcc0384fb18860
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 */
39public abstract class SpellCheckerService extends Service {
40    private static final String TAG = SpellCheckerService.class.getSimpleName();
41    private static final boolean DBG = false;
42    public static final String SERVICE_INTERFACE =
43            "android.service.textservice.SpellCheckerService";
44
45    private final SpellCheckerServiceBinder mBinder = new SpellCheckerServiceBinder(this);
46
47
48    /**
49     * Implement to return the implementation of the internal spell checker
50     * service interface. Subclasses should not override.
51     */
52    @Override
53    public final IBinder onBind(final Intent intent) {
54        if (DBG) {
55            Log.w(TAG, "onBind");
56        }
57        return mBinder;
58    }
59
60    /**
61     * Factory method to create a spell checker session impl
62     * @return SpellCheckerSessionImpl which should be overridden by a concrete implementation.
63     */
64    public abstract Session createSession();
65
66    /**
67     * This abstract class should be overridden by a concrete implementation of a spell checker.
68     */
69    public abstract class Session {
70        private InternalISpellCheckerSession mInternalSession;
71
72        /**
73         * @hide
74         */
75        public final void setInternalISpellCheckerSession(InternalISpellCheckerSession session) {
76            mInternalSession = session;
77        }
78
79        /**
80         * This is called after the class is initialized, at which point it knows it can call
81         * getLocale() etc...
82         */
83        public abstract void onCreate();
84
85        /**
86         * Get suggestions for specified text in TextInfo.
87         * This function will run on the incoming IPC thread.
88         * So, this is not called on the main thread,
89         * but will be called in series on another thread.
90         * @param textInfo the text metadata
91         * @param suggestionsLimit the number of limit of suggestions returned
92         * @return SuggestionInfo which contains suggestions for textInfo
93         */
94        public abstract SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit);
95
96        /**
97         * A batch process of onGetSuggestions.
98         * This function will run on the incoming IPC thread.
99         * So, this is not called on the main thread,
100         * but will be called in series on another thread.
101         * @param textInfos an array of the text metadata
102         * @param suggestionsLimit the number of limit of suggestions returned
103         * @param sequentialWords true if textInfos can be treated as sequential words.
104         * @return an array of SuggestionInfo of onGetSuggestions
105         */
106        public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos,
107                int suggestionsLimit, boolean sequentialWords) {
108            final int length = textInfos.length;
109            final SuggestionsInfo[] retval = new SuggestionsInfo[length];
110            for (int i = 0; i < length; ++i) {
111                retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit);
112                retval[i].setCookieAndSequence(
113                        textInfos[i].getCookie(), textInfos[i].getSequence());
114            }
115            return retval;
116        }
117
118        /**
119         * Request to abort all tasks executed in SpellChecker.
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         */
124        public void onCancel() {}
125
126        /**
127         * @return Locale for this session
128         */
129        public String getLocale() {
130            return mInternalSession.getLocale();
131        }
132
133        /**
134         * @return Bundle for this session
135         */
136        public Bundle getBundle() {
137            return mInternalSession.getBundle();
138        }
139    }
140
141    // Preventing from exposing ISpellCheckerSession.aidl, create an internal class.
142    private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub {
143        private final ISpellCheckerSessionListener mListener;
144        private final Session mSession;
145        private final String mLocale;
146        private final Bundle mBundle;
147
148        public InternalISpellCheckerSession(String locale, ISpellCheckerSessionListener listener,
149                Bundle bundle, Session session) {
150            mListener = listener;
151            mSession = session;
152            mLocale = locale;
153            mBundle = bundle;
154            session.setInternalISpellCheckerSession(this);
155        }
156
157        @Override
158        public void onGetSuggestionsMultiple(
159                TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
160            try {
161                mListener.onGetSuggestions(
162                        mSession.onGetSuggestionsMultiple(
163                                textInfos, suggestionsLimit, sequentialWords));
164            } catch (RemoteException e) {
165            }
166        }
167
168        @Override
169        public void onCancel() {
170            mSession.onCancel();
171        }
172
173        public String getLocale() {
174            return mLocale;
175        }
176
177        public Bundle getBundle() {
178            return mBundle;
179        }
180    }
181
182    private static class SpellCheckerServiceBinder extends ISpellCheckerService.Stub {
183        private final WeakReference<SpellCheckerService> mInternalServiceRef;
184
185        public SpellCheckerServiceBinder(SpellCheckerService service) {
186            mInternalServiceRef = new WeakReference<SpellCheckerService>(service);
187        }
188
189        @Override
190        public ISpellCheckerSession getISpellCheckerSession(
191                String locale, ISpellCheckerSessionListener listener, Bundle bundle) {
192            final SpellCheckerService service = mInternalServiceRef.get();
193            if (service == null) return null;
194            final Session session = service.createSession();
195            final InternalISpellCheckerSession internalSession =
196                    new InternalISpellCheckerSession(locale, listener, bundle, session);
197            session.onCreate();
198            return internalSession;
199        }
200    }
201}
202