]> gitweb.fperrin.net Git - Dictionary.git/commitdiff
go
authorThad Hughes <thad.hughes@gmail.com>
Tue, 19 Oct 2010 06:23:58 +0000 (23:23 -0700)
committerThad Hughes <thad.hughes@gmail.com>
Tue, 19 Oct 2010 06:23:58 +0000 (23:23 -0700)
AndroidManifest.xml
default.properties
res/values/strings.xml
src/com/hughes/android/dictionary/DictionaryActivity.java
src/com/hughes/android/dictionary/engine/Index.java
src/com/hughes/android/dictionary/engine/RowBase.java

index c6889012843d018ec152f1d8be80f864ff9de432..644efd27aa137698087d5d4782858857486df3fb 100644 (file)
@@ -2,13 +2,15 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.hughes.android.dictionary" android:versionCode="9"
- android:versionName="2.0">
+ android:versionName="2.0"
+ android:installLocation="auto">
 
  <uses-sdk android:minSdkVersion="4" />
 
  <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.VIBRATE" />
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
  <application 
   android:icon="@drawable/icon"
index 19c96655d772aa6da4be76417b997aa63fa6cfcb..51e933a98fd96dd5f348b0c3b0f78f52c68717e2 100644 (file)
@@ -10,4 +10,4 @@
 # Indicates whether an apk should be generated for each density.
 split.density=false
 # Project target.
-target=android-4
+target=android-8
index 7a60885343af24ccc941c93273beb428f6c3f207..ea95fb865b998c4ea098509a513797d942baafb6 100644 (file)
@@ -19,7 +19,7 @@
   <string name="dictionaryInfo">Dictionary info:</string>
   <string name="localFile">Dictionary file</string>
   <string name="wordListFile">Word list file</string>
-  <string name="fileNotFound">File not found: '%s'</string>
+  <string name="fileNotFound">File not found: \'%s\'</string>
   <string name="invalidDictionary">Invalid dictionary: file=%s, error=%s</string>
   <string name="numPairEntries">Entries: %d</string>
   <string name="numTokens">Tokens: %d</string>
@@ -74,4 +74,8 @@
        <string name="dictFetchUrlSummary">URL to use to download the dictionary from the Internet.</string>
        <string name="dictFetchUrlDefault">http://www.stanford.edu/~egirard/dict/de-en.dict</string>
 
+  <string name="vibrateOnFailedSearchKey">vibrateOnFailedSearch</string>
+  <string name="vibrateOnFailedSearchTitle">Vibrate on failed search.</string>
+  <string name="vibrateOnFailedSearchSummary">Vibrate the phone when invalid search text is entered.</string>
+
 </resources>
index 7f156cfea69d776c5c927da37223c06712fe76a6..c8850ffafb4627421d2cf9357f6344cfcdfa1b23 100644 (file)
@@ -1,17 +1,19 @@
 package com.hughes.android.dictionary;\r
 \r
 import java.io.File;\r
-import java.io.IOException;\r
 import java.io.RandomAccessFile;\r
 import java.util.concurrent.Executor;\r
 import java.util.concurrent.Executors;\r
 import java.util.concurrent.atomic.AtomicBoolean;\r
 \r
 import android.app.ListActivity;\r
+import android.content.Context;\r
 import android.content.Intent;\r
+import android.content.SharedPreferences;\r
 import android.graphics.Typeface;\r
 import android.os.Bundle;\r
 import android.os.Handler;\r
+import android.os.Vibrator;\r
 import android.preference.PreferenceManager;\r
 import android.text.Editable;\r
 import android.text.Spannable;\r
@@ -21,6 +23,7 @@ import android.util.Log;
 import android.view.View;\r
 import android.view.ViewGroup;\r
 import android.view.View.OnClickListener;\r
+import android.view.inputmethod.InputMethodManager;\r
 import android.widget.BaseAdapter;\r
 import android.widget.Button;\r
 import android.widget.EditText;\r
