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