diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index c450a1d4fc89ff6a47ffecfe5d6fd2c67f2ffdee..607f7644b3e956d1924a5ad23854c9fcd19e21d7 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -28,6 +28,7 @@ import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.makedict.WordProperty; +import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.FileUtils; @@ -508,7 +509,9 @@ public final class BinaryDictionary extends Dictionary { */ @UsedForTesting public static int setCurrentTimeForTest(final int currentTime) { - return setCurrentTimeForTestNative(currentTime); + final int currentNativeTimestamp = setCurrentTimeForTestNative(currentTime); + PersonalizationHelper.currentTimeChangedForTesting(currentNativeTimestamp); + return currentNativeTimestamp; } @UsedForTesting diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java index 8c358cd50cf568e2f67619e60b0e8d4b04b06026..ca8a72c9d72f5cfca2a45ad831f88d43d80b1501 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java @@ -163,7 +163,7 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB clearAndFlushDictionary(); } - /* package */ void decayIfNeeded() { + /* package */ void runGCIfRequired() { runGCIfRequired(false /* mindsBlockByGC */); } } diff --git a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java index e9ca662e7a356bcfad2ec6ee04e7b88193a3a17c..de2744f29220f8aa1a3b31f5629b4398a0ea6e3c 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java +++ b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java @@ -43,7 +43,7 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver { /** * Interval to update for decaying dictionaries. */ - private static final long DICTIONARY_DECAY_INTERVAL = TimeUnit.MINUTES.toMillis(60); + /* package */ static final long DICTIONARY_DECAY_INTERVAL = TimeUnit.MINUTES.toMillis(60); public static void setUpIntervalAlarmForDictionaryDecaying(Context context) { AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); @@ -60,7 +60,7 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver { public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) { - PersonalizationHelper.tryDecayingAllOpeningUserHistoryDictionary(); + PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries(); } } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index 5ae2fb6f8add270e9a8cc20fe4f272f29c0e1da3..385b525b6d7ffb35e99813ae764d9ee20f8a6399 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin.personalization; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.FileUtils; @@ -27,6 +28,7 @@ import java.io.FilenameFilter; import java.lang.ref.SoftReference; import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; public class PersonalizationHelper { private static final String TAG = PersonalizationHelper.class.getSimpleName(); @@ -59,14 +61,35 @@ public class PersonalizationHelper { } } - public static void tryDecayingAllOpeningUserHistoryDictionary() { - for (final ConcurrentHashMap.Entry<String, SoftReference<UserHistoryDictionary>> entry - : sLangUserHistoryDictCache.entrySet()) { - if (entry.getValue() != null) { - final UserHistoryDictionary dict = entry.getValue().get(); - if (dict != null) { - dict.decayIfNeeded(); - } + private static int sCurrentTimestampForTesting = 0; + public static void currentTimeChangedForTesting(final int currentTimestamp) { + if (TimeUnit.MILLISECONDS.toSeconds( + DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL) + < currentTimestamp - sCurrentTimestampForTesting) { + // TODO: Run GC for both PersonalizationDictionary and UserHistoryDictionary. + runGCOnAllOpenedUserHistoryDictionaries(); + } + } + + public static void runGCOnAllOpenedUserHistoryDictionaries() { + runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache); + } + + @UsedForTesting + public static void runGCOnAllOpenedPersonalizationDictionaries() { + runGCOnAllDictionariesIfRequired(sLangPersonalizationDictCache); + } + + private static <T extends DecayingExpandableBinaryDictionaryBase> + void runGCOnAllDictionariesIfRequired( + final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) { + for (final ConcurrentHashMap.Entry<String, SoftReference<T>> entry + : dictionaryMap.entrySet()) { + final DecayingExpandableBinaryDictionaryBase dict = entry.getValue().get(); + if (dict != null) { + dict.runGCIfRequired(); + } else { + dictionaryMap.remove(entry.getKey()); } } } diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java index b1239f0af810b31a78ee9cb43c9441038defb3fa..6ace2de4f924b481900e97141aa4f033b13e2269 100644 --- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java @@ -267,13 +267,13 @@ public class UserHistoryDictionaryTests extends AndroidTestCase { assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); } forcePassingShortTime(); - dict.decayIfNeeded(); + dict.runGCIfRequired(); dict.waitAllTasksForTests(); for (final String word : words) { assertTrue(dict.isInUnderlyingBinaryDictionaryForTests(word)); } forcePassingLongTime(); - dict.decayIfNeeded(); + dict.runGCIfRequired(); dict.waitAllTasksForTests(); for (final String word : words) { assertFalse(dict.isInUnderlyingBinaryDictionaryForTests(word));