X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=src%2Fcom%2Fhughes%2Fandroid%2Fdictionary%2FDictionaryActivity.java;h=ac77c8558c8d6be0e62a06ac36522f261436a0bd;hb=01332c7697b595328bbd5397e95341a0dd575493;hp=92ec72e341b8ece1885a9f716c9faebfe52e86e4;hpb=606cbb1a9a064eb9da500784514fa05e926654d5;p=Dictionary.git diff --git a/src/com/hughes/android/dictionary/DictionaryActivity.java b/src/com/hughes/android/dictionary/DictionaryActivity.java index 92ec72e..ac77c85 100644 --- a/src/com/hughes/android/dictionary/DictionaryActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryActivity.java @@ -20,6 +20,7 @@ import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; @@ -41,6 +42,7 @@ import android.text.Spannable; import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.style.StyleSpan; +import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.ContextMenu; @@ -194,7 +196,7 @@ public class DictionaryActivity extends ActionBarActivity { } public static Intent getLaunchIntent(Context c, final File dictFile, final String indexShortName, - final String searchToken) { + final String searchToken) { final Intent intent = new Intent(c, DictionaryActivity.class); intent.putExtra(C.DICT_FILE, dictFile.getPath()); intent.putExtra(C.INDEX_SHORT_NAME, indexShortName); @@ -211,11 +213,9 @@ public class DictionaryActivity extends ActionBarActivity { outState.putString(C.SEARCH_TOKEN, searchView.getQuery().toString()); } - private int getMatchLen(String search, Index.IndexEntry e) - { + private int getMatchLen(String search, Index.IndexEntry e) { if (e == null) return 0; - for (int i = 0; i < search.length(); ++i) - { + for (int i = 0; i < search.length(); ++i) { String a = search.substring(0, i + 1); String b = e.token.substring(0, i + 1); if (!a.equalsIgnoreCase(b)) @@ -254,8 +254,7 @@ public class DictionaryActivity extends ActionBarActivity { * -> language in which the phrase is written to -> to which * language shall be translated */ - if (intentAction != null && intentAction.equals("com.hughes.action.ACTION_SEARCH_DICT")) - { + if (intentAction != null && intentAction.equals("com.hughes.action.ACTION_SEARCH_DICT")) { String query = intent.getStringExtra(SearchManager.QUERY); String from = intent.getStringExtra("from"); if (from != null) @@ -263,42 +262,35 @@ public class DictionaryActivity extends ActionBarActivity { String to = intent.getStringExtra("to"); if (to != null) to = to.toLowerCase(Locale.US); - if (query != null) - { + if (query != null) { getIntent().putExtra(C.SEARCH_TOKEN, query); } - if (intent.getStringExtra(C.DICT_FILE) == null && (from != null || to != null)) - { + if (intent.getStringExtra(C.DICT_FILE) == null && (from != null || to != null)) { Log.d(LOG, "DictSearch: from: " + from + " to " + to); List dicts = application.getDictionariesOnDevice(null); - for (DictionaryInfo info : dicts) - { + for (DictionaryInfo info : dicts) { boolean hasFrom = from == null; boolean hasTo = to == null; - for (IndexInfo index : info.indexInfos) - { + for (IndexInfo index : info.indexInfos) { if (!hasFrom && index.shortName.toLowerCase(Locale.US).equals(from)) hasFrom = true; if (!hasTo && index.shortName.toLowerCase(Locale.US).equals(to)) hasTo = true; } - if (hasFrom && hasTo) - { - if (from != null) - { + if (hasFrom && hasTo) { + if (from != null) { int which_index = 0; - for (; which_index < info.indexInfos.size(); ++which_index) - { + for (; which_index < info.indexInfos.size(); ++which_index) { if (info.indexInfos.get(which_index).shortName.toLowerCase( - Locale.US).equals(from)) + Locale.US).equals(from)) break; } intent.putExtra(C.INDEX_SHORT_NAME, - info.indexInfos.get(which_index).shortName); + info.indexInfos.get(which_index).shortName); } intent.putExtra(C.DICT_FILE, application.getPath(info.uncompressedFilename) - .toString()); + .toString()); break; } } @@ -310,14 +302,12 @@ public class DictionaryActivity extends ActionBarActivity { * simple query Arguments follow from android standard (see * documentation) */ - if (intentAction != null && intentAction.equals(Intent.ACTION_SEARCH)) - { + if (intentAction != null && intentAction.equals(Intent.ACTION_SEARCH)) { String query = intent.getStringExtra(SearchManager.QUERY); if (query != null) getIntent().putExtra(C.SEARCH_TOKEN, query); } - if (intentAction != null && intentAction.equals(Intent.ACTION_SEND)) - { + if (intentAction != null && intentAction.equals(Intent.ACTION_SEND)) { String query = intent.getStringExtra(Intent.EXTRA_TEXT); if (query != null) getIntent().putExtra(C.SEARCH_TOKEN, query); @@ -337,23 +327,20 @@ public class DictionaryActivity extends ActionBarActivity { * fail (no default dictionary specified), show a toast and * abort. */ - if (intent.getStringExtra(C.DICT_FILE) == null) - { + if (intent.getStringExtra(C.DICT_FILE) == null) { String dictfile = prefs.getString(getString(R.string.defaultDicKey), null); if (dictfile != null) intent.putExtra(C.DICT_FILE, application.getPath(dictfile).toString()); } String dictFilename = intent.getStringExtra(C.DICT_FILE); - if (dictFilename == null && intent.getStringExtra(C.SEARCH_TOKEN) != null) - { + if (dictFilename == null && intent.getStringExtra(C.SEARCH_TOKEN) != null) { final List dics = application.getDictionariesOnDevice(null); final String search = intent.getStringExtra(C.SEARCH_TOKEN); String bestFname = null; String bestIndex = null; int bestMatchLen = 2; // ignore shorter matches AtomicBoolean dummy = new AtomicBoolean(); - for (int i = 0; dictFilename == null && i < dics.size(); ++i) - { + for (int i = 0; dictFilename == null && i < dics.size(); ++i) { try { Log.d(LOG, "Checking dictionary " + dics.get(i).uncompressedFilename); final File dictfile = application.getPath(dics.get(i).uncompressedFilename); @@ -361,8 +348,7 @@ public class DictionaryActivity extends ActionBarActivity { for (int j = 0; j < dic.indices.size(); ++j) { Index idx = dic.indices.get(j); Log.d(LOG, "Checking index " + idx.shortName); - if (idx.findExact(search) != null) - { + if (idx.findExact(search) != null) { Log.d(LOG, "Found exact match"); dictFilename = dictfile.toString(); intent.putExtra(C.INDEX_SHORT_NAME, idx.shortName); @@ -370,8 +356,7 @@ public class DictionaryActivity extends ActionBarActivity { } int matchLen = getMatchLen(search, idx.findInsertionPoint(search, dummy)); Log.d(LOG, "Found partial match length " + matchLen); - if (matchLen > bestMatchLen) - { + if (matchLen > bestMatchLen) { bestFname = dictfile.toString(); bestIndex = idx.shortName; bestMatchLen = matchLen; @@ -379,15 +364,13 @@ public class DictionaryActivity extends ActionBarActivity { } } catch (Exception e) {} } - if (dictFilename == null && bestFname != null) - { + if (dictFilename == null && bestFname != null) { dictFilename = bestFname; intent.putExtra(C.INDEX_SHORT_NAME, bestIndex); } } - if (dictFilename == null) - { + if (dictFilename == null) { Toast.makeText(this, getString(R.string.no_dict_file), Toast.LENGTH_LONG).show(); startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext())); finish(); @@ -421,7 +404,7 @@ public class DictionaryActivity extends ActionBarActivity { dictRaf = null; } Toast.makeText(this, getString(R.string.invalidDictionary, "", e.getMessage()), - Toast.LENGTH_LONG).show(); + Toast.LENGTH_LONG).show(); startActivity(DictionaryManagerActivity.getLaunchIntent(getApplicationContext())); finish(); return; @@ -439,27 +422,36 @@ public class DictionaryActivity extends ActionBarActivity { } Log.d(LOG, "Loading index " + indexIndex); index = dictionary.indices.get(indexIndex); + getListView().setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); getListView().setEmptyView(findViewById(android.R.id.empty)); + getListView().setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int row, long id) { + onListItemClick(getListView(), view, row, id); + } + }); + setListAdapter(new IndexAdapter(index)); + // Pre-load the Transliterator (will spawn its own thread) + TransliteratorManager.init(new TransliteratorManager.Callback() { + @Override + public void onTransliteratorReady() { + uiHandler.post(new Runnable() { + @Override + public void run() { + onSearchTextChange(searchView.getQuery().toString()); + } + }); + } + }, DictionaryApplication.threadBackground); + // Pre-load the collators. new Thread(new Runnable() { public void run() { - android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE); final long startMillis = System.currentTimeMillis(); try { - TransliteratorManager.init(new TransliteratorManager.Callback() { - @Override - public void onTransliteratorReady() { - uiHandler.post(new Runnable() { - @Override - public void run() { - onSearchTextChange(searchView.getQuery().toString()); - } - }); - } - }); - for (final Index index : dictionary.indices) { final String searchToken = index.sortedIndexEntries.get(0).token; final IndexEntry entry = index.findExact(searchToken); @@ -470,7 +462,7 @@ public class DictionaryActivity extends ActionBarActivity { indexPrepFinished = true; } catch (Exception e) { Log.w(LOG, - "Exception while prepping. This can happen if dictionary is closed while search is happening."); + "Exception while prepping. This can happen if dictionary is closed while search is happening."); } Log.d(LOG, "Prepping indices took:" + (System.currentTimeMillis() - startMillis)); } @@ -479,11 +471,11 @@ public class DictionaryActivity extends ActionBarActivity { String fontName = prefs.getString(getString(R.string.fontKey), "FreeSerif.otf.jpg"); if ("SYSTEM".equals(fontName)) { typeface = Typeface.DEFAULT; - } else if ("SERIF".equals(fontName)) { + } else if ("SERIF".equals(fontName)) { typeface = Typeface.SERIF; - } else if ("SANS_SERIF".equals(fontName)) { + } else if ("SANS_SERIF".equals(fontName)) { typeface = Typeface.SANS_SERIF; - } else if ("MONOSPACE".equals(fontName)) { + } else if ("MONOSPACE".equals(fontName)) { typeface = Typeface.MONOSPACE; } else { if ("FreeSerif.ttf.jpg".equals(fontName)) { @@ -494,7 +486,7 @@ public class DictionaryActivity extends ActionBarActivity { } catch (Exception e) { Log.w(LOG, "Exception trying to use typeface, using default.", e); Toast.makeText(this, getString(R.string.fontFailure, e.getLocalizedMessage()), - Toast.LENGTH_LONG).show(); + Toast.LENGTH_LONG).show(); } } if (typeface == null) { @@ -514,20 +506,14 @@ public class DictionaryActivity extends ActionBarActivity { // Cache some prefs. wordList = application.getWordListFile(); saveOnlyFirstSubentry = prefs.getBoolean(getString(R.string.saveOnlyFirstSubentryKey), - false); + false); clickOpensContextMenu = prefs.getBoolean(getString(R.string.clickOpensContextMenuKey), - false); + !getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)); Log.d(LOG, "wordList=" + wordList + ", saveOnlyFirstSubentry=" + saveOnlyFirstSubentry); onCreateSetupActionBarAndSearchView(); View floatSwapButton = findViewById(R.id.floatSwapButton); - floatSwapButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - onLanguageButtonClick(); - } - }); floatSwapButton.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { @@ -536,21 +522,6 @@ public class DictionaryActivity extends ActionBarActivity { } }); - final FloatingActionButton floatSearchButton = (FloatingActionButton)findViewById(R.id.floatSearchButton); - floatSearchButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - if (!searchView.hasFocus()) { - searchView.requestFocus(); - } - if (searchView.getQuery().toString().length() > 0) { - searchView.setQuery("", false); - } - showKeyboard(); - searchView.setIconified(false); - } - }); - // Set the search text from the intent, then the saved state. String text = getIntent().getStringExtra(C.SEARCH_TOKEN); if (savedInstanceState != null) { @@ -580,17 +551,11 @@ public class DictionaryActivity extends ActionBarActivity { final LinearLayout customSearchView = new LinearLayout(getSupportActionBar().getThemedContext()); final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); customSearchView.setLayoutParams(layoutParams); - listView.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int row, long id) { - onListItemClick(getListView(), view, row, id); - } - }); - languageButton = new ImageButton(customSearchView.getContext()); + languageButton.setId(R.id.languageButton); languageButton.setScaleType(ScaleType.FIT_CENTER); languageButton.setOnClickListener(new OnClickListener() { @Override @@ -603,6 +568,7 @@ public class DictionaryActivity extends ActionBarActivity { customSearchView.addView(languageButton, lpb); searchView = new SearchView(getSupportActionBar().getThemedContext()); + searchView.setId(R.id.searchView); // Get rid of search icon, it takes up too much space. // There is still text saying "search" in the search field. @@ -613,11 +579,11 @@ public class DictionaryActivity extends ActionBarActivity { searchView.setSubmitButtonEnabled(false); searchView.setInputType(InputType.TYPE_CLASS_TEXT); searchView.setImeOptions( - EditorInfo.IME_ACTION_DONE | - EditorInfo.IME_FLAG_NO_EXTRACT_UI | - // EditorInfo.IME_FLAG_NO_FULLSCREEN | // Requires API - // 11 - EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + EditorInfo.IME_ACTION_DONE | + EditorInfo.IME_FLAG_NO_EXTRACT_UI | + // EditorInfo.IME_FLAG_NO_FULLSCREEN | // Requires API + // 11 + EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS); onQueryTextListener = new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { @@ -642,9 +608,13 @@ public class DictionaryActivity extends ActionBarActivity { actionBar.setCustomView(customSearchView); actionBar.setDisplayShowCustomEnabled(true); - // Avoid wasting space on large left inset + // Avoid wasting space on large left inset Toolbar tb = (Toolbar)customSearchView.getParent(); tb.setContentInsetsRelative(0, 0); + + getListView().setNextFocusLeftId(R.id.searchView); + findViewById(R.id.floatSwapButton).setNextFocusRightId(R.id.languageButton); + languageButton.setNextFocusLeftId(R.id.floatSwapButton); } @Override @@ -678,7 +648,7 @@ public class DictionaryActivity extends ActionBarActivity { } private static void setDictionaryPrefs(final Context context, final File dictFile, - final String indexShortName, final String searchToken) { + final String indexShortName, final String searchToken) { final SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences( context).edit(); prefs.putString(C.DICT_FILE, dictFile.getPath()); @@ -749,10 +719,9 @@ public class DictionaryActivity extends ActionBarActivity { } void updateLangButton() { - final LanguageResources languageResources = - DictionaryApplication.isoCodeToResources.get(index.shortName); - if (languageResources != null && languageResources.flagId != 0) { - languageButton.setImageResource(languageResources.flagId); + final int flagId = IsoUtils.INSTANCE.getFlagIdForIsoCode(index.shortName); + if (flagId != 0) { + languageButton.setImageResource(flagId); } else { if (indexIndex % 2 == 0) { languageButton.setImageResource(android.R.drawable.ic_media_next); @@ -771,17 +740,28 @@ public class DictionaryActivity extends ActionBarActivity { final Locale locale = new Locale(dictionary.indices.get(i).sortLanguage.getIsoCode()); Log.d(LOG, "Setting TTS locale to: " + locale); try { - final int ttsResult = textToSpeech.setLanguage(locale); - if (ttsResult != TextToSpeech.LANG_AVAILABLE && - ttsResult != TextToSpeech.LANG_COUNTRY_AVAILABLE) { - Log.e(LOG, "TTS not available in this language: ttsResult=" + ttsResult); - } + final int ttsResult = textToSpeech.setLanguage(locale); + if (ttsResult != TextToSpeech.LANG_AVAILABLE && + ttsResult != TextToSpeech.LANG_COUNTRY_AVAILABLE) { + Log.e(LOG, "TTS not available in this language: ttsResult=" + ttsResult); + } } catch (Exception e) { Toast.makeText(this, getString(R.string.TTSbroken), Toast.LENGTH_LONG).show(); } } - void onLanguageButtonClick() { + public void onSearchButtonClick(View dummy) { + if (!searchView.hasFocus()) { + searchView.requestFocus(); + } + if (searchView.getQuery().toString().length() > 0) { + searchView.setQuery("", false); + } + showKeyboard(); + searchView.setIconified(false); + } + + public void onLanguageButtonClick(View dummy) { if (dictionary.indices.size() == 1) { // No need to work to switch indices. return; @@ -791,7 +771,7 @@ public class DictionaryActivity extends ActionBarActivity { currentSearchOperation = null; } setIndexAndSearchText((indexIndex + 1) % dictionary.indices.size(), - searchView.getQuery().toString(), false); + searchView.getQuery().toString(), false); } void onLanguageButtonLongClick(final Context context) { @@ -806,7 +786,7 @@ public class DictionaryActivity extends ActionBarActivity { final String name = getString(R.string.dictionaryManager); button.setText(name); final IntentLauncher intentLauncher = new IntentLauncher(listView.getContext(), - DictionaryManagerActivity.getLaunchIntent(getApplicationContext())) { + DictionaryManagerActivity.getLaunchIntent(getApplicationContext())) { @Override protected void onGo() { dialog.dismiss(); @@ -816,6 +796,7 @@ public class DictionaryActivity extends ActionBarActivity { button.setOnClickListener(intentLauncher); listView.addHeaderView(button); + listView.setItemsCanFocus(true); listView.setAdapter(new BaseAdapter() { @Override public View getView(int position, View convertView, ViewGroup parent) { @@ -825,12 +806,12 @@ public class DictionaryActivity extends ActionBarActivity { for (int i = 0; i < dictionaryInfo.indexInfos.size(); ++i) { final IndexInfo indexInfo = dictionaryInfo.indexInfos.get(i); - final View button = application.createButton(parent.getContext(), - dictionaryInfo, indexInfo); + final View button = IsoUtils.INSTANCE.createButton(parent.getContext(), + dictionaryInfo, indexInfo, application.languageButtonPixels); final IntentLauncher intentLauncher = new IntentLauncher(parent.getContext(), getLaunchIntent(getApplicationContext(), - application.getPath(dictionaryInfo.uncompressedFilename), - indexInfo.shortName, searchView.getQuery().toString())) { + application.getPath(dictionaryInfo.uncompressedFilename), + indexInfo.shortName, searchView.getQuery().toString())) { @Override protected void onGo() { dialog.dismiss(); @@ -839,7 +820,7 @@ public class DictionaryActivity extends ActionBarActivity { }; button.setOnClickListener(intentLauncher); if (i == indexIndex && dictFile != null && - dictFile.getName().equals(dictionaryInfo.uncompressedFilename)) { + dictFile.getName().equals(dictionaryInfo.uncompressedFilename)) { button.setPressed(true); } result.addView(button); @@ -847,10 +828,10 @@ public class DictionaryActivity extends ActionBarActivity { final TextView nameView = new TextView(parent.getContext()); final String name = application - .getDictionaryName(dictionaryInfo.uncompressedFilename); + .getDictionaryName(dictionaryInfo.uncompressedFilename); nameView.setText(name); final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); layoutParams.width = 0; layoutParams.weight = 1.0f; nameView.setLayoutParams(layoutParams); @@ -923,7 +904,7 @@ public class DictionaryActivity extends ActionBarActivity { .getBoolean(getString(R.string.showPrevNextButtonsKey), true)) { // Next word. nextWordMenuItem = menu.add(getString(R.string.nextWord)) - .setIcon(R.drawable.arrow_down_float); + .setIcon(R.drawable.arrow_down_float); MenuItemCompat.setShowAsAction(nextWordMenuItem, MenuItem.SHOW_AS_ACTION_IF_ROOM); nextWordMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override @@ -935,7 +916,7 @@ public class DictionaryActivity extends ActionBarActivity { // Previous word. previousWordMenuItem = menu.add(getString(R.string.previousWord)) - .setIcon(R.drawable.arrow_up_float); + .setIcon(R.drawable.arrow_up_float); MenuItemCompat.setShowAsAction(previousWordMenuItem, MenuItem.SHOW_AS_ACTION_IF_ROOM); previousWordMenuItem.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override @@ -988,27 +969,27 @@ public class DictionaryActivity extends ActionBarActivity { if (dictionaryInfo != null) { builder.append(dictionaryInfo.dictInfo).append("\n\n"); builder.append(getString(R.string.dictionaryPath, dictFile.getPath())) - .append("\n"); + .append("\n"); builder.append( - getString(R.string.dictionarySize, dictionaryInfo.uncompressedBytes)) - .append("\n"); + getString(R.string.dictionarySize, dictionaryInfo.uncompressedBytes)) + .append("\n"); builder.append( - getString(R.string.dictionaryCreationTime, - dictionaryInfo.creationMillis)).append("\n"); + getString(R.string.dictionaryCreationTime, + dictionaryInfo.creationMillis)).append("\n"); for (final IndexInfo indexInfo : dictionaryInfo.indexInfos) { builder.append("\n"); builder.append(getString(R.string.indexName, indexInfo.shortName)) - .append("\n"); + .append("\n"); builder.append( - getString(R.string.mainTokenCount, indexInfo.mainTokenCount)) - .append("\n"); + getString(R.string.mainTokenCount, indexInfo.mainTokenCount)) + .append("\n"); } builder.append("\n"); builder.append(getString(R.string.sources)).append("\n"); for (final EntrySource source : dictionary.sources) { builder.append( - getString(R.string.sourceInfo, source.getName(), - source.getNumEntries())).append("\n"); + getString(R.string.sourceInfo, source.getName(), + source.getNumEntries())).append("\n"); } } textView.setText(builder.toString()); @@ -1032,18 +1013,31 @@ public class DictionaryActivity extends ActionBarActivity { @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) menuInfo; + final AdapterContextMenuInfo adapterContextMenuInfo = (AdapterContextMenuInfo) menuInfo; final RowBase row = (RowBase) getListAdapter().getItem(adapterContextMenuInfo.position); + if (clickOpensContextMenu && (row instanceof HtmlEntry.Row || + (row instanceof TokenRow && ((TokenRow)row).getIndexEntry().htmlEntries.size() > 0))) { + final List html = row instanceof TokenRow ? ((TokenRow)row).getIndexEntry().htmlEntries : Collections.singletonList(((HtmlEntry.Row)row).getEntry()); + final String highlight = row instanceof HtmlEntry.Row ? ((HtmlEntry.Row)row).getTokenRow(true).getToken() : null; + final MenuItem open = menu.add("Open"); + open.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + showHtml(html, highlight); + return false; + } + }); + } + final android.view.MenuItem addToWordlist = menu.add(getString(R.string.addToWordList, wordList.getName())); addToWordlist - .setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(android.view.MenuItem item) { - onAppendToWordList(row); - return false; - } - }); + .setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { + public boolean onMenuItemClick(android.view.MenuItem item) { + onAppendToWordList(row); + return false; + } + }); final android.view.MenuItem share = menu.add("Share"); share.setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { @@ -1051,9 +1045,9 @@ public class DictionaryActivity extends ActionBarActivity { Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND); shareIntent.setType("text/plain"); shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, row.getTokenRow(true) - .getToken()); + .getToken()); shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, - row.getRawText(saveOnlyFirstSubentry)); + row.getRawText(saveOnlyFirstSubentry)); startActivity(shareIntent); return false; } @@ -1070,15 +1064,15 @@ public class DictionaryActivity extends ActionBarActivity { if (selectedSpannableText != null) { final String selectedText = selectedSpannableText; final android.view.MenuItem searchForSelection = menu.add(getString( - R.string.searchForSelection, - selectedSpannableText)); + R.string.searchForSelection, + selectedSpannableText)); searchForSelection - .setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { - public boolean onMenuItemClick(android.view.MenuItem item) { - jumpToTextFromHyperLink(selectedText, selectedSpannableIndex); - return false; - } - }); + .setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { + public boolean onMenuItemClick(android.view.MenuItem item) { + jumpToTextFromHyperLink(selectedText, selectedSpannableIndex); + return false; + } + }); // Rats, this won't be shown: //searchForSelection.setIcon(R.drawable.abs__ic_search); } @@ -1091,7 +1085,38 @@ public class DictionaryActivity extends ActionBarActivity { @Override public boolean onMenuItemClick(android.view.MenuItem item) { textToSpeech.speak(textToSpeak, TextToSpeech.QUEUE_FLUSH, - new HashMap()); + new HashMap()); + return false; + } + }); + } + if (row instanceof PairEntry.Row && ttsReady) { + final List pairs = ((PairEntry.Row)row).getEntry().pairs; + final MenuItem speakLeft = menu.add(R.string.speak_left); + speakLeft.setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(android.view.MenuItem item) { + int idx = index.swapPairEntries ? 1 : 0; + updateTTSLanguage(idx); + String text = ""; + for (Pair p : pairs) text += p.get(idx); + text = text.replaceAll("\\{[^{}]*\\}", "").replace("{", "").replace("}", ""); + textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, + new HashMap()); + return false; + } + }); + final MenuItem speakRight = menu.add(R.string.speak_right); + speakRight.setOnMenuItemClickListener(new android.view.MenuItem.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(android.view.MenuItem item) { + int idx = index.swapPairEntries ? 0 : 1; + updateTTSLanguage(idx); + String text = ""; + for (Pair p : pairs) text += p.get(idx); + text = text.replaceAll("\\{[^{}]*\\}", "").replace("{", "").replace("}", ""); + textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, + new HashMap()); return false; } }); @@ -1099,7 +1124,7 @@ public class DictionaryActivity extends ActionBarActivity { } private void jumpToTextFromHyperLink( - final String selectedText, final int defaultIndexToUse) { + final String selectedText, final int defaultIndexToUse) { int indexToUse = -1; int numFound = 0; for (int i = 0; i < dictionary.indices.size(); ++i) { @@ -1109,7 +1134,7 @@ public class DictionaryActivity extends ActionBarActivity { final IndexEntry indexEntry = index.findExact(selectedText); if (indexEntry != null) { final TokenRow tokenRow = index.rows.get(indexEntry.startRow) - .getTokenRow(false); + .getTokenRow(false); if (tokenRow != null && tokenRow.hasMainEntry) { indexToUse = i; ++numFound; @@ -1148,10 +1173,15 @@ public class DictionaryActivity extends ActionBarActivity { // searchView.selectAll(); } - protected void onListItemClick(ListView l, View v, int row, long id) { + protected void onListItemClick(ListView l, View v, int rowIdx, long id) { defocusSearchText(); if (clickOpensContextMenu && dictRaf != null) { openContextMenu(v); + } else { + final RowBase row = (RowBase)getListAdapter().getItem(rowIdx); + if (!(row instanceof PairEntry.Row)) { + v.performClick(); + } } } @@ -1174,8 +1204,8 @@ public class DictionaryActivity extends ActionBarActivity { } catch (Exception e) { Log.e(LOG, "Unable to append to " + wordList.getAbsolutePath(), e); Toast.makeText(this, - getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()), - Toast.LENGTH_LONG).show(); + getString(R.string.failedAddingToWordList, wordList.getAbsolutePath()), + Toast.LENGTH_LONG).show(); } return; } @@ -1213,7 +1243,7 @@ public class DictionaryActivity extends ActionBarActivity { View focus = getCurrentFocus(); if (focus != null) { inputManager.hideSoftInputFromWindow(focus.getWindowToken(), - InputMethodManager.HIDE_NOT_ALWAYS); + InputMethodManager.HIDE_NOT_ALWAYS); } return true; } @@ -1257,7 +1287,7 @@ public class DictionaryActivity extends ActionBarActivity { } private void setSearchText(final String text, final boolean triggerSearch) { - setSearchText(text, triggerSearch, true); + setSearchText(text, triggerSearch, true); } // private long cursorDelayMillis = 100; @@ -1364,12 +1394,12 @@ public class DictionaryActivity extends ActionBarActivity { } else { searchTokens = Arrays.asList(searchTokenArray); multiWordSearchResult = index.multiWordSearch(searchText, searchTokens, - interrupted); + interrupted); } Log.d(LOG, - "searchText=" + searchText + ", searchDuration=" - + (System.currentTimeMillis() - searchStartMillis) - + ", interrupted=" + interrupted.get()); + "searchText=" + searchText + ", searchDuration=" + + (System.currentTimeMillis() - searchStartMillis) + + ", interrupted=" + interrupted.get()); if (!interrupted.get()) { uiHandler.post(new Runnable() { @Override @@ -1395,11 +1425,21 @@ public class DictionaryActivity extends ActionBarActivity { // IndexAdapter // -------------------------------------------------------------------------- + private void showHtml(final List htmlEntries, final String htmlTextToHighlight) { + String html = HtmlEntry.htmlBody(htmlEntries, index.shortName); + // Log.d(LOG, "html=" + html); + startActivityForResult( + HtmlDisplayActivity.getHtmlIntent(getApplicationContext(), String.format( + "%s", html), + htmlTextToHighlight, false), + 0); + } + static ViewGroup.LayoutParams WEIGHT_1 = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f); + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f); static ViewGroup.LayoutParams WEIGHT_0 = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0f); + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0f); final class IndexAdapter extends BaseAdapter { @@ -1433,7 +1473,12 @@ public class DictionaryActivity extends ActionBarActivity { private void getMetrics() { // Get the screen's density scale - final float scale = getResources().getDisplayMetrics().density; + // The previous method getResources().getDisplayMetrics() + // used to occasionally trigger a null pointer exception, + // so try this instead. + DisplayMetrics dm = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(dm); + final float scale = dm.density; // Convert the dps to pixels, based on density scale mPaddingDefault = (int) (PADDING_DEFAULT_DP * scale + 0.5f); mPaddingLarge = (int) (PADDING_LARGE_DP * scale + 0.5f); @@ -1476,7 +1521,7 @@ public class DictionaryActivity extends ActionBarActivity { } private TableLayout getView(final int position, PairEntry.Row row, ViewGroup parent, - final TableLayout result) { + final TableLayout result) { final PairEntry entry = row.getEntry(); final int rowCount = entry.pairs.size(); @@ -1489,8 +1534,7 @@ public class DictionaryActivity extends ActionBarActivity { final TextView col1 = new TextView(tableRow.getContext()); final TextView col2 = new TextView(tableRow.getContext()); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) - { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { col1.setTextIsSelectable(true); col2.setTextIsSelectable(true); } @@ -1525,13 +1569,13 @@ public class DictionaryActivity extends ActionBarActivity { // Bold the token instances in col1. final Set toBold = toHighlight != null ? this.toHighlight : Collections - .singleton(row.getTokenRow(true).getToken()); + .singleton(row.getTokenRow(true).getToken()); final Spannable col1Spannable = (Spannable) col1.getText(); for (final String token : toBold) { int startPos = 0; while ((startPos = col1Text.indexOf(token, startPos)) != -1) { col1Spannable.setSpan(new StyleSpan(Typeface.BOLD), startPos, startPos - + token.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + + token.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); startPos += token.length(); } } @@ -1560,7 +1604,7 @@ public class DictionaryActivity extends ActionBarActivity { // 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.setFocusable(false); result.setLongClickable(true); // result.setBackgroundResource(android.R.drawable.menuitem_background); @@ -1583,7 +1627,7 @@ public class DictionaryActivity extends ActionBarActivity { final TableRow tableRow = new TableRow(result.getContext()); tableRow.setBackgroundResource(hasMainEntry ? theme.tokenRowMainBg - : theme.tokenRowOtherBg); + : theme.tokenRowOtherBg); if (isTokenRow) { tableRow.setPadding(mPaddingDefault, mPaddingDefault, mPaddingDefault, 0); } else { @@ -1627,32 +1671,33 @@ public class DictionaryActivity extends ActionBarActivity { textView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - String html = HtmlEntry.htmlBody(htmlEntries, index.shortName); - // Log.d(LOG, "html=" + html); - startActivityForResult( - HtmlDisplayActivity.getHtmlIntent(getApplicationContext(), String.format( - "%s", html), - htmlTextToHighlight, false), - 0); + showHtml(htmlEntries, htmlTextToHighlight); + } + }); + result.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + textView.performClick(); } }); } + result.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); return result; } private TableLayout getView(TokenRow row, ViewGroup parent, final TableLayout result) { final IndexEntry indexEntry = row.getIndexEntry(); return getPossibleLinkToHtmlEntryView(true, indexEntry.token, row.hasMainEntry, - indexEntry.htmlEntries, null, parent, result); + indexEntry.htmlEntries, null, parent, result); } private TableLayout getView(HtmlEntry.Row row, ViewGroup parent, final TableLayout result) { final HtmlEntry htmlEntry = row.getEntry(); final TokenRow tokenRow = row.getTokenRow(true); return getPossibleLinkToHtmlEntryView(false, - getString(R.string.seeAlso, htmlEntry.title, htmlEntry.entrySource.getName()), - false, Collections.singletonList(htmlEntry), tokenRow.getToken(), parent, - result); + getString(R.string.seeAlso, htmlEntry.title, htmlEntry.entrySource.getName()), + false, Collections.singletonList(htmlEntry), tokenRow.getToken(), parent, + result); } } @@ -1660,15 +1705,15 @@ public class DictionaryActivity extends ActionBarActivity { static final Pattern CHAR_DASH = Pattern.compile("['\\p{L}\\p{M}\\p{N}]+"); private void createTokenLinkSpans(final TextView textView, final Spannable spannable, - final String text) { + final String text) { // Saw from the source code that LinkMovementMethod sets the selection! // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.1_r1/android/text/method/LinkMovementMethod.java#LinkMovementMethod textView.setMovementMethod(LinkMovementMethod.getInstance()); final Matcher matcher = CHAR_DASH.matcher(text); while (matcher.find()) { spannable.setSpan(new NonLinkClickableSpan(textColorFg), matcher.start(), - matcher.end(), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + matcher.end(), + Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } } @@ -1704,10 +1749,10 @@ public class DictionaryActivity extends ActionBarActivity { } final TextViewLongClickListener textViewLongClickListenerIndex0 = new TextViewLongClickListener( - 0); + 0); final TextViewLongClickListener textViewLongClickListenerIndex1 = new TextViewLongClickListener( - 1); + 1); // -------------------------------------------------------------------------- // SearchText