+import com.hughes.util.ListUtil;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public enum DictionaryApplication {
+ INSTANCE;
+
+ private Context appContext;
+
+ static final String LOG = "QuickDicApp";
+
+ // If set to false, avoid use of ICU collator
+ // Works well enough for most european languages,
+ // gives faster startup and avoids crashes on some
+ // devices due to Dalvik bugs (e.g. ARMv6, S5570i, CM11)
+ // when using ICU4J.
+ // Leave it enabled by default for correctness except
+ // for my known broken development/performance test device config.
+ //static public final boolean USE_COLLATOR = !android.os.Build.FINGERPRINT.equals("Samsung/cm_tassve/tassve:4.4.4/KTU84Q/20150211:userdebug/release-keys");
+ public static final boolean USE_COLLATOR = true;
+
+ public static final TransliteratorManager.ThreadSetup threadBackground = new TransliteratorManager.ThreadSetup() {
+ @Override
+ public void onThreadStart() {
+ // THREAD_PRIORITY_BACKGROUND seemed like a good idea, but it
+ // can make Transliterator go from 20 seconds to 3 minutes (!)
+ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
+ }
+ };
+
+ // Static, determined by resources (and locale).
+ // Unordered.
+ static Map<String, DictionaryInfo> DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO = null;
+
+ enum Theme {
+ DEFAULT(R.style.Theme_Default,
+ R.style.Theme_Default_TokenRow_Fg,
+ R.color.theme_default_token_row_fg,
+ R.drawable.theme_default_token_row_main_bg,
+ R.drawable.theme_default_token_row_other_bg,
+ R.drawable.theme_default_normal_row_bg),
+
+ LIGHT(R.style.Theme_Light,
+ R.style.Theme_Light_TokenRow_Fg,
+ R.color.theme_light_token_row_fg,
+ R.drawable.theme_light_token_row_main_bg,
+ R.drawable.theme_light_token_row_other_bg,
+ R.drawable.theme_light_normal_row_bg);
+
+ Theme(final int themeId, final int tokenRowFg,
+ final int tokenRowFgColor,
+ final int tokenRowMainBg, final int tokenRowOtherBg,
+ final int normalRowBg) {
+ this.themeId = themeId;
+ this.tokenRowFg = tokenRowFg;
+ this.tokenRowFgColor = tokenRowFgColor;
+ this.tokenRowMainBg = tokenRowMainBg;
+ this.tokenRowOtherBg = tokenRowOtherBg;
+ this.normalRowBg = normalRowBg;
+ }
+
+ final int themeId;
+ final int tokenRowFg;
+ final int tokenRowFgColor;
+ final int tokenRowMainBg;
+ final int tokenRowOtherBg;
+ final int normalRowBg;
+ }
+
+ public static final class DictionaryConfig implements Serializable {
+ private static final long serialVersionUID = -1444177164708201263L;
+ // User-ordered list, persisted, just the ones that are/have been
+ // present.
+ final List<String> dictionaryFilesOrdered = new ArrayList<>();
+
+ final Map<String, DictionaryInfo> uncompressedFilenameToDictionaryInfo = new HashMap<>();
+
+ /**
+ * Sometimes a deserialized version of this data structure isn't valid.
+ */
+ @SuppressWarnings("ConstantConditions")
+ boolean isValid() {
+ return uncompressedFilenameToDictionaryInfo != null && dictionaryFilesOrdered != null;
+ }
+ }
+
+ DictionaryConfig dictionaryConfig = null;
+
+ public int languageButtonPixels = -1;
+
+ static synchronized void staticInit(final Context context) {
+ if (DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO != null) {
+ return;
+ }
+ DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO = new HashMap<>();
+ final BufferedReader reader = new BufferedReader(
+ new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info)));
+ try {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (line.length() == 0 || line.charAt(0) == '#') {
+ continue;
+ }
+ final DictionaryInfo dictionaryInfo = new DictionaryInfo(line);
+ DOWNLOADABLE_UNCOMPRESSED_FILENAME_NAME_TO_DICTIONARY_INFO.put(
+ dictionaryInfo.uncompressedFilename, dictionaryInfo);
+ }
+ } catch (IOException e) {
+ Log.e(LOG, "Failed to load downloadable dictionary lists.", e);
+ }
+ try {
+ reader.close();
+ } catch (IOException ignored) {}
+ }
+
+ public synchronized void init(Context c) {
+ if (appContext != null) {
+ assert c == appContext;
+ return;
+ }
+ appContext = c;
+ Log.d("QuickDic", "Application: onCreate");
+ TransliteratorManager.init(null, threadBackground);
+ staticInit(appContext);
+
+ languageButtonPixels = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 60, appContext.getResources().getDisplayMetrics());
+
+ // Load the dictionaries we know about.
+ dictionaryConfig = PersistentObjectCache.init(appContext).read(
+ C.DICTIONARY_CONFIGS, DictionaryConfig.class);
+ if (dictionaryConfig == null) {
+ dictionaryConfig = new DictionaryConfig();
+ }
+ if (!dictionaryConfig.isValid()) {
+ dictionaryConfig = new DictionaryConfig();
+ }
+
+ // Theme stuff.
+ appContext.setTheme(getSelectedTheme().themeId);
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
+ prefs.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ Log.d("QuickDic", "prefs changed: " + key);
+ if (key.equals(appContext.getString(R.string.themeKey))) {
+ appContext.setTheme(getSelectedTheme().themeId);
+ }
+ }
+ });
+ }
+
+ public static void onCreateGlobalOptionsMenu(
+ final Context context, final Menu menu) {
+ final Context c = context.getApplicationContext();
+
+ final MenuItem preferences = menu.add(c.getString(R.string.settings));
+ MenuItemCompat.setShowAsAction(preferences, MenuItem.SHOW_AS_ACTION_NEVER);
+ preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(final MenuItem menuItem) {
+ PreferenceActivity.prefsMightHaveChanged = true;
+ final Intent intent = new Intent(c, PreferenceActivity.class);
+ context.startActivity(intent);
+ return false;
+ }
+ });
+
+ final MenuItem help = menu.add(c.getString(R.string.help));
+ MenuItemCompat.setShowAsAction(help, MenuItem.SHOW_AS_ACTION_NEVER);
+ help.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(final MenuItem menuItem) {
+ context.startActivity(HtmlDisplayActivity.getHelpLaunchIntent(c));
+ return false;
+ }
+ });
+
+ final MenuItem reportIssue = menu.add(c.getString(R.string.reportIssue));
+ MenuItemCompat.setShowAsAction(reportIssue, MenuItem.SHOW_AS_ACTION_NEVER);
+ reportIssue.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(final MenuItem menuItem) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri
+ .parse("https://github.com/rdoeffinger/Dictionary/issues"));
+ context.startActivity(intent);
+ return false;
+ }
+ });
+
+ final MenuItem about = menu.add(c.getString(R.string.about));
+ MenuItemCompat.setShowAsAction(about, MenuItem.SHOW_AS_ACTION_NEVER);
+ about.setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(final MenuItem menuItem) {
+ final Intent intent = new Intent(c, AboutActivity.class);
+ context.startActivity(intent);
+ return false;
+ }
+ });