From: Thad Hughes Date: Fri, 3 Feb 2012 23:44:05 +0000 (-0800) Subject: Lots of bug fixes! Workaround for ICS OOM, background loading of which X-Git-Url: http://gitweb.fperrin.net/?p=Dictionary.git;a=commitdiff_plain;h=cbcff0e7ca442adc1064f60b56ff2e551243576f Lots of bug fixes! Workaround for ICS OOM, background loading of which dictionaries are available. New screenshots. --- diff --git a/images/dictionary_list.png b/images/dictionary_list.png index eff48de..c57b778 100644 Binary files a/images/dictionary_list.png and b/images/dictionary_list.png differ diff --git a/images/german_fuenf.png b/images/german_fuenf.png deleted file mode 100644 index 24a7e1d..0000000 Binary files a/images/german_fuenf.png and /dev/null differ diff --git a/images/italian_sogni.png b/images/italian_sogni.png deleted file mode 100644 index 6f0e647..0000000 Binary files a/images/italian_sogni.png and /dev/null differ diff --git a/images/nihao_hello.png b/images/nihao_hello.png new file mode 100644 index 0000000..b417463 Binary files /dev/null and b/images/nihao_hello.png differ diff --git a/images/q128x128.png b/images/q128x128.png index ceb7466..738a7e3 100644 Binary files a/images/q128x128.png and b/images/q128x128.png differ diff --git a/images/search_zh_shia_shia_thank_you.png b/images/search_zh_shia_shia_thank_you.png new file mode 100644 index 0000000..6af4762 Binary files /dev/null and b/images/search_zh_shia_shia_thank_you.png differ diff --git a/images/switch_dictionary_quick.png b/images/switch_dictionary_quick.png new file mode 100644 index 0000000..da151c4 Binary files /dev/null and b/images/switch_dictionary_quick.png differ diff --git a/images/v3.1_multi_search_train_station.png b/images/v3.1_multi_search_train_station.png new file mode 100644 index 0000000..e1f93f0 Binary files /dev/null and b/images/v3.1_multi_search_train_station.png differ diff --git a/images/v3.1_search_selected.png b/images/v3.1_search_selected.png new file mode 100644 index 0000000..4da612c Binary files /dev/null and b/images/v3.1_search_selected.png differ diff --git a/res/layout/thadolina_dialog.xml b/res/layout/thadolina_dialog.xml index 440d8fc..e81ccd9 100644 --- a/res/layout/thadolina_dialog.xml +++ b/res/layout/thadolina_dialog.xml @@ -6,26 +6,49 @@ + + + + + + + /> + + \ No newline at end of file diff --git a/res/raw-de/whats_new.html b/res/raw-de/whats_new.html index dcb9326..73c35be 100644 --- a/res/raw-de/whats_new.html +++ b/res/raw-de/whats_new.html @@ -10,7 +10,7 @@ diff --git a/res/raw/help.html b/res/raw/help.html index ac9362c..82e4ac3 100644 --- a/res/raw/help.html +++ b/res/raw/help.html @@ -18,20 +18,27 @@ under all the relevant words.

Searching

-

Other

+

Tricks

diff --git a/res/raw/whats_new.html b/res/raw/whats_new.html index 85d2e92..5ae4cd8 100644 --- a/res/raw/whats_new.html +++ b/res/raw/whats_new.html @@ -10,7 +10,7 @@ diff --git a/res/values-de/languages.xml b/res/values-de/languages.xml new file mode 100644 index 0000000..274120d --- /dev/null +++ b/res/values-de/languages.xml @@ -0,0 +1,80 @@ + + + + Afrikaans + Albanisch + Arabisch + Armenisch + Belarussisch + Bengali + Bosnisch + Bulgarisch + Katalanisch + Kroatisch + Tschechisch + Chinesisch (Mandarin, Kantonesisch) + Dänisch + Niederländisch + Englisch + Esperanto + Estnisch + Finnisch + Französisch + Deutsch + Griechisch + Hawaiian + Hebräisch + Hindi + Ungarisch + Isländisch + Indonesisch + Gälisch (Irisch, Schottisch) + Italienisch + Latin + Lettisch + Litauisch + Japanisch + Korean + Kurdisch + Malay + Maori + Mongolisch + Nepali + Norwegisch + Persisch + Polnisch + Portugiesisch + Punjabi + Rumänisch + Russisch + Sanskrit + Serbisch + Slowakisch + Somali + Spanisch + Swahili + Schwedisch + Tagalog + Tadschikisch + Thailändisch + Tibetisch + Türkisch + Ukrainisch + Urdu + Vietnamesisch + Walisisch + Jiddisch + Zulu + + + Azeri + Baskisch + Breton + Birmanisch + Färöisch + Galizisch + Georgisch + Haitian Creole + Luxemburgisch + Mazedonisch + \ No newline at end of file diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 97f92fa..311b56b 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -12,8 +12,8 @@ Wörterbuch-Liste Long-drücken, um weitere Möglichkeiten zu sehen. - Herunterladen - Neuladen + Herunterladen (%.1fMB) + Neuladen (%.1fMB) Nach Anfang ziehen Wörterbuch entfernen %1$s: %2$,d Wörter @@ -67,6 +67,12 @@ "Fehler beim Herunterladen: \n%s" + + quickdicDirectory + QuickDic Verzeichnis + Das Verzeichnis, in dem QuickDic speichert Wörterbücher. + /sdcard/quickDic/ + wordListFile Wortlist Datei Die lokale Datei, wo das Wortliste hinzugefügt wird. diff --git a/res/values/strings.xml b/res/values/strings.xml index 779d3b9..e7d97dd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -68,6 +68,12 @@ + + quickdicDirectory + QuickDic directory + The directory where QuickDic stores dictionaries. + /sdcard/quickDic/ + wordListFile Word list file The local file where the word list will be appended. diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 30a6066..23a7a03 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -1,5 +1,14 @@ + + + = 0) { - Log.e(LOG, c.getClass() - + " is buggy, lookups may not work properly."); + for (final Index index : dictionary.indices) { + final String searchToken = index.sortedIndexEntries.get(0).token; + final IndexEntry entry = index.findExact(searchToken); + if (!searchToken.equals(entry.token)) { + Log.e(LOG, "Couldn't find token: " + searchToken + ", " + entry.token); + } } + indexPrepFinished = true; + } catch (Exception e) { + Log.w(LOG, "Exception while prepping. This can happen if dictionary is closed while search is happening."); } - Log.d(LOG, "Loading collators took:" - + (System.currentTimeMillis() - startMillis)); + Log.d(LOG, "Prepping indices took:" + + (System.currentTimeMillis() - startMillis)); } - }); + }).start(); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -246,10 +262,15 @@ public class DictionaryActivity extends ListActivity { searchText.requestFocus(); searchText.addTextChangedListener(searchTextWatcher); - final String search = prefs.getString(C.SEARCH_TOKEN, ""); - searchText.setText(search); - searchText.setSelection(0, search.length()); - Log.d(LOG, "Trying to restore searchText=" + search); + String text = ""; + if (savedInstanceState != null) { + text = savedInstanceState.getString(C.SEARCH_TOKEN); + if (text == null) { + text = ""; + } + } + setSearchText(text, true); + Log.d(LOG, "Trying to restore searchText=" + text); final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton); clearSearchTextButton.setOnClickListener(new OnClickListener() { @@ -333,7 +354,7 @@ public class DictionaryActivity extends ListActivity { startActivity(getIntent()); } if (initialSearchText != null) { - setSearchText(initialSearchText); + setSearchText(initialSearchText, true); } } @@ -421,7 +442,7 @@ public class DictionaryActivity extends ListActivity { currentSearchOperation.interrupted.set(true); currentSearchOperation = null; } - changeIndex((indexIndex + 1)% dictionary.indices.size()); + changeIndexGetFocusAndResearch((indexIndex + 1)% dictionary.indices.size()); } void onLanguageButtonLongClick(final Context context) { @@ -477,7 +498,7 @@ public class DictionaryActivity extends ListActivity { } - private void changeIndex(final int newIndex) { + private void changeIndexGetFocusAndResearch(final int newIndex) { indexIndex = newIndex; index = dictionary.indices.get(indexIndex); indexAdapter = new IndexAdapter(index); @@ -565,9 +586,10 @@ public class DictionaryActivity extends ListActivity { for (final EntrySource source : dictionary.sources) { builder.append(getString(R.string.sourceInfo, source.getName(), source.getNumEntries())).append("\n"); } - } else { - builder.append(getString(R.string.invalidDictionary)); } +// } else { +// builder.append(getString(R.string.invalidDictionary)); +// } textView.setText(builder.toString()); dialog.show(); @@ -618,20 +640,30 @@ public class DictionaryActivity extends ListActivity { int indexToUse = -1; for (int i = 0; i < dictionary.indices.size(); ++i) { final Index index = dictionary.indices.get(i); - final IndexEntry indexEntry = index.findExact(selectedText); - final TokenRow tokenRow = index.rows.get(indexEntry.startRow).getTokenRow(false); - if (tokenRow != null && tokenRow.hasMainEntry) { - indexToUse = i; - break; + if (indexPrepFinished) { + System.out.println("Doing index lookup: on " + selectedText); + final IndexEntry indexEntry = index.findExact(selectedText); + if (indexEntry != null) { + final TokenRow tokenRow = index.rows.get(indexEntry.startRow).getTokenRow(false); + if (tokenRow != null && tokenRow.hasMainEntry) { + indexToUse = i; + break; + } + } + } else { + Log.w(LOG, "Skipping findExact on index " + index.shortName); } } if (indexToUse == -1) { indexToUse = selectedSpannableIndex; } - if (indexIndex != indexToUse) { - changeIndex(indexToUse); + final boolean changeIndex = indexIndex != indexToUse; + setSearchText(selectedText, !changeIndex); // If we're not changing index, we have to triggerSearch. + if (changeIndex) { + changeIndexGetFocusAndResearch(indexToUse); } - setSearchText(selectedText); + // Give focus back to list view because typing is done. + getListView().requestFocus(); return false; } }); @@ -701,7 +733,7 @@ public class DictionaryActivity extends ListActivity { public boolean onKeyDown(final int keyCode, final KeyEvent event) { if (event.getUnicodeChar() != 0) { if (!searchText.hasFocus()) { - setSearchText("" + (char) event.getUnicodeChar()); + setSearchText("" + (char) event.getUnicodeChar(), true); } return true; } @@ -718,14 +750,19 @@ public class DictionaryActivity extends ListActivity { return super.onKeyDown(keyCode, event); } - private void setSearchText(final String text) { + private void setSearchText(final String text, final boolean triggerSearch) { + if (!triggerSearch) { + getListView().requestFocus(); + } searchText.setText(text); searchText.requestFocus(); - onSearchTextChange(searchText.getText().toString()); if (searchText.getLayout() != null) { // Surprising, but this can crash when you rotate... Selection.moveToRightEdge(searchText.getText(), searchText.getLayout()); } + if (triggerSearch) { + onSearchTextChange(text); + } } @@ -869,28 +906,36 @@ public class DictionaryActivity extends ListActivity { } @Override - public View getView(int position, final View convertView, ViewGroup parent) { + public TableLayout getView(int position, View convertView, ViewGroup parent) { + final TableLayout result; + if (convertView instanceof TableLayout) { + result = (TableLayout) convertView; + result.removeAllViews(); + } else { + result = new TableLayout(parent.getContext()); + } final RowBase row = getItem(position); if (row instanceof PairEntry.Row) { - return getView(position, (PairEntry.Row) row, parent, convertView); + return getView(position, (PairEntry.Row) row, parent, result); } else if (row instanceof TokenRow) { - return getView((TokenRow) row, parent, convertView); + return getView((TokenRow) row, parent, result); } else { throw new IllegalArgumentException("Unsupported Row type: " + row.getClass()); } } - private View getView(final int position, PairEntry.Row row, ViewGroup parent, final View convertView) { - final TableLayout result = new TableLayout(parent.getContext()); + private TableLayout getView(final int position, PairEntry.Row row, ViewGroup parent, final TableLayout result) { final PairEntry entry = row.getEntry(); final int rowCount = entry.pairs.size(); + + final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(); + layoutParams.weight = 0.5f; + for (int r = 0; r < rowCount; ++r) { final TableRow tableRow = new TableRow(result.getContext()); final TextView col1 = new TextView(tableRow.getContext()); final TextView col2 = new TextView(tableRow.getContext()); - final TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(); - layoutParams.weight = 0.5f; // Set the columns in the table. if (r > 0) { @@ -913,7 +958,6 @@ public class DictionaryActivity extends ListActivity { // Set what's in the columns. - // TODO: color words by gender final Pair pair = entry.pairs.get(r); final String col1Text = index.swapPairEntries ? pair.lang2 : pair.lang1; final String col2Text = index.swapPairEntries ? pair.lang1 : pair.lang2; @@ -948,86 +992,40 @@ public class DictionaryActivity extends ListActivity { col2.setOnLongClickListener(textViewLongClickListenerIndex1); } - // Because we have a Button inside a ListView row: - // http://groups.google.com/group/android-developers/browse_thread/thread/3d96af1530a7d62a?pli=1 - result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); - result.setClickable(true); - result.setFocusable(true); - result.setLongClickable(true); - result.setBackgroundResource(android.R.drawable.menuitem_background); - result.setOnClickListener(new TextView.OnClickListener() { - @Override - public void onClick(View v) { - DictionaryActivity.this.onListItemClick(null, v, position, position); - } - }); - result.addView(tableRow); } - return result; + // Because we have a Button inside a ListView row: + // http://groups.google.com/group/android-developers/browse_thread/thread/3d96af1530a7d62a?pli=1 + result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + result.setClickable(true); + result.setFocusable(true); + result.setLongClickable(true); + result.setBackgroundResource(android.R.drawable.menuitem_background); + result.setOnClickListener(new TextView.OnClickListener() { + @Override + public void onClick(View v) { + DictionaryActivity.this.onListItemClick(getListView(), v, position, position); + } + }); - -// final WebView result = (WebView) (convertView instanceof WebView ? convertView : new WebView(parent.getContext())); -// -// final PairEntry entry = row.getEntry(); -// final int rowCount = entry.pairs.size(); -// final StringBuilder html = new StringBuilder(); -// html.append(""); -// for (int r = 0; r < rowCount; ++r) { -// html.append(""); -// -// final Pair pair = entry.pairs.get(r); -// // TODO: escape both the token and the text. -// final String token = row.getTokenRow(true).getToken(); -// final String col1Text = index.swapPairEntries ? pair.lang2 : pair.lang1; -// final String col2Text = index.swapPairEntries ? pair.lang1 : pair.lang2; -// -// col1Text.replaceAll(token, String.format("%s", token)); -// -// // Column1 -// html.append(""); -// -// // Column2 -// html.append(""); -// -//// column1.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSizeSp); -//// column2.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSizeSp); -// -// html.append(""); -// } -// html.append("
"); -// if (r > 0) { -// html.append("
  • "); -// } -// html.append(col1Text); -// html.append("
  • "); -// if (r > 0) { -// html.append("
  • "); -// } -// html.append(col2Text); -// html.append("
  • "); -// -// Log.i(LOG, html.toString()); -// -// result.getSettings().setRenderPriority(RenderPriority.HIGH); -// result.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); -// -// result.loadData("
    line (connected series of public conveyances, and hence, an established arrangement for forwarding merchandise, etc.) (noun)verbinding
    ", "text/html", "utf-8"); -// -// return result; + return result; } - private View getView(TokenRow row, ViewGroup parent, final View convertView) { + private TableLayout getView(TokenRow row, ViewGroup parent, final TableLayout result) { final Context context = parent.getContext(); final TextView textView = new TextView(context); textView.setText(row.getToken()); - textView.setBackgroundResource(row.hasMainEntry ? theme.tokenRowMainBg : theme.tokenRowOtherBg); // Doesn't work: //textView.setTextColor(android.R.color.secondary_text_light); textView.setTextAppearance(context, theme.tokenRowFg); textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 5 * fontSizeSp / 4); - return textView; + + final TableRow tableRow = new TableRow(result.getContext()); + tableRow.addView(textView); + tableRow.setBackgroundResource(row.hasMainEntry ? theme.tokenRowMainBg : theme.tokenRowOtherBg); + result.addView(tableRow); + return result; } } @@ -1087,6 +1085,15 @@ public class DictionaryActivity extends ListActivity { final Dialog dialog = new Dialog(getListView().getContext()); dialog.setContentView(R.layout.thadolina_dialog); dialog.setTitle("Ti amo, amore mio!"); + final ImageView imageView = (ImageView) dialog.findViewById(R.id.thadolina_image); + imageView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + final Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("https://sites.google.com/site/cfoxroxvday/vday2012")); + startActivity(intent); + } + }); dialog.show(); } if (dictRaf == null) { diff --git a/src/com/hughes/android/dictionary/DictionaryApplication.java b/src/com/hughes/android/dictionary/DictionaryApplication.java index fc80df6..d36e99d 100644 --- a/src/com/hughes/android/dictionary/DictionaryApplication.java +++ b/src/com/hughes/android/dictionary/DictionaryApplication.java @@ -23,17 +23,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import android.app.Application; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.os.Environment; import android.preference.PreferenceManager; import android.util.Log; import android.view.Menu; @@ -50,17 +47,15 @@ public class DictionaryApplication extends Application { static final String LOG = "QuickDicApp"; - private static final File DICT_DIR = new File(Environment.getExternalStorageDirectory().getName(), "quickdic"); - // Static, determined by resources (and locale). // Unordered. static Map DOWNLOADABLE_NAME_TO_INFO = null; static final class DictionaryConfig implements Serializable { - private static final long serialVersionUID = -1444177164708201262L; + private static final long serialVersionUID = -1444177164708201263L; // User-ordered list, persisted, just the ones that are/have been present. - final List dictionaryFilesOrdered = new ArrayList(); - final Set invalidatedFilenames = new LinkedHashSet(); + final List dictionaryFilesOrdered = new ArrayList(); + final Map dictionaryInfoCache = new LinkedHashMap(); } DictionaryConfig dictionaryConfig = null; @@ -70,6 +65,29 @@ public class DictionaryApplication extends Application { final List dictionaryLinks = new ArrayList(); } DictionaryHistory dictionaryHistory = null; + + private File dictDir; + + static synchronized void staticInit(final Context context) { + if (DOWNLOADABLE_NAME_TO_INFO != null) { + return; + } + DOWNLOADABLE_NAME_TO_INFO = new LinkedHashMap(); + final BufferedReader reader = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info))); + try { + String line; + while ((line = reader.readLine()) != null) { + if (line.startsWith("#") || line.length() == 0) { + continue; + } + final DictionaryInfo dictionaryInfo = new DictionaryInfo(line); + DOWNLOADABLE_NAME_TO_INFO.put(dictionaryInfo.uncompressedFilename, dictionaryInfo); + } + reader.close(); + } catch (IOException e) { + Log.e(LOG, "Failed to load downloadable dictionary lists.", e); + } + } @Override @@ -85,7 +103,6 @@ public class DictionaryApplication extends Application { dictionaryConfig = new DictionaryConfig(); } - // Theme stuff. setTheme(getSelectedTheme().themeId); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -101,6 +118,49 @@ public class DictionaryApplication extends Application { }); } + public void onCreateGlobalOptionsMenu( + final Context context, final Menu menu) { + final MenuItem about = menu.add(getString(R.string.about)); + about.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(final MenuItem menuItem) { + final Intent intent = new Intent().setClassName(AboutActivity.class + .getPackage().getName(), AboutActivity.class.getCanonicalName()); + context.startActivity(intent); + return false; + } + }); + + final MenuItem help = menu.add(getString(R.string.help)); + help.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(final MenuItem menuItem) { + context.startActivity(HelpActivity.getLaunchIntent()); + return false; + } + }); + + final MenuItem preferences = menu.add(getString(R.string.preferences)); + preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() { + public boolean onMenuItemClick(final MenuItem menuItem) { + PreferenceActivity.prefsMightHaveChanged = true; + final Intent intent = new Intent().setClassName(PreferenceActivity.class + .getPackage().getName(), PreferenceActivity.class.getCanonicalName()); + context.startActivity(intent); + return false; + } + }); + } + + public synchronized File getDictDir() { + // This metaphore doesn't work, because we've already reset prefsMightHaveChanged. +// if (dictDir == null || PreferenceActivity.prefsMightHaveChanged) { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + final String dir = prefs.getString(getString(R.string.quickdicDirectoryKey), getString(R.string.quickdicDirectoryDefault)); + dictDir = new File(dir); + dictDir.mkdirs(); +// } + return dictDir; + } + public C.Theme getSelectedTheme() { final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); final String theme = prefs.getString(getString(R.string.themeKey), "themeLight"); @@ -111,60 +171,19 @@ public class DictionaryApplication extends Application { } } - static synchronized void staticInit(final Context context) { - if (DOWNLOADABLE_NAME_TO_INFO != null) { - return; - } - DOWNLOADABLE_NAME_TO_INFO = new LinkedHashMap(); - final BufferedReader reader = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(R.raw.dictionary_info))); - try { - String line; - while ((line = reader.readLine()) != null) { - if (line.startsWith("#") || line.length() == 0) { - continue; - } - final DictionaryInfo dictionaryInfo = new DictionaryInfo(line); - DOWNLOADABLE_NAME_TO_INFO.put(dictionaryInfo.uncompressedFilename, dictionaryInfo); - } - reader.close(); - } catch (IOException e) { - Log.e(LOG, "Failed to load downloadable dictionary lists.", e); - } - } - public File getPath(String uncompressedFilename) { - return new File(DICT_DIR, uncompressedFilename); - } - - - public List getUsableDicts() { - final List result = new ArrayList(dictionaryConfig.dictionaryFilesOrdered.size()); - for (int i = 0; i < dictionaryConfig.dictionaryFilesOrdered.size(); ++i) { - DictionaryInfo dictionaryInfo = dictionaryConfig.dictionaryFilesOrdered.get(i); - if (dictionaryConfig.invalidatedFilenames.contains(dictionaryInfo.uncompressedFilename)) { - dictionaryInfo = Dictionary.getDictionaryInfo(getPath(dictionaryInfo.uncompressedFilename)); - if (dictionaryInfo != null) { - dictionaryConfig.dictionaryFilesOrdered.set(i, dictionaryInfo); - } - } - if (dictionaryInfo != null) { - result.add(dictionaryInfo); - } - } - if (!dictionaryConfig.invalidatedFilenames.isEmpty()) { - dictionaryConfig.invalidatedFilenames.clear(); - PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig); - } - return result; + return new File(getDictDir(), uncompressedFilename); } + + final Map fileToNameCache = new LinkedHashMap(); + public String getLanguageName(final String isoCode) { final Language.LanguageResources languageResources = Language.isoCodeToResources.get(isoCode); final String lang = languageResources != null ? getApplicationContext().getString(languageResources.nameId) : isoCode; return lang; } - final Map fileToNameCache = new LinkedHashMap(); public synchronized String getDictionaryName(final String uncompressedFilename) { String name = fileToNameCache.get(uncompressedFilename); if (name != null) { @@ -188,81 +207,121 @@ public class DictionaryApplication extends Application { return name; } - public void moveDictionaryToTop(final DictionaryInfo dictionaryInfo) { - dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo); - dictionaryConfig.dictionaryFilesOrdered.add(0, dictionaryInfo); + public synchronized void moveDictionaryToTop(final DictionaryInfo dictionaryInfo) { + dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo.uncompressedFilename); + dictionaryConfig.dictionaryFilesOrdered.add(0, dictionaryInfo.uncompressedFilename); PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig); } - public void deleteDictionary(final DictionaryInfo dictionaryInfo) { - while (dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo)) {}; + public synchronized void deleteDictionary(final DictionaryInfo dictionaryInfo) { + while (dictionaryConfig.dictionaryFilesOrdered.remove(dictionaryInfo.uncompressedFilename)) {}; + dictionaryConfig.dictionaryInfoCache.remove(dictionaryInfo.uncompressedFilename); getPath(dictionaryInfo.uncompressedFilename).delete(); PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig); } final Collator collator = Collator.getInstance(); - final Comparator comparator = new Comparator() { + final Comparator uncompressedFilenameComparator = new Comparator() { @Override - public int compare(DictionaryInfo object1, DictionaryInfo object2) { - return collator.compare(getDictionaryName(object1.uncompressedFilename), getDictionaryName(object2.uncompressedFilename)); + public int compare(String uncompressedFilename1, String uncompressedFilename2) { + return collator.compare(getDictionaryName(uncompressedFilename1), getDictionaryName(uncompressedFilename2)); } }; - - public List getAllDictionaries() { - final List result = getUsableDicts(); - - // The ones we knew about... - final Set known = new LinkedHashSet(); - for (final DictionaryInfo usable : result) { - known.add(usable.uncompressedFilename); - } - if (!dictionaryConfig.invalidatedFilenames.isEmpty()) { - dictionaryConfig.invalidatedFilenames.clear(); + final Comparator dictionaryInfoComparator = new Comparator() { + @Override + public int compare(DictionaryInfo d1, DictionaryInfo d2) { + return uncompressedFilenameComparator.compare(d1.uncompressedFilename, d2.uncompressedFilename); } - - // Are there dictionaries on the device that we didn't know about already? - // Pick them up and put them at the end of the list. - final List toAddSorted = new ArrayList(); - final File[] dictDirFiles = DICT_DIR.listFiles(); - for (final File file : dictDirFiles) { - // TODO: delete zip files here. - if (!file.getName().endsWith(".quickdic")) { - continue; - } - if (known.contains(file.getName())) { - // We have it in our list already. - continue; - } - final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(file); - if (dictionaryInfo == null) { - Log.e(LOG, "Unable to parse dictionary: " + file.getPath()); - continue; + }; + + public void backgroundUpdateDictionaries(final Runnable onUpdateFinished) { + new Thread(new Runnable() { + @Override + public void run() { + final DictionaryConfig oldDictionaryConfig = new DictionaryConfig(); + synchronized(this) { + oldDictionaryConfig.dictionaryFilesOrdered.addAll(dictionaryConfig.dictionaryFilesOrdered); + } + final DictionaryConfig newDictionaryConfig = new DictionaryConfig(); + for (final String uncompressedFilename : oldDictionaryConfig.dictionaryFilesOrdered) { + final File dictFile = getPath(uncompressedFilename); + final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(dictFile); + if (dictionaryInfo != null) { + newDictionaryConfig.dictionaryFilesOrdered.add(uncompressedFilename); + newDictionaryConfig.dictionaryInfoCache.put(uncompressedFilename, dictionaryInfo); + } + } + + // Are there dictionaries on the device that we didn't know about already? + // Pick them up and put them at the end of the list. + final List toAddSorted = new ArrayList(); + final File[] dictDirFiles = getDictDir().listFiles(); + for (final File file : dictDirFiles) { + if (file.getName().endsWith(".zip")) { + if (DOWNLOADABLE_NAME_TO_INFO.containsKey(file.getName().replace(".zip", ""))) { + file.delete(); + } + } + if (!file.getName().endsWith(".quickdic")) { + continue; + } + if (newDictionaryConfig.dictionaryInfoCache.containsKey(file.getName())) { + // We have it in our list already. + continue; + } + final DictionaryInfo dictionaryInfo = Dictionary.getDictionaryInfo(file); + if (dictionaryInfo == null) { + Log.e(LOG, "Unable to parse dictionary: " + file.getPath()); + continue; + } + + toAddSorted.add(file.getName()); + newDictionaryConfig.dictionaryInfoCache.put(file.getName(), dictionaryInfo); + } + if (!toAddSorted.isEmpty()) { + Collections.sort(toAddSorted, uncompressedFilenameComparator); + newDictionaryConfig.dictionaryFilesOrdered.addAll(toAddSorted); + } + + PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, newDictionaryConfig); + synchronized (this) { + dictionaryConfig = newDictionaryConfig; + } + + try { + onUpdateFinished.run(); + } catch (Exception e) { + Log.e(LOG, "Exception running callback.", e); + } + }}).start(); + } + + public synchronized List getUsableDicts() { + final List result = new ArrayList(dictionaryConfig.dictionaryFilesOrdered.size()); + for (final String uncompressedFilename : dictionaryConfig.dictionaryFilesOrdered) { + final DictionaryInfo dictionaryInfo = dictionaryConfig.dictionaryInfoCache.get(uncompressedFilename); + if (dictionaryInfo != null) { + result.add(dictionaryInfo); } - known.add(file.getName()); - toAddSorted.add(dictionaryInfo); - } - if (!toAddSorted.isEmpty()) { - Collections.sort(toAddSorted, comparator); - result.addAll(toAddSorted); -// for (final DictionaryInfo dictionaryInfo : toAddSorted) { -// dictionaryConfig.dictionaryFilesOrdered.add(dictionaryInfo.uncompressedFilename); -// } - dictionaryConfig.dictionaryFilesOrdered.addAll(toAddSorted); - PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig); } + return result; + } + public synchronized List getAllDictionaries() { + final List result = getUsableDicts(); + // The downloadable ones. final Map remaining = new LinkedHashMap(DOWNLOADABLE_NAME_TO_INFO); - remaining.keySet().removeAll(known); - toAddSorted.clear(); - toAddSorted.addAll(remaining.values()); - Collections.sort(toAddSorted, comparator); + remaining.keySet().removeAll(dictionaryConfig.dictionaryFilesOrdered); + final List toAddSorted = new ArrayList(remaining.values()); + Collections.sort(toAddSorted, dictionaryInfoComparator); result.addAll(toAddSorted); + return result; } - public boolean isDictionaryOnDevice(String uncompressedFilename) { - return getPath(uncompressedFilename).canRead(); + public synchronized boolean isDictionaryOnDevice(String uncompressedFilename) { + return dictionaryConfig.dictionaryInfoCache.get(uncompressedFilename) != null; } public boolean updateAvailable(final DictionaryInfo dictionaryInfo) { @@ -275,41 +334,4 @@ public class DictionaryApplication extends Application { return downloadable; } - public void invalidateDictionaryInfo(final String uncompressedFilename) { - dictionaryConfig.invalidatedFilenames.add(uncompressedFilename); - PersistentObjectCache.getInstance().write(C.DICTIONARY_CONFIGS, dictionaryConfig); - } - - public void onCreateGlobalOptionsMenu( - final Context context, final Menu menu) { - final MenuItem about = menu.add(getString(R.string.about)); - about.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - final Intent intent = new Intent().setClassName(AboutActivity.class - .getPackage().getName(), AboutActivity.class.getCanonicalName()); - context.startActivity(intent); - return false; - } - }); - - final MenuItem help = menu.add(getString(R.string.help)); - help.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - context.startActivity(HelpActivity.getLaunchIntent()); - return false; - } - }); - - final MenuItem preferences = menu.add(getString(R.string.preferences)); - preferences.setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(final MenuItem menuItem) { - PreferenceActivity.prefsMightHaveChanged = true; - final Intent intent = new Intent().setClassName(PreferenceActivity.class - .getPackage().getName(), PreferenceActivity.class.getCanonicalName()); - context.startActivity(intent); - return false; - } - }); - } - } diff --git a/src/com/hughes/android/dictionary/DictionaryManagerActivity.java b/src/com/hughes/android/dictionary/DictionaryManagerActivity.java index 44d7641..f7db7de 100644 --- a/src/com/hughes/android/dictionary/DictionaryManagerActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryManagerActivity.java @@ -23,6 +23,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Handler; import android.preference.PreferenceManager; import android.util.Log; import android.util.TypedValue; @@ -44,6 +45,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import com.hughes.android.dictionary.C.Theme; import com.hughes.android.dictionary.DictionaryInfo.IndexInfo; import com.hughes.android.util.IntentLauncher; import com.hughes.util.StringUtil; @@ -56,6 +58,8 @@ public class DictionaryManagerActivity extends ListActivity { DictionaryApplication application; Adapter adapter; + Handler uiHandler; + public static Intent getLaunchIntent() { final Intent intent = new Intent(); intent.setClassName(DictionaryManagerActivity.class.getPackage().getName(), @@ -117,14 +121,23 @@ public class DictionaryManagerActivity extends ListActivity { } } + @Override + protected void onStart() { + super.onStart(); + uiHandler = new Handler(); + } + + @Override + protected void onStop() { + super.onStop(); + uiHandler = null; + } + private void onClick(int index) { final DictionaryInfo dictionaryInfo = adapter.getItem(index); final DictionaryInfo downloadable = application.getDownloadable(dictionaryInfo.uncompressedFilename); if (!application.isDictionaryOnDevice(dictionaryInfo.uncompressedFilename) && downloadable != null) { - final Intent intent = DownloadActivity - .getLaunchIntent(downloadable.downloadUrl, - application.getPath(dictionaryInfo.uncompressedFilename).getPath() + ".zip", - dictionaryInfo.dictInfo); + final Intent intent = getDownloadIntent(downloadable); startActivity(intent); } else { final Intent intent = DictionaryActivity.getLaunchIntent(application.getPath(dictionaryInfo.uncompressedFilename), 0, ""); @@ -151,6 +164,21 @@ public class DictionaryManagerActivity extends ListActivity { //finish(); return; } + + application.backgroundUpdateDictionaries(new Runnable() { + @Override + public void run() { + if (uiHandler == null) { + return; + } + uiHandler.post(new Runnable() { + @Override + public void run() { + setListAdapter(adapter = new Adapter()); + } + }); + } + }); setListAdapter(adapter = new Adapter()); } @@ -170,7 +198,7 @@ public class DictionaryManagerActivity extends ListActivity { final int position = adapterContextMenuInfo.position; final DictionaryInfo dictionaryInfo = adapter.getItem(position); - if (position > 0) { + if (position > 0 && application.isDictionaryOnDevice(dictionaryInfo.uncompressedFilename)) { final MenuItem moveToTopMenuItem = menu.add(R.string.moveToTop); moveToTopMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override @@ -192,6 +220,28 @@ public class DictionaryManagerActivity extends ListActivity { } }); + final DictionaryInfo downloadable = application.getDownloadable(dictionaryInfo.uncompressedFilename); + if (downloadable != null) { + final MenuItem downloadMenuItem = menu.add(getString(R.string.downloadButton, downloadable.zipBytes/1024.0/1024.0)); + downloadMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + final Intent intent = getDownloadIntent(downloadable); + startActivity(intent); + setListAdapter(adapter = new Adapter()); + return true; + } + + }); + } + + } + + private Intent getDownloadIntent(final DictionaryInfo downloadable) { + final Intent intent = DownloadActivity.getLaunchIntent(downloadable.downloadUrl, + application.getPath(downloadable.uncompressedFilename).getPath() + ".zip", + downloadable.dictInfo); + return intent; } class Adapter extends BaseAdapter { @@ -215,8 +265,16 @@ public class DictionaryManagerActivity extends ListActivity { @Override public View getView(final int position, final View convertView, final ViewGroup parent) { + final LinearLayout result; + // Android 4.0.3 leaks memory like crazy if we don't do this. + if (convertView instanceof LinearLayout) { + result = (LinearLayout) convertView; + result.removeAllViews(); + } else { + result = new LinearLayout(parent.getContext()); + } + final DictionaryInfo dictionaryInfo = getItem(position); - final LinearLayout result = new LinearLayout(parent.getContext()); result.setOrientation(LinearLayout.VERTICAL); final LinearLayout row = new LinearLayout(parent.getContext()); @@ -239,15 +297,8 @@ public class DictionaryManagerActivity extends ListActivity { if ((!application.isDictionaryOnDevice(dictionaryInfo.uncompressedFilename) || updateAvailable) && downloadable != null) { final Button downloadButton = new Button(parent.getContext()); downloadButton.setText(getString(updateAvailable ? R.string.updateButton : R.string.downloadButton, downloadable.zipBytes / 1024.0 / 1024.0)); - downloadButton.setOnClickListener(new IntentLauncher(parent.getContext(), DownloadActivity - .getLaunchIntent(downloadable.downloadUrl, - application.getPath(dictionaryInfo.uncompressedFilename).getPath() + ".zip", - dictionaryInfo.dictInfo)) { - @Override - protected void onGo() { - application.invalidateDictionaryInfo(dictionaryInfo.uncompressedFilename); - } - }); + final Intent intent = getDownloadIntent(downloadable); + downloadButton.setOnClickListener(new IntentLauncher(parent.getContext(), intent)); WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; @@ -290,7 +341,7 @@ public class DictionaryManagerActivity extends ListActivity { DictionaryManagerActivity.this.onClick(position); } }); - + return result; } } diff --git a/src/com/hughes/android/dictionary/PreferenceActivity.java b/src/com/hughes/android/dictionary/PreferenceActivity.java index 96a1b7d..b933382 100644 --- a/src/com/hughes/android/dictionary/PreferenceActivity.java +++ b/src/com/hughes/android/dictionary/PreferenceActivity.java @@ -32,7 +32,5 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { public void onContentChanged() { super.onContentChanged(); } - - }