PersonalizationHelper.java revision 89eaa6701fd40c909cda492712b9afa7134805e1
1/*
2 * Copyright (C) 2013 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.android.inputmethod.latin.personalization;
18
19import com.android.inputmethod.latin.utils.CollectionUtils;
20import com.android.inputmethod.latin.utils.FileUtils;
21
22import android.content.Context;
23import android.util.Log;
24
25import java.io.File;
26import java.io.FilenameFilter;
27import java.lang.ref.SoftReference;
28import java.util.Locale;
29import java.util.concurrent.ConcurrentHashMap;
30import java.util.concurrent.TimeUnit;
31
32public class PersonalizationHelper {
33    private static final String TAG = PersonalizationHelper.class.getSimpleName();
34    private static final boolean DEBUG = false;
35    private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
36            sLangUserHistoryDictCache = CollectionUtils.newConcurrentHashMap();
37    private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>>
38            sLangPersonalizationDictCache = CollectionUtils.newConcurrentHashMap();
39
40    public static UserHistoryDictionary getUserHistoryDictionary(
41            final Context context, final Locale locale) {
42        final String localeStr = locale.toString();
43        synchronized (sLangUserHistoryDictCache) {
44            if (sLangUserHistoryDictCache.containsKey(localeStr)) {
45                final SoftReference<UserHistoryDictionary> ref =
46                        sLangUserHistoryDictCache.get(localeStr);
47                final UserHistoryDictionary dict = ref == null ? null : ref.get();
48                if (dict != null) {
49                    if (DEBUG) {
50                        Log.w(TAG, "Use cached UserHistoryDictionary for " + locale);
51                    }
52                    dict.reloadDictionaryIfRequired();
53                    return dict;
54                }
55            }
56            final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale);
57            sLangUserHistoryDictCache.put(localeStr,
58                    new SoftReference<UserHistoryDictionary>(dict));
59            return dict;
60        }
61    }
62
63    private static int sCurrentTimestampForTesting = 0;
64    public static void currentTimeChangedForTesting(final int currentTimestamp) {
65        if (TimeUnit.MILLISECONDS.toSeconds(
66                DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL)
67                        < currentTimestamp - sCurrentTimestampForTesting) {
68            runGCOnAllOpenedUserHistoryDictionaries();
69            runGCOnAllOpenedPersonalizationDictionaries();
70        }
71    }
72
73    public static void runGCOnAllOpenedUserHistoryDictionaries() {
74        runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache);
75    }
76
77    public static void runGCOnAllOpenedPersonalizationDictionaries() {
78        runGCOnAllDictionariesIfRequired(sLangPersonalizationDictCache);
79    }
80
81    private static <T extends DecayingExpandableBinaryDictionaryBase>
82            void runGCOnAllDictionariesIfRequired(
83                    final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) {
84        for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry
85                : dictionaryMap.entrySet()) {
86            final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get();
87            if (dict != null) {
88                dict.runGCIfRequired();
89            } else {
90                dictionaryMap.remove(entry.getKey());
91            }
92        }
93    }
94
95    public static PersonalizationDictionary getPersonalizationDictionary(
96            final Context context, final Locale locale) {
97        final String localeStr = locale.toString();
98        synchronized (sLangPersonalizationDictCache) {
99            if (sLangPersonalizationDictCache.containsKey(localeStr)) {
100                final SoftReference<PersonalizationDictionary> ref =
101                        sLangPersonalizationDictCache.get(localeStr);
102                final PersonalizationDictionary dict = ref == null ? null : ref.get();
103                if (dict != null) {
104                    if (DEBUG) {
105                        Log.w(TAG, "Use cached PersonalizationDictionary for " + locale);
106                    }
107                    return dict;
108                }
109            }
110            final PersonalizationDictionary dict = new PersonalizationDictionary(context, locale);
111            sLangPersonalizationDictCache.put(
112                    localeStr, new SoftReference<PersonalizationDictionary>(dict));
113            return dict;
114        }
115    }
116
117    public static void removeAllPersonalizationDictionaries(final Context context) {
118        removeAllDictionaries(context, sLangPersonalizationDictCache,
119                PersonalizationDictionary.NAME);
120    }
121
122    public static void removeAllUserHistoryDictionaries(final Context context) {
123        removeAllDictionaries(context, sLangUserHistoryDictCache,
124                UserHistoryDictionary.NAME);
125    }
126
127    private static <T extends DecayingExpandableBinaryDictionaryBase> void removeAllDictionaries(
128            final Context context, final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap,
129            final String dictNamePrefix) {
130        synchronized (dictionaryMap) {
131            for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry
132                    : dictionaryMap.entrySet()) {
133                if (entry.getValue() != null) {
134                    final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get();
135                    if (dict != null) {
136                        dict.clear();
137                    }
138                }
139            }
140            dictionaryMap.clear();
141            if (!FileUtils.deleteFilteredFiles(
142                    context.getFilesDir(), new DictFilter(dictNamePrefix))) {
143                Log.e(TAG, "Cannot remove all existing dictionary files. filesDir: "
144                        + context.getFilesDir().getAbsolutePath() + ", dictNamePrefix: "
145                        + dictNamePrefix);
146            }
147        }
148    }
149
150    private static class DictFilter implements FilenameFilter {
151        private final String mName;
152
153        DictFilter(final String name) {
154            mName = name;
155        }
156
157        @Override
158        public boolean accept(final File dir, final String name) {
159            return name.startsWith(mName);
160        }
161    }
162}
163