@@ -39,6 +42,8 @@ import com.hughes.android.util.PersistentObjectCache;
 public class DictionaryActivity extends ListActivity {\r
 \r
   static final String LOG = "QuickDic";\r
+  \r
+  static final int VIBRATE_MILLIS = 100;\r
 \r
   RandomAccessFile dictRaf = null;\r
   Dictionary dictionary = null;\r
@@ -60,6 +65,10 @@ public class DictionaryActivity extends ListActivity {
   // Visible for testing.\r
   ListAdapter indexAdapter = null;\r
 \r
+  private Vibrator vibrator = null;\r
+  \r
+  public DictionaryActivity() {\r
+  }\r
   \r
   public static Intent getIntent(final int dictIndex, final int indexIndex, final String searchToken) {\r
     final Intent intent = new Intent();\r
@@ -74,24 +83,45 @@ public class DictionaryActivity extends ListActivity {
   public void onCreate(Bundle savedInstanceState) {\r
     super.onCreate(savedInstanceState);\r
     \r
+    final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);\r
+    \r
     PersistentObjectCache.init(this);\r
     QuickDicConfig quickDicConfig = PersistentObjectCache.init(\r
         this).read(C.DICTIONARY_CONFIGS, QuickDicConfig.class);\r
     \r
     final Intent intent = getIntent();\r
     \r
-    final DictionaryConfig dictionaryConfig = quickDicConfig.dictionaryConfigs.get(intent.getIntExtra(C.DICT_INDEX, 0));\r
+    final int dictIndex = intent.getIntExtra(C.DICT_INDEX, 0);\r
     try {\r
+      final DictionaryConfig dictionaryConfig = quickDicConfig.dictionaryConfigs.get(dictIndex);\r
       dictRaf = new RandomAccessFile(dictionaryConfig.localFile, "r");\r
       dictionary = new Dictionary(dictRaf); \r
-    } catch (IOException e) {\r
+    } catch (Exception e) {\r
       Log.e(LOG, "Unable to load dictionary.", e);\r
-      // TODO: Start up the editor.\r
+      DictionaryEditActivity.getIntent(dictIndex);\r
       finish();\r
       return;\r
     }\r
+\r
+    // Pre-load the collators.\r
+    searchExecutor.execute(new Runnable() {\r
+      public void run() {\r
+        final long startMillis = System.currentTimeMillis();\r
+        for (final Index index : dictionary.indices) {\r
+          index.sortLanguage.getFindCollator();\r
+          final com.ibm.icu.text.Collator c = index.sortLanguage\r
+              .getSortCollator();\r
+          if (c.compare("pre-print", "preppy") >= 0) {\r
+            Log.e(LOG, c.getClass()\r
+                + " is buggy, lookups may not work properly.");\r
+          }\r
+        }\r
+        Log.d(LOG, "Loading collators took:"\r
+            + (System.currentTimeMillis() - startMillis));\r
+      }\r
+    });\r
     \r
-    indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0);\r
+    indexIndex = intent.getIntExtra(C.INDEX_INDEX, 0) % dictionary.indices.size();\r
     index = dictionary.indices.get(indexIndex);\r
     setListAdapter(new IndexAdapter(index));\r
     \r
@@ -105,7 +135,7 @@ public class DictionaryActivity extends ListActivity {
     final Button clearSearchTextButton = (Button) findViewById(R.id.ClearSearchTextButton);\r
     clearSearchTextButton.setOnClickListener(new OnClickListener() {\r
       public void onClick(View v) {\r
-        //onClearSearchTextButton(clearSearchTextButton);\r
+        onClearSearchTextButton(clearSearchTextButton);\r
       }\r
     });\r
     clearSearchTextButton.setVisibility(PreferenceManager.getDefaultSharedPreferences(this).getBoolean(\r
@@ -122,32 +152,49 @@ public class DictionaryActivity extends ListActivity {
     final Button upButton = (Button) findViewById(R.id.UpButton);\r
     upButton.setOnClickListener(new OnClickListener() {\r
       public void onClick(View v) {\r
-        //onUpButton();\r
+        onUpDownButton(true);\r
       }\r
     });\r
     final Button downButton = (Button) findViewById(R.id.DownButton);\r
     downButton.setOnClickListener(new OnClickListener() {\r
       public void onClick(View v) {\r
-        //onDownButton();\r
+        onUpDownButton(false);\r
       }\r
     });\r
 \r
     // ContextMenu.\r
     registerForContextMenu(getListView());\r
+    \r
+    if (prefs.getBoolean(getString(R.string.vibrateOnFailedSearchKey), true)) {\r
+      vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);\r
+    }\r
 \r
     updateLangButton();\r
 \r
   }\r
+\r
+  // --------------------------------------------------------------------------\r
+  // Buttons\r
+  // --------------------------------------------------------------------------\r
+\r
+  private void onClearSearchTextButton(final Button clearSearchTextButton) {\r
+    clearSearchTextButton.requestFocus();\r
+    searchText.setText("");\r
+    searchText.requestFocus();\r
+    Log.d(LOG, "Trying to show soft keyboard.");\r
+    final InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);\r
+    manager.showSoftInput(searchText, InputMethodManager.SHOW_IMPLICIT);\r
+  }\r
   \r
   void updateLangButton() {\r
     langButton.setText(index.shortName.toUpperCase());\r
   }\r
 \r
-\r
-  \r
-  \r
   void onLanguageButton() {\r
-    // TODO: synchronized, stop search.\r
+    if (currentSearchOperation != null) {\r
+      currentSearchOperation.interrupted.set(true);\r
+      currentSearchOperation = null;\r
+    }\r
     \r
     indexIndex = (indexIndex + 1) % dictionary.indices.size();\r
     index = dictionary.indices.get(indexIndex);\r
@@ -158,16 +205,58 @@ public class DictionaryActivity extends ListActivity {
     onSearchTextChange(searchText.getText().toString());\r
   }\r
   \r
+  void onUpDownButton(final boolean up) {\r
+    final int firstVisibleRow = getListView().getFirstVisiblePosition();\r
+    final RowBase row = index.rows.get(firstVisibleRow);\r
+    final TokenRow tokenRow = row.getTokenRow(true);\r
+    final int destIndexEntry;\r
+    if (up) {\r
+      if (row != tokenRow) {\r
+        destIndexEntry = tokenRow.referenceIndex;\r
+      } else {\r
+        destIndexEntry = Math.max(tokenRow.referenceIndex - 1, 0);\r
+      }\r
+    } else {\r
+      // Down\r
+      destIndexEntry = Math.min(tokenRow.referenceIndex + 1, index.sortedIndexEntries.size());\r
+    }\r
+    \r
+    Log.d(LOG, "onUpDownButton, destIndexEntry=" + destIndexEntry);\r
+    jumpToRow(index.sortedIndexEntries.get(destIndexEntry).startRow);\r
+  }\r
+\r
+  // --------------------------------------------------------------------------\r
+  // Menu\r
+  // --------------------------------------------------------------------------\r
+\r
   // --------------------------------------------------------------------------\r
   // SearchOperation\r
   // --------------------------------------------------------------------------\r
 \r
   private void searchFinished(final SearchOperation searchOperation) {\r
-    if (searchOperation == this.currentSearchOperation) {\r
-      setSelection(searchOperation.tokenRow.index());\r
-      getListView().setSelected(true);\r
+    if (searchOperation != this.currentSearchOperation) {\r
+      return;\r
+    }\r
+    \r
+    final Index.SearchResult searchResult = searchOperation.searchResult;\r
+    Log.d(LOG, "searchFinished, " + searchResult.longestPrefixString + ", success=" + searchResult.success);\r
+\r
+    jumpToRow(searchResult.longestPrefix.startRow);\r
+    \r
+    if (!searchResult.success) {\r
+      if (vibrator != null) {\r
+        vibrator.vibrate(VIBRATE_MILLIS);\r
+      }\r
+      searchText.setText(searchResult.longestPrefixString);\r
+      searchText.setSelection(searchResult.longestPrefixString.length());\r
+      return;\r
     }\r
   }\r
+  \r
+  private final void jumpToRow(final int row) {\r
+    setSelection(row);\r
+    getListView().setSelected(true);\r
+  }\r
 \r
   final class SearchOperation implements Runnable {\r
     \r
@@ -175,8 +264,9 @@ public class DictionaryActivity extends ListActivity {
     final String searchText;\r
     final Index index;\r
     \r
-    boolean failed = false;\r
-    TokenRow tokenRow;\r
+    long searchStartMillis;\r
+\r
+    Index.SearchResult searchResult;\r
     \r
     SearchOperation(final String searchText, final Index index) {\r
       this.searchText = searchText.trim();\r
@@ -185,8 +275,11 @@ public class DictionaryActivity extends ListActivity {
 \r
     @Override\r
     public void run() {\r
-      tokenRow = index.findInsertionPoint(searchText, interrupted);\r
-      failed = false; // TODO\r
+      searchStartMillis = System.currentTimeMillis();\r
+      searchResult = index.findLongestSubstring(searchText, interrupted);\r
+      Log.d(LOG, "searchText=" + searchText + ", searchDuration="\r
+          + (System.currentTimeMillis() - searchStartMillis) + ", interrupted="\r
+          + interrupted.get());\r
       if (!interrupted.get()) {\r
         uiHandler.post(new Runnable() {\r
           @Override\r
index 6e53cf24db1894df4e0daabd864d25e649649f82..e15c1b74502cd8cc6d100f035e3ba55544ee843b 100644 (file)
@@ -82,9 +82,9 @@ public final class Index implements RAFSerializable<Index> {
     }
   }
   
-  static final class IndexEntry implements RAFSerializable<Index.IndexEntry> {
-    String token;
-    int startRow;
+  public static final class IndexEntry implements RAFSerializable<Index.IndexEntry> {
+    public final String token;
+    public final int startRow;
     
     static final RAFSerializer<IndexEntry> SERIALIZER = new RAFSerializer<IndexEntry> () {
       @Override
@@ -152,35 +152,42 @@ public final class Index implements RAFSerializable<Index> {
   }
   
   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) {
index 2d8bf21fee8636dad299fd331b72df030ef72309..64500585e4b9716c78a300346bbac4b5a1ba849e 100644 (file)
@@ -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);