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