From: Thad Hughes Date: Sat, 19 Feb 2011 19:50:27 +0000 (-0800) Subject: go X-Git-Url: http://gitweb.fperrin.net/?p=Dictionary.git;a=commitdiff_plain;h=319caebfa9fa020c44b61b7014cc8570bc14a2fa go --- diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 644efd2..091a0b0 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,7 +1,10 @@ diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index a9b4a7a..dd4f356 100755 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -17,19 +17,9 @@ Wenn QuickDic dir gefällt, würde ich gern von dir hören. Bitte schicke Bemerkungen, Aufforderungen, oder Programmfehler an: Wörterbuch Info: Kein Wörterbuch geöffnet. - - %d von %d Bytes heruntergeladen... + %1$d von %2$d Bytes heruntergeladen... Herunterladen fertig, %d Bytes heruntergeladen. "Fehler während des Herunterladens: \n%s" diff --git a/res/values/strings.xml b/res/values/strings.xml index 4f69aab..03d9cc5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -38,7 +38,7 @@ Dictionary file Word list file File not found: \'%s\' - Invalid dictionary: file=%s, error=%s + Invalid dictionary: file=%1$s, error=%2$s Entries: %d Tokens: %d Rows: %d @@ -62,7 +62,7 @@ http://sites.google.com/site/quickdic/home - Downloading, %d of %d bytes. + Downloading, %1$d of %2$d bytes. Download finished, %d bytes downloaded. "Error downloading file: \n%s" diff --git a/src/com/hughes/android/dictionary/DictionaryActivity.java b/src/com/hughes/android/dictionary/DictionaryActivity.java index 5e251b7..10b3cf6 100644 --- a/src/com/hughes/android/dictionary/DictionaryActivity.java +++ b/src/com/hughes/android/dictionary/DictionaryActivity.java @@ -9,6 +9,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; import android.app.ListActivity; @@ -50,8 +51,10 @@ import android.widget.Toast; import com.hughes.android.dictionary.engine.Dictionary; import com.hughes.android.dictionary.engine.Index; import com.hughes.android.dictionary.engine.PairEntry; +import com.hughes.android.dictionary.engine.PairEntry.Pair; import com.hughes.android.dictionary.engine.RowBase; import com.hughes.android.dictionary.engine.TokenRow; +import com.hughes.android.dictionary.engine.TransliteratorManager; import com.hughes.android.util.PersistentObjectCache; public class DictionaryActivity extends ListActivity { @@ -68,7 +71,12 @@ public class DictionaryActivity extends ListActivity { // package for test. final Handler uiHandler = new Handler(); - private final Executor searchExecutor = Executors.newSingleThreadExecutor(); + private final Executor searchExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "searchExecutor"); + } + }); private SearchOperation currentSearchOperation = null; EditText searchText; @@ -116,6 +124,7 @@ public class DictionaryActivity extends ListActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Log.d(LOG, "onCreate:" + this); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -143,14 +152,32 @@ public class DictionaryActivity extends ListActivity { return; } + indexIndex = prefs.getInt(C.INDEX_INDEX, 0) % dictionary.indices.size(); + Log.d(LOG, "Loading index."); + index = dictionary.indices.get(indexIndex); + setListAdapter(new IndexAdapter(index)); + // Pre-load the collators. searchExecutor.execute(new Runnable() { public void run() { final long startMillis = System.currentTimeMillis(); - Log.d(LOG, "Constructing index for lang=" + index.sortLanguage.getSymbol()); + + TransliteratorManager.init(new TransliteratorManager.Callback() { + @Override + public void onTransliteratorReady() { + uiHandler.post(new Runnable() { + @Override + public void run() { + onSearchTextChange(searchText.getText().toString()); + } + }); + } + }); + for (final Index index : dictionary.indices) { Log.d(LOG, "Starting collator load for lang=" + index.sortLanguage.getSymbol()); - final com.ibm.icu.text.Collator c = index.sortLanguage.getCollator(); + + final com.ibm.icu.text.Collator c = index.sortLanguage.getCollator(); if (c.compare("pre-print", "preppy") >= 0) { Log.e(LOG, c.getClass() + " is buggy, lookups may not work properly."); @@ -161,10 +188,7 @@ public class DictionaryActivity extends ListActivity { } }); - indexIndex = prefs.getInt(C.INDEX_INDEX, 0) % dictionary.indices.size(); - index = dictionary.indices.get(indexIndex); - setListAdapter(new IndexAdapter(index)); - + setContentView(R.layout.dictionary_activity); searchText = (EditText) findViewById(R.id.SearchText); langButton = (Button) findViewById(R.id.LangButton); @@ -212,6 +236,7 @@ public class DictionaryActivity extends ListActivity { if (!searchText.isFocused()) { // TODO: don't do this if multi words are entered. final RowBase row = (RowBase) getListAdapter().getItem(position); + Log.d(LOG, "onItemSelected: " + row.index()); final TokenRow tokenRow = row.getTokenRow(true); searchText.setText(tokenRow.getToken()); } @@ -312,7 +337,7 @@ public class DictionaryActivity extends ListActivity { searchText.removeTextChangedListener(searchTextWatcher); searchText.setText(dest.token); jumpToRow(index.sortedIndexEntries.get(destIndexEntry).startRow); - searchText.removeTextChangedListener(searchTextWatcher); + searchText.addTextChangedListener(searchTextWatcher); } // -------------------------------------------------------------------------- @@ -454,7 +479,18 @@ public class DictionaryActivity extends ListActivity { final Index.IndexEntry searchResult = searchOperation.searchResult; Log.d(LOG, "searchFinished: " + searchOperation + ", searchResult=" + searchResult); - jumpToRow(searchResult.startRow); + currentSearchOperation = null; + + uiHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (currentSearchOperation == null) { + jumpToRow(searchResult.startRow); + } else { + Log.d(LOG, "More coming, waiting for currentSearchOperation."); + } + } + }, 50); // if (!searchResult.success) { // if (vibrator != null) { @@ -464,6 +500,7 @@ public class DictionaryActivity extends ListActivity { // searchText.setSelection(searchResult.longestPrefixString.length()); // return; // } + } private final void jumpToRow(final int row) { @@ -551,7 +588,7 @@ public class DictionaryActivity extends ListActivity { private View getView(PairEntry.Row row, ViewGroup parent) { final TableLayout result = new TableLayout(parent.getContext()); final PairEntry entry = row.getEntry(); - final int rowCount = entry.pairs.length; + final int rowCount = entry.pairs.size(); for (int r = 0; r < rowCount; ++r) { final TableRow tableRow = new TableRow(result.getContext()); @@ -577,7 +614,8 @@ public class DictionaryActivity extends ListActivity { column2.setWidth(1); // TODO: color words by gender - final String col1Text = index.swapPairEntries ? entry.pairs[r].lang2 : entry.pairs[r].lang1; + final Pair pair = entry.pairs.get(r); + final String col1Text = index.swapPairEntries ? pair.lang2 : pair.lang1; column1.setText(col1Text, TextView.BufferType.SPANNABLE); final Spannable col1Spannable = (Spannable) column1.getText(); @@ -589,7 +627,7 @@ public class DictionaryActivity extends ListActivity { startPos += token.length(); } - final String col2Text = index.swapPairEntries ? entry.pairs[r].lang1 : entry.pairs[r].lang2; + final String col2Text = index.swapPairEntries ? pair.lang1 : pair.lang2; column2.setText(col2Text, TextView.BufferType.NORMAL); result.addView(tableRow); diff --git a/src/com/hughes/android/dictionary/engine/EntrySource.java b/src/com/hughes/android/dictionary/engine/EntrySource.java index 391e8ce..bded4d5 100644 --- a/src/com/hughes/android/dictionary/engine/EntrySource.java +++ b/src/com/hughes/android/dictionary/engine/EntrySource.java @@ -12,10 +12,12 @@ public class EntrySource extends IndexedObject implements Serializable { private static final long serialVersionUID = -1323165134846120269L; final String name; + final int pairEntryStart; - public EntrySource(final int index, final String name) { + public EntrySource(final int index, final String name, final int pairEntryStart) { super(index); this.name = name; + this.pairEntryStart = pairEntryStart; } @Override @@ -30,12 +32,14 @@ public class EntrySource extends IndexedObject implements Serializable { public EntrySource read(RandomAccessFile raf, int readIndex) throws IOException { final String name = raf.readUTF(); - return new EntrySource(readIndex, name); + final int pairEntryStart = raf.readInt(); + return new EntrySource(readIndex, name, pairEntryStart); } @Override public void write(RandomAccessFile raf, EntrySource t) throws IOException { raf.writeUTF(t.name); + raf.writeInt(t.pairEntryStart); } }; diff --git a/src/com/hughes/android/dictionary/engine/EntryTypeName.java b/src/com/hughes/android/dictionary/engine/EntryTypeName.java index c65db05..409b636 100644 --- a/src/com/hughes/android/dictionary/engine/EntryTypeName.java +++ b/src/com/hughes/android/dictionary/engine/EntryTypeName.java @@ -16,6 +16,7 @@ public enum EntryTypeName { MULTIROW_TAIL_ONE_WORD(0), WIKTIONARY_TITLE_MULTI_WORD(0), + WIKTIONARY_PRONUNCIATION(0), WIKTIONARY_MEANING_MULTI_WORD(0), WIKTIONARY_FORM_OF(0), WIKTIONARY_EXAMPLE_HEADWORDS(0), diff --git a/src/com/hughes/android/dictionary/engine/Index.java b/src/com/hughes/android/dictionary/engine/Index.java index d0d2404..f05c0dc 100644 --- a/src/com/hughes/android/dictionary/engine/Index.java +++ b/src/com/hughes/android/dictionary/engine/Index.java @@ -33,7 +33,7 @@ public final class Index implements RAFSerializable { final String normalizerRules; // Built from the two above. - final Transliterator normalizer; + private Transliterator normalizer; // persisted public final List sortedIndexEntries; @@ -57,7 +57,14 @@ public final class Index implements RAFSerializable { sortedIndexEntries = new ArrayList(); rows = new ArrayList(); - normalizer = Transliterator.createFromRules("", normalizerRules, Transliterator.FORWARD); + normalizer = null; + } + + public synchronized Transliterator normalizer() { + if (normalizer == null) { + normalizer = Transliterator.createFromRules("", normalizerRules, Transliterator.FORWARD); + } + return normalizer; } public Index(final Dictionary dict, final RandomAccessFile raf) throws IOException { @@ -73,8 +80,6 @@ public final class Index implements RAFSerializable { } sortedIndexEntries = CachingList.create(RAFList.create(raf, IndexEntry.SERIALIZER, raf.getFilePointer()), CACHE_SIZE); rows = CachingList.create(UniformRAFList.create(raf, new RowBase.Serializer(this), raf.getFilePointer()), CACHE_SIZE); - - normalizer = Transliterator.createFromRules("", normalizerRules, Transliterator.FORWARD); } @Override @@ -96,10 +101,10 @@ public final class Index implements RAFSerializable { public static final class IndexEntry implements RAFSerializable { public final String token; + private final String normalizedToken; public final int startRow; public final int numRows; - private String normalizedToken; static final RAFSerializer SERIALIZER = new RAFSerializer () { @Override @@ -111,10 +116,11 @@ public final class Index implements RAFSerializable { t.write(raf); }}; - public IndexEntry(final String token, final int startRow, final int numRows) { + public IndexEntry(final String token, final String normalizedToken, final int startRow, final int numRows) { assert token.equals(token.trim()); assert token.length() > 0; this.token = token; + this.normalizedToken = normalizedToken; this.startRow = startRow; this.numRows = numRows; } @@ -123,28 +129,35 @@ public final class Index implements RAFSerializable { token = raf.readUTF(); startRow = raf.readInt(); numRows = raf.readInt(); + final boolean hasNormalizedForm = raf.readBoolean(); + normalizedToken = hasNormalizedForm ? raf.readUTF() : token; } public void write(RandomAccessFile raf) throws IOException { raf.writeUTF(token); raf.writeInt(startRow); raf.writeInt(numRows); + final boolean hasNormalizedForm = !token.equals(normalizedToken); + raf.writeBoolean(hasNormalizedForm); + if (hasNormalizedForm) { + raf.writeUTF(normalizedToken); + } } public String toString() { return String.format("%s@%d(%d)", token, startRow, numRows); } - public synchronized String normalizedToken(final Transliterator normalizer) { - if (normalizedToken == null) { - normalizedToken = normalizer.transform(token); - } + public String normalizedToken() { return normalizedToken; } } public IndexEntry findInsertionPoint(String token, final AtomicBoolean interrupted) { - token = normalizer.transliterate(token); + final Transliterator normalizer = normalizer(); + if (TransliteratorManager.init(null)) { + token = normalizer.transliterate(token); + } int start = 0; int end = sortedIndexEntries.size(); @@ -157,22 +170,22 @@ public final class Index implements RAFSerializable { } final IndexEntry midEntry = sortedIndexEntries.get(mid); - final int comp = sortCollator.compare(token, midEntry.normalizedToken(normalizer)); + final int comp = sortCollator.compare(token, midEntry.normalizedToken()); if (comp == 0) { final int result = windBackCase(token, mid, interrupted); return sortedIndexEntries.get(result); } else if (comp < 0) { - System.out.println("Upper bound: " + midEntry + ", norm=" + midEntry.normalizedToken(normalizer) + ", mid=" + mid); + //System.out.println("Upper bound: " + midEntry + ", norm=" + midEntry.normalizedToken() + ", mid=" + mid); end = mid; } else { - System.out.println("Lower bound: " + midEntry + ", norm=" + midEntry.normalizedToken(normalizer) + ", mid=" + mid); + //System.out.println("Lower bound: " + midEntry + ", norm=" + midEntry.normalizedToken() + ", mid=" + mid); start = mid + 1; } } // If we search for a substring of a string that's in there, return that. int result = Math.min(start, sortedIndexEntries.size() - 1); - result = windBackCase(sortedIndexEntries.get(result).normalizedToken(normalizer), result, interrupted); + result = windBackCase(sortedIndexEntries.get(result).normalizedToken(), result, interrupted); return sortedIndexEntries.get(result); } @@ -222,7 +235,7 @@ public final class Index implements RAFSerializable { // } private final int windBackCase(final String token, int result, final AtomicBoolean interrupted) { - while (result > 0 && sortedIndexEntries.get(result - 1).normalizedToken(normalizer).equals(token)) { + while (result > 0 && sortedIndexEntries.get(result - 1).normalizedToken().equals(token)) { --result; if (interrupted.get()) { return result; diff --git a/src/com/hughes/android/dictionary/engine/Language.java b/src/com/hughes/android/dictionary/engine/Language.java index 42ad7b6..cc1c332 100755 --- a/src/com/hughes/android/dictionary/engine/Language.java +++ b/src/com/hughes/android/dictionary/engine/Language.java @@ -13,13 +13,11 @@ public class Language { final String symbol; final Locale locale; - final Collator collator; + private Collator collator; public Language(final Locale locale) { this.symbol = locale.getLanguage(); this.locale = locale; - this.collator = Collator.getInstance(locale); - this.collator.setStrength(Collator.IDENTICAL); symbolToLangauge.put(symbol.toLowerCase(), this); } @@ -33,7 +31,11 @@ public class Language { return symbol; } - public Collator getCollator() { + public synchronized Collator getCollator() { + if (collator == null) { + this.collator = Collator.getInstance(locale); + this.collator.setStrength(Collator.IDENTICAL); + } return collator; } @@ -53,18 +55,14 @@ public class Language { } }; - static { - for (final String lang : Locale.getISOLanguages()) { - if (lookup(lang) == null) { - new Language(new Locale(lang)); - } - } - } - // ---------------------------------------------------------------- - public static Language lookup(final String symbol) { - return symbolToLangauge.get(symbol.toLowerCase()); + public static synchronized Language lookup(final String symbol) { + Language lang = symbolToLangauge.get(symbol.toLowerCase()); + if (lang == null) { + lang = new Language(new Locale(symbol)); + } + return lang; } } diff --git a/src/com/hughes/android/dictionary/engine/PairEntry.java b/src/com/hughes/android/dictionary/engine/PairEntry.java index 5406ed5..9160ac0 100644 --- a/src/com/hughes/android/dictionary/engine/PairEntry.java +++ b/src/com/hughes/android/dictionary/engine/PairEntry.java @@ -3,68 +3,39 @@ package com.hughes.android.dictionary.engine; import java.io.IOException; import java.io.PrintStream; import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; import com.hughes.util.raf.RAFSerializable; import com.hughes.util.raf.RAFSerializer; public class PairEntry extends Entry implements RAFSerializable, Comparable { - public static final class Pair { - - public final String lang1; - public final String lang2; - - public Pair(final String lang1, final String lang2) { - this.lang1 = lang1; - this.lang2 = lang2; - } + public final List pairs; - public Pair(final String lang1, final String lang2, final boolean swap) { - this(swap ? lang2 : lang1, swap ? lang1 : lang2); - } - - public String toString() { - return lang1 + " :: " + lang2; - } - - public String toStringTab() { - return lang1 + "\t" + lang2; - } - - public String get(int i) { - if (i == 0) { - return lang1; - } else if (i == 1) { - return lang2; - } - throw new IllegalArgumentException(); - } - - } - - public final Pair[] pairs; - - public PairEntry(final Pair[] pairs) { - this.pairs = pairs; + public PairEntry() { + pairs = new ArrayList(1); } - + public PairEntry(final String lang1, final String lang2) { - this.pairs = new Pair[] { new Pair(lang1, lang2) }; + pairs = new ArrayList(1); + this.pairs.add(new Pair(lang1, lang2)); } public PairEntry(final RandomAccessFile raf) throws IOException { - pairs = new Pair[raf.readInt()]; - for (int i = 0; i < pairs.length; ++i) { - pairs[i] = new Pair(raf.readUTF(), raf.readUTF()); + final int size = raf.readInt(); + pairs = new ArrayList(size); + for (int i = 0; i < size; ++i) { + pairs.add(new Pair(raf.readUTF(), raf.readUTF())); } } @Override public void write(RandomAccessFile raf) throws IOException { // TODO: this could be a short. - raf.writeInt(pairs.length); - for (int i = 0; i < pairs.length; ++i) { - raf.writeUTF(pairs[i].lang1); - raf.writeUTF(pairs[i].lang2); + raf.writeInt(pairs.size()); + for (int i = 0; i < pairs.size(); ++i) { + raf.writeUTF(pairs.get(i).lang1); + raf.writeUTF(pairs.get(i).lang2); } } @@ -100,8 +71,8 @@ public class PairEntry extends Entry implements RAFSerializable, Comp @Override public void print(PrintStream out) { final PairEntry pairEntry = getEntry(); - for (int i = 0; i < pairEntry.pairs.length; ++i) { - out.print((i == 0 ? " " : " ") + pairEntry.pairs[i]); + for (int i = 0; i < pairEntry.pairs.size(); ++i) { + out.print((i == 0 ? " " : " ") + pairEntry.pairs.get(i)); out.println(); } } @@ -116,21 +87,21 @@ public class PairEntry extends Entry implements RAFSerializable, Comp public String getRawText(final boolean compact) { if (compact) { - return this.pairs[0].toStringTab(); + return this.pairs.get(0).toStringTab(); } final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < this.pairs.length; ++i) { + for (int i = 0; i < this.pairs.size(); ++i) { if (i > 0) { builder.append(" | "); } - builder.append(this.pairs[i].lang1); + builder.append(this.pairs.get(i).lang1); } builder.append("\t"); - for (int i = 0; i < this.pairs.length; ++i) { + for (int i = 0; i < this.pairs.size(); ++i) { if (i > 0) { builder.append(" | "); } - builder.append(this.pairs[i].lang2); + builder.append(this.pairs.get(i).lang2); } return builder.toString(); } @@ -144,6 +115,42 @@ public class PairEntry extends Entry implements RAFSerializable, Comp public String toString() { return getRawText(false); } + + // ----------------------------------------------------------------------- + + public static final class Pair { + + public final String lang1; + public final String lang2; + + public Pair(final String lang1, final String lang2) { + this.lang1 = lang1; + this.lang2 = lang2; + //assert lang1.trim().length() > 0 || lang2.trim().length() > 0 : "Empty pair!!!"; + } + + public Pair(final String lang1, final String lang2, final boolean swap) { + this(swap ? lang2 : lang1, swap ? lang1 : lang2); + } + + public String toString() { + return lang1 + " :: " + lang2; + } + + public String toStringTab() { + return lang1 + "\t" + lang2; + } + + public String get(int i) { + if (i == 0) { + return lang1; + } else if (i == 1) { + return lang2; + } + throw new IllegalArgumentException(); + } + + } } diff --git a/src/com/hughes/android/dictionary/engine/RowBase.java b/src/com/hughes/android/dictionary/engine/RowBase.java index 7ac86d0..9104398 100644 --- a/src/com/hughes/android/dictionary/engine/RowBase.java +++ b/src/com/hughes/android/dictionary/engine/RowBase.java @@ -53,8 +53,13 @@ public abstract class RowBase extends IndexedObject { } if (rUp < index.rows.size()) { final RowBase rowUp = index.rows.get(rUp); - final TokenRow candidateUp = rowUp.getTokenRow(false); + TokenRow candidateUp = rowUp.getTokenRow(false); if (candidateUp != null) { + // Did we hit the next set of TokenRows? + if (candidateUp.index() > this.index()) { + final int tokenIndex = index.sortedIndexEntries.get(candidateUp.referenceIndex - 1).startRow; + candidateUp = (TokenRow) index.rows.get(tokenIndex); + } for (--rUp; rUp >= index(); --rUp) { index.rows.get(rUp).setTokenRow(candidateUp); } diff --git a/src/com/hughes/android/dictionary/engine/TokenRow.java b/src/com/hughes/android/dictionary/engine/TokenRow.java index e40d124..a47de2f 100644 --- a/src/com/hughes/android/dictionary/engine/TokenRow.java +++ b/src/com/hughes/android/dictionary/engine/TokenRow.java @@ -34,7 +34,7 @@ public class TokenRow extends RowBase { @Override public void print(final PrintStream out) { - out.println(getToken()); + out.println("===" + getToken() + "==="); } @Override diff --git a/src/com/hughes/android/dictionary/engine/TransliteratorManager.java b/src/com/hughes/android/dictionary/engine/TransliteratorManager.java new file mode 100644 index 0000000..50a7ca6 --- /dev/null +++ b/src/com/hughes/android/dictionary/engine/TransliteratorManager.java @@ -0,0 +1,58 @@ +package com.hughes.android.dictionary.engine; + +import java.util.ArrayList; +import java.util.List; + +import android.util.Log; + +import com.ibm.icu.text.Transliterator; + +public class TransliteratorManager { + + private static boolean starting = false; + private static boolean ready = false; + + private static List callbacks = new ArrayList(); + + public static synchronized boolean init(final Callback callback) { + if (ready) { + return true; + } + if (callback != null) { + callbacks.add(callback); + } + if (!starting) { + starting = true; + new Thread(init).start(); + } + return false; + } + + private static final Runnable init = new Runnable() { + @Override + public void run() { + System.out.println("Starting Transliterator load."); + final String transliterated = + Transliterator.createFromRules("", ":: Any-Latin; :: Lower; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC ;", + Transliterator.FORWARD).transliterate("Îñţérñåţîöñåļîžåţîờñ"); + if (!"internationalization".equals(transliterated)) { + System.out.println("Wrong transliteratation: " + transliterated); + } + + final List callbacks = new ArrayList(); + synchronized (TransliteratorManager.class) { + callbacks.addAll(TransliteratorManager.callbacks); + ready = true; + } + for (final Callback callback : callbacks) { + callback.onTransliteratorReady(); + } + } + }; + + + public interface Callback { + void onTransliteratorReady(); + } + +}