1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.samplespellcheckerservice;
18
19import android.os.Build;
20import android.service.textservice.SpellCheckerService;
21import android.util.Log;
22import android.view.textservice.SentenceSuggestionsInfo;
23import android.view.textservice.SuggestionsInfo;
24import android.view.textservice.TextInfo;
25
26import java.util.ArrayList;
27
28public class SampleSpellCheckerService extends SpellCheckerService {
29    private static final String TAG = SampleSpellCheckerService.class.getSimpleName();
30    private static final boolean DBG = true;
31
32    @Override
33    public Session createSession() {
34        return new AndroidSpellCheckerSession();
35    }
36
37    private static class AndroidSpellCheckerSession extends Session {
38
39        private boolean isSentenceSpellCheckApiSupported() {
40            // Note that the sentence level spell check APIs work on Jelly Bean or later.
41            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
42        }
43
44        private String mLocale;
45        @Override
46        public void onCreate() {
47            mLocale = getLocale();
48        }
49
50        /**
51         * This method should have a concrete implementation in all spell checker services.
52         * Please note that the default implementation of
53         * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}
54         * calls up this method. You may want to override
55         * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}
56         * by your own implementation if you'd like to provide an optimized implementation for
57         * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}.
58         */
59        @Override
60        public SuggestionsInfo onGetSuggestions(TextInfo textInfo, int suggestionsLimit) {
61            if (DBG) {
62                Log.d(TAG, "onGetSuggestions: " + textInfo.getText());
63            }
64            final String input = textInfo.getText();
65            final int length = input.length();
66            // Just a fake logic:
67            // length <= 3 for short words that we assume are in the fake dictionary
68            // length > 20 for too long words that we assume can't be recognized (such as CJK words)
69            final int flags = length <= 3 ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
70                    : length <= 20 ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0;
71            return new SuggestionsInfo(flags,
72                    new String[] {"aaa", "bbb", "Candidate for " + input, mLocale});
73        }
74
75        /**
76         * Please consider providing your own implementation of sentence level spell checking.
77         * Please note that this sample implementation is just a mock to demonstrate how a sentence
78         * level spell checker returns the result.
79         * If you don't override this method, the framework converts queries of
80         * {@link SpellCheckerService.Session#onGetSentenceSuggestionsMultiple(TextInfo[], int)}
81         * to queries of
82         * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}
83         * by the default implementation.
84         */
85        @Override
86        public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(
87                TextInfo[] textInfos, int suggestionsLimit) {
88            if (!isSentenceSpellCheckApiSupported()) {
89                Log.e(TAG, "Sentence spell check is not supported on this platform, "
90                        + "but accidentially called.");
91                return null;
92            }
93            final ArrayList<SentenceSuggestionsInfo> retval =
94                    new ArrayList<SentenceSuggestionsInfo>();
95            for (int i = 0; i < textInfos.length; ++i) {
96                final TextInfo ti = textInfos[i];
97                if (DBG) {
98                    Log.d(TAG, "onGetSentenceSuggestionsMultiple: " + ti.getText());
99                }
100                final String input = ti.getText();
101                final int length = input.length();
102                final SuggestionsInfo[] sis;
103                final int[] lengths;
104                final int[] offsets;
105                if (input.equalsIgnoreCase("I wold like to here form you")) {
106                    // Return sentence level suggestion for this fixed input
107                    final int flags0 = SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO;
108                    final int flags1 = SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS
109                            | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO;
110                    final int flags2 = flags1;
111                    final SuggestionsInfo si0 = new SuggestionsInfo(
112                            flags0, new String[] { "would" });
113                    final SuggestionsInfo si1 = new SuggestionsInfo(
114                            flags1, new String[] { "hear" });
115                    final SuggestionsInfo si2 = new SuggestionsInfo(
116                            flags2, new String[] { "from" });
117                    sis = new SuggestionsInfo[] {si0, si1, si2};
118                    offsets = new int[] { 2, 15, 20 };
119                    lengths = new int[] { 4, 4, 4 };
120                } else {
121                    // Just a mock logic:
122                    // length <= 3 for short words that we assume are in the fake dictionary
123                    // length > 20 for too long words that we assume can't be recognized
124                    // (such as CJK words)
125                    final int flags = length <= 3 ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY
126                            : length <= 20 ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0;
127                    final SuggestionsInfo si = new SuggestionsInfo(flags,
128                            new String[] {"aaa", "bbb", "Candidate for " + input, mLocale});
129                    sis = new SuggestionsInfo[] { si };
130                    offsets = new int[] { 0 };
131                    lengths = new int[] { ti.getText().length() };
132                }
133                final SentenceSuggestionsInfo ssi =
134                        new SentenceSuggestionsInfo(sis, lengths, offsets);
135                retval.add(ssi);
136            }
137            return retval.toArray(new SentenceSuggestionsInfo[0]);
138        }
139    }
140}
141