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 
17 package com.android.inputmethod.latin;
18 
19 import android.util.Log;
20 
21 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
22 import com.android.inputmethod.latin.common.ComposedData;
23 import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
24 
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.Locale;
29 import java.util.concurrent.CopyOnWriteArrayList;
30 
31 /**
32  * Class for a collection of dictionaries that behave like one dictionary.
33  */
34 public final class DictionaryCollection extends Dictionary {
35     private final String TAG = DictionaryCollection.class.getSimpleName();
36     protected final CopyOnWriteArrayList<Dictionary> mDictionaries;
37 
DictionaryCollection(final String dictType, final Locale locale)38     public DictionaryCollection(final String dictType, final Locale locale) {
39         super(dictType, locale);
40         mDictionaries = new CopyOnWriteArrayList<>();
41     }
42 
DictionaryCollection(final String dictType, final Locale locale, final Dictionary... dictionaries)43     public DictionaryCollection(final String dictType, final Locale locale,
44             final Dictionary... dictionaries) {
45         super(dictType, locale);
46         if (null == dictionaries) {
47             mDictionaries = new CopyOnWriteArrayList<>();
48         } else {
49             mDictionaries = new CopyOnWriteArrayList<>(dictionaries);
50             mDictionaries.removeAll(Collections.singleton(null));
51         }
52     }
53 
DictionaryCollection(final String dictType, final Locale locale, final Collection<Dictionary> dictionaries)54     public DictionaryCollection(final String dictType, final Locale locale,
55             final Collection<Dictionary> dictionaries) {
56         super(dictType, locale);
57         mDictionaries = new CopyOnWriteArrayList<>(dictionaries);
58         mDictionaries.removeAll(Collections.singleton(null));
59     }
60 
61     @Override
getSuggestions(final ComposedData composedData, final NgramContext ngramContext, final long proximityInfoHandle, final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId, final float weightForLocale, final float[] inOutWeightOfLangModelVsSpatialModel)62     public ArrayList<SuggestedWordInfo> getSuggestions(final ComposedData composedData,
63             final NgramContext ngramContext, final long proximityInfoHandle,
64             final SettingsValuesForSuggestion settingsValuesForSuggestion,
65             final int sessionId, final float weightForLocale,
66             final float[] inOutWeightOfLangModelVsSpatialModel) {
67         final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
68         if (dictionaries.isEmpty()) return null;
69         // To avoid creating unnecessary objects, we get the list out of the first
70         // dictionary and add the rest to it if not null, hence the get(0)
71         ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composedData,
72                 ngramContext, proximityInfoHandle, settingsValuesForSuggestion, sessionId,
73                 weightForLocale, inOutWeightOfLangModelVsSpatialModel);
74         if (null == suggestions) suggestions = new ArrayList<>();
75         final int length = dictionaries.size();
76         for (int i = 1; i < length; ++ i) {
77             final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(
78                     composedData, ngramContext, proximityInfoHandle, settingsValuesForSuggestion,
79                     sessionId, weightForLocale, inOutWeightOfLangModelVsSpatialModel);
80             if (null != sugg) suggestions.addAll(sugg);
81         }
82         return suggestions;
83     }
84 
85     @Override
isInDictionary(final String word)86     public boolean isInDictionary(final String word) {
87         for (int i = mDictionaries.size() - 1; i >= 0; --i)
88             if (mDictionaries.get(i).isInDictionary(word)) return true;
89         return false;
90     }
91 
92     @Override
getFrequency(final String word)93     public int getFrequency(final String word) {
94         int maxFreq = -1;
95         for (int i = mDictionaries.size() - 1; i >= 0; --i) {
96             final int tempFreq = mDictionaries.get(i).getFrequency(word);
97             maxFreq = Math.max(tempFreq, maxFreq);
98         }
99         return maxFreq;
100     }
101 
102     @Override
getMaxFrequencyOfExactMatches(final String word)103     public int getMaxFrequencyOfExactMatches(final String word) {
104         int maxFreq = -1;
105         for (int i = mDictionaries.size() - 1; i >= 0; --i) {
106             final int tempFreq = mDictionaries.get(i).getMaxFrequencyOfExactMatches(word);
107             maxFreq = Math.max(tempFreq, maxFreq);
108         }
109         return maxFreq;
110     }
111 
112     @Override
isInitialized()113     public boolean isInitialized() {
114         return !mDictionaries.isEmpty();
115     }
116 
117     @Override
close()118     public void close() {
119         for (final Dictionary dict : mDictionaries)
120             dict.close();
121     }
122 
123     // Warning: this is not thread-safe. Take necessary precaution when calling.
addDictionary(final Dictionary newDict)124     public void addDictionary(final Dictionary newDict) {
125         if (null == newDict) return;
126         if (mDictionaries.contains(newDict)) {
127             Log.w(TAG, "This collection already contains this dictionary: " + newDict);
128         }
129         mDictionaries.add(newDict);
130     }
131 
132     // Warning: this is not thread-safe. Take necessary precaution when calling.
removeDictionary(final Dictionary dict)133     public void removeDictionary(final Dictionary dict) {
134         if (mDictionaries.contains(dict)) {
135             mDictionaries.remove(dict);
136         } else {
137             Log.w(TAG, "This collection does not contain this dictionary: " + dict);
138         }
139     }
140 }
141