From 9f830ff4f8546209a28bc8cc3a831000e92e9a9b Mon Sep 17 00:00:00 2001 From: Thad Hughes Date: Mon, 18 Oct 2010 23:23:58 -0700 Subject: [PATCH] go --- AndroidManifest.xml | 6 +- default.properties | 2 +- res/values/strings.xml | 6 +- .../dictionary/DictionaryActivity.java | 131 +++++++++++++++--- .../android/dictionary/engine/Index.java | 27 ++-- .../android/dictionary/engine/RowBase.java | 6 +- 6 files changed, 142 insertions(+), 36 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index c688901..644efd2 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,13 +2,15 @@ + android:versionName="2.0" + android:installLocation="auto"> - + + Dictionary info: Dictionary file Word list file - File not found: '%s' + File not found: \'%s\' Invalid dictionary: file=%s, error=%s Entries: %d Tokens: %d @@ -74,4 +74,8 @@ URL to use to download the dictionary from the Internet. http://www.stanford.edu/~egirard/dict/de-en.dict + vibrateOnFailedSearch + Vibrate on failed search. + Vibrate the phone when invalid search text is entered. + diff --git a/src/com/hughes/android/dictionary/DictionaryActivity.java b/src/com/hughes/android/dictionary/DictionaryActivity.java index 7f156cf..c8850ff 100644 --- a/src/com/hughes/android/dictionary/DictionaryActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryActivity.java @@ -1,17 +1,19 @@ package com.hughes.android.dictionary; import java.io.File; -import java.io.IOException; import java.io.RandomAccessFile; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; import android.app.ListActivity; +import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.graphics.Typeface; import android.os.Bundle; import android.os.Handler; +import android.os.Vibrator; import android.preference.PreferenceManager; import android.text.Editable; import android.text.Spannable; @@ -21,6 +23,7 @@ import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; +import android.view.inputmethod.InputMethodManager; import android.widget.BaseAdapter; import android.widget.Button; import android.widget.EditText; @@ -39,6 +42,8 @@ import com.hughes.android.util.PersistentObjectCache; public class DictionaryActivity extends ListActivity { static final String LOG = "QuickDic"; + + static final int VIBRATE_MILLIS = 100; RandomAccessFile dictRaf = null; Dictionary dictionary = null; @@ -60,6 +65,10 @@ public class DictionaryActivity extends ListActivity { // Visible for testing. ListAdapter indexAdapter = null; + private Vibrator vibrator = null; + + public DictionaryActivity() { + } public static Intent getIntent(final int dictIndex, final int indexIndex, final String searchToken) { final Intent intent = new Intent(); @@ -74,24 +83,45 @@ public class DictionaryActivity extends ListActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + PersistentObjectCache.init(this); QuickDicConfig quickDicConfig = PersistentObjectCache.init( this).read(C.DICTIONARY_CONFIGS, QuickDicConfig.class); final Intent intent = getIntent(); - final DictionaryConfig dictionaryConfig = quickDicConfig.dictionaryConfigs.get(intent.getIntExtra(C.DICT_INDEX, 0)); + final int dictIndex = intent.getIntExtra(C.DICT_INDEX, 0); try { + final DictionaryConfig dictionaryConfig = quickDicConfig.dictionaryConfigs.get(dictIndex); dictRaf = new RandomAccessFile(dictionaryConfig.localFile, "r"); dictionary = new Dictionary(dictRaf); - } catch (IOException e) { + } catch (Exception e) { Log.e(LOG, "Unable to load dictionary.", e); - // TODO: Start up the editor. + DictionaryEditActivity.getIntent(dictIndex); finish(); return; } + + // Pre-load the collators. + searchExecutor.execute(new Runnable() { + public void run() { + final long startMillis = System.currentTimeMillis(); + for (final Index index : dictionary.indices) { + index.sortLanguage.getFindCollator(); + final com.ibm.icu.text.Collator c = index.sortLanguage + .getSortCollator(); + if (c.compare("pre-print", "preppy") >= 0) { + Log.e(LOG, c.getClass() + + " is buggy, lookups may not work properly."); + } + } + Log.d(LOG, "Loading collators took:" + + (System.currentTimeMillis() - startMillis)); + } + }); - indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0); + indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0) % dictionary.indices.size(); index = dictionary.indices.get(indexIndex); setListAdapter(new IndexAdapter(index)); @@ -105,7 +135,7 @@ public class DictionaryActivity extends ListActivity { final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton); clearSearchTextButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { - //onClearSearchTextButton(clearSearchTextButton); + onClearSearchTextButton(clearSearchTextButton); } }); clearSearchTextButton.setVisibility(PreferenceManager.getDefaultSharedPreferences(this).getBoolean( @@ -122,32 +152,49 @@ public class DictionaryActivity extends ListActivity { final Button upButton = (Button) findViewById(R.id.UpButton); upButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { - //onUpButton(); + onUpDownButton(true); } }); final Button downButton = (Button) findViewById(R.id.DownButton); downButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { - //onDownButton(); + onUpDownButton(false); } }); // ContextMenu. registerForContextMenu(getListView()); + + if (prefs.getBoolean(getString(R.string.vibrateOnFailedSearchKey), true)) { + vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); + } updateLangButton(); } + + // -------------------------------------------------------------------------- + // Buttons + // -------------------------------------------------------------------------- + + private void onClearSearchTextButton(final Button clearSearchTextButton) { + clearSearchTextButton.requestFocus(); + searchText.setText(""); + searchText.requestFocus(); + Log.d(LOG, "Trying to show soft keyboard."); + final InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + manager.showSoftInput(searchText, InputMethodManager.SHOW_IMPLICIT); + } void updateLangButton() { langButton.setText(index.shortName.toUpperCase()); } - - - void onLanguageButton() { - // TODO: synchronized, stop search. + if (currentSearchOperation != null) { + currentSearchOperation.interrupted.set(true); + currentSearchOperation = null; + } indexIndex = (indexIndex + 1) % dictionary.indices.size(); index = dictionary.indices.get(indexIndex); @@ -158,16 +205,58 @@ public class DictionaryActivity extends ListActivity { onSearchTextChange(searchText.getText().toString()); } + void onUpDownButton(final boolean up) { + final int firstVisibleRow = getListView().getFirstVisiblePosition(); + final RowBase row = index.rows.get(firstVisibleRow); + final TokenRow tokenRow = row.getTokenRow(true); + final int destIndexEntry; + if (up) { + if (row != tokenRow) { + destIndexEntry = tokenRow.referenceIndex; + } else { + destIndexEntry = Math.max(tokenRow.referenceIndex - 1, 0); + } + } else { + // Down + destIndexEntry = Math.min(tokenRow.referenceIndex + 1, index.sortedIndexEntries.size()); + } + + Log.d(LOG, "onUpDownButton, destIndexEntry=" + destIndexEntry); + jumpToRow(index.sortedIndexEntries.get(destIndexEntry).startRow); + } + + // -------------------------------------------------------------------------- + // Menu + // -------------------------------------------------------------------------- + // -------------------------------------------------------------------------- // SearchOperation // -------------------------------------------------------------------------- private void searchFinished(final SearchOperation searchOperation) { - if (searchOperation == this.currentSearchOperation) { - setSelection(searchOperation.tokenRow.index()); - getListView().setSelected(true); + if (searchOperation != this.currentSearchOperation) { + return; + } + + final Index.SearchResult searchResult = searchOperation.searchResult; + Log.d(LOG, "searchFinished, " + searchResult.longestPrefixString + ", success=" + searchResult.success); + + jumpToRow(searchResult.longestPrefix.startRow); + + if (!searchResult.success) { + if (vibrator != null) { + vibrator.vibrate(VIBRATE_MILLIS); + } + searchText.setText(searchResult.longestPrefixString); + searchText.setSelection(searchResult.longestPrefixString.length()); + return; } } + + private final void jumpToRow(final int row) { + setSelection(row); + getListView().setSelected(true); + } final class SearchOperation implements Runnable { @@ -175,8 +264,9 @@ public class DictionaryActivity extends ListActivity { final String searchText; final Index index; - boolean failed = false; - TokenRow tokenRow; + long searchStartMillis; + + Index.SearchResult searchResult; SearchOperation(final String searchText, final Index index) { this.searchText = searchText.trim(); @@ -185,8 +275,11 @@ public class DictionaryActivity extends ListActivity { @Override public void run() { - tokenRow = index.findInsertionPoint(searchText, interrupted); - failed = false; // TODO + searchStartMillis = System.currentTimeMillis(); + searchResult = index.findLongestSubstring(searchText, interrupted); + Log.d(LOG, "searchText=" + searchText + ", searchDuration=" + + (System.currentTimeMillis() - searchStartMillis) + ", interrupted=" + + interrupted.get()); if (!interrupted.get()) { uiHandler.post(new Runnable() { @Override diff --git a/src/com/hughes/android/dictionary/engine/Index.java b/src/com/hughes/android/dictionary/engine/Index.java index 6e53cf2..e15c1b7 100644 --- a/src/com/hughes/android/dictionary/engine/Index.java +++ b/src/com/hughes/android/dictionary/engine/Index.java @@ -82,9 +82,9 @@ public final class Index implements RAFSerializable { } } - static final class IndexEntry implements RAFSerializable { - String token; - int startRow; + public static final class IndexEntry implements RAFSerializable { + public final String token; + public final int startRow; static final RAFSerializer SERIALIZER = new RAFSerializer () { @Override @@ -152,35 +152,42 @@ public final class Index implements RAFSerializable { } public static final class SearchResult { - final IndexEntry insertionPoint; - final IndexEntry longestPrefix; - final String longestPrefixString; + public final IndexEntry insertionPoint; + public final IndexEntry longestPrefix; + public final String longestPrefixString; + public final boolean success; public SearchResult(IndexEntry insertionPoint, IndexEntry longestPrefix, - String longestPrefixString) { + String longestPrefixString, boolean success) { this.insertionPoint = insertionPoint; this.longestPrefix = longestPrefix; this.longestPrefixString = longestPrefixString; + this.success = success; } } public SearchResult findLongestSubstring(String token, final AtomicBoolean interrupted) { + if (token.length() == 0) { + return new SearchResult(sortedIndexEntries.get(0), sortedIndexEntries.get(0), "", true); + } IndexEntry insertionPoint = null; IndexEntry result = null; + boolean unmodified = true; while (!interrupted.get() && token.length() > 0) { result = findInsertionPoint(token, interrupted); if (result == null) { return null; } - if (insertionPoint == null) { + if (unmodified) { insertionPoint = result; } if (sortLanguage.textNorm(result.token, true).startsWith(sortLanguage.textNorm(token, true))) { - return new SearchResult(insertionPoint, result, token); + return new SearchResult(insertionPoint, result, token, unmodified); } + unmodified = false; token = token.substring(0, token.length() - 1); } - return new SearchResult(insertionPoint, sortedIndexEntries.get(0), ""); + return new SearchResult(insertionPoint, sortedIndexEntries.get(0), "", false); } private final int windBackCase(final String token, int result, final Collator sortCollator, final AtomicBoolean interrupted) { diff --git a/src/com/hughes/android/dictionary/engine/RowBase.java b/src/com/hughes/android/dictionary/engine/RowBase.java index 2d8bf21..6450058 100644 --- a/src/com/hughes/android/dictionary/engine/RowBase.java +++ b/src/com/hughes/android/dictionary/engine/RowBase.java @@ -11,17 +11,17 @@ public abstract class RowBase extends IndexedObject { /** * the Index owning this RowBase. */ - final Index index; + public final Index index; /** * Where this RowBase points to. */ - int referenceIndex; + public final int referenceIndex; /** * the TokenRow above this RowBase, populated on demand. */ - TokenRow tokenRow = null; + private TokenRow tokenRow = null; RowBase(final RandomAccessFile raf, final int thisRowIndex, final Index index) throws IOException { super(thisRowIndex); -- 2.43.0