diff --git a/src/ui/android/AndroidManifest.xml b/src/ui/android/AndroidManifest.xml index 37f1efeca..d52722356 100644 --- a/src/ui/android/AndroidManifest.xml +++ b/src/ui/android/AndroidManifest.xml @@ -25,7 +25,14 @@ - + + + + + + + + diff --git a/src/ui/android/res/values/strings.xml b/src/ui/android/res/values/strings.xml index 6ce31d213..a4d02295d 100644 --- a/src/ui/android/res/values/strings.xml +++ b/src/ui/android/res/values/strings.xml @@ -11,6 +11,7 @@ Help org.grammaticalframework.ui.android.GLOBAL_PREFERENCES + authority_key source_key target_key alternatives_key diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java b/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java index e5d691820..2cb8f9da4 100644 --- a/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java +++ b/src/ui/android/src/org/grammaticalframework/ui/android/AlternativesActivity.java @@ -1,6 +1,6 @@ package org.grammaticalframework.ui.android; -import java.util.List; +import java.util.*; import android.app.Activity; import android.app.ListActivity; @@ -17,6 +17,7 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; +import android.util.Log; import org.grammaticalframework.pgf.*; import org.grammaticalframework.ui.android.LanguageSelector.OnLanguageSelectedListener; @@ -26,7 +27,8 @@ public class AlternativesActivity extends ListActivity { private Translator mTranslator; private LanguageSelector mShowLanguageView; private View mProgressBarView = null; - + private AlternativesAdapter mAdapter = null; + /** Called when the activity is first created. */ @Override protected void onCreate(Bundle savedInstanceState) { @@ -55,7 +57,8 @@ public class AlternativesActivity extends ListActivity { @Override protected void onPostExecute(Void result) { - updateTranslations(); + mAdapter.notifyDataSetChanged(); + expandedView = null; hideProgressBar(); } }.execute(); @@ -63,11 +66,20 @@ public class AlternativesActivity extends ListActivity { }); TextView descrView = (TextView) findViewById(R.id.lexical_desc); - descrView.setText(getIntent().getExtras().getString("source")); + + String authority = getIntent().getData().getAuthority(); + String source = getIntent().getData().getQueryParameter("source"); + List analyses = new ArrayList(); + for (String an : getIntent().getData().getQueryParameters("alternative")) { + analyses.add(Expr.readExpr(an)); + } + descrView.setText(source); + + mAdapter = new AlternativesAdapter(this, authority, analyses); + setListAdapter(mAdapter); + expandedView = null; mProgressBarView = findViewById(R.id.progressBarView); - - updateTranslations(); } @Override @@ -86,15 +98,6 @@ public class AlternativesActivity extends ListActivity { } private View expandedView; - - private void updateTranslations() { - @SuppressWarnings("unchecked") - List list = (List) - getIntent().getExtras().getSerializable("analyses"); - - setListAdapter(new AlternativesAdapter(this, list)); - expandedView = null; - } private void collapse() { if (expandedView == null) @@ -113,7 +116,7 @@ public class AlternativesActivity extends ListActivity { expandedView = null; } - private void expand(View view, String lemma) { + private void expandWord(View view, Expr lemma) { String html = mTranslator.getInflectionTable(lemma); if (html == null) return; @@ -136,7 +139,7 @@ public class AlternativesActivity extends ListActivity { expandedView = view; } - private void expandExpr(View view, ExprProb ep) { + private void expandSentence(View view, Expr expr) { ImageView arrow = (ImageView) view.findViewById(R.id.arrow); arrow.setImageResource(R.drawable.close_arrow); @@ -150,7 +153,7 @@ public class AlternativesActivity extends ListActivity { ((RelativeLayout) view).addView(parseView, params); } - Object[] brackets = mTranslator.bracketedLinearize(ep.getExpr()); + Object[] brackets = mTranslator.bracketedLinearize(expr); if (brackets[0] instanceof Bracket) { Bracket b = (Bracket) brackets[0]; if (b.children[0].equals("*") || @@ -174,20 +177,23 @@ public class AlternativesActivity extends ListActivity { params.addRule(RelativeLayout.BELOW, R.id.desc_details); ((RelativeLayout) view).addView(textView, params); } - textView.setText(ep.getExpr().toString()); + textView.setText(expr.toString()); expandedView = view; } - private class AlternativesAdapter extends ArrayAdapter { - public AlternativesAdapter(Context context, List data) { + private class AlternativesAdapter extends ArrayAdapter { + private String mAuthority; + + public AlternativesAdapter(Context context, String authority, List data) { super(context, android.R.layout.simple_list_item_1, data); + mAuthority = authority; } public View getView(int position, View convertView, ViewGroup parent) { - Object item = getItem(position); + final Expr expr = getItem(position); - if (item instanceof MorphoAnalysis) { + if (mAuthority.equals(Translator.WORDS)) { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE); @@ -197,9 +203,7 @@ public class AlternativesActivity extends ListActivity { TextView descView = (TextView) convertView.findViewById(R.id.lexical_desc); - final String lemma = ((MorphoAnalysis) item).getLemma(); - - String phrase = mTranslator.generateLexiconEntry(lemma); + String phrase = mTranslator.generateLexiconEntry(expr); descView.setText(phrase); convertView.setOnClickListener(new OnClickListener() { @@ -208,16 +212,14 @@ public class AlternativesActivity extends ListActivity { if (expandedView == view) collapse(); else if (expandedView == null) - expand(view, lemma); + expandWord(view, expr); else { collapse(); - expand(view, lemma); + expandWord(view, expr); } } }); - } else if (item instanceof ExprProb) { - final ExprProb ep = (ExprProb) item; - + } else if (mAuthority.equals(Translator.SENTENCES)) { if (convertView == null) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE); @@ -233,7 +235,7 @@ public class AlternativesActivity extends ListActivity { TextView descView = (TextView) convertView.findViewById(R.id.alternative_desc); - String phrase = mTranslator.linearize(ep.getExpr()); + String phrase = mTranslator.linearize(expr); // parse by words, marked by %, darkest red color if (phrase.charAt(0) == '%') { @@ -270,10 +272,10 @@ public class AlternativesActivity extends ListActivity { if (expandedView == view) collapse(); else if (expandedView == null) - expandExpr(view, ep); + expandSentence(view, expr); else { collapse(); - expandExpr(view, ep); + expandSentence(view, expr); } } }); diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java b/src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java index 95cebbd9a..b7d118e7c 100644 --- a/src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java +++ b/src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java @@ -1,7 +1,7 @@ package org.grammaticalframework.ui.android; import java.io.Serializable; -import java.util.ArrayList; +import java.util.*; import android.content.Context; import android.os.Bundle; @@ -17,6 +17,8 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; +import org.grammaticalframework.pgf.Expr; + public class ConversationView extends ScrollView { private LayoutInflater mInflater; @@ -105,7 +107,7 @@ public class ConversationView extends ScrollView { } @SuppressWarnings("deprecation") - public CharSequence addSecondPersonUtterance(final CharSequence source, CharSequence target, final Object alternatives) { + public CharSequence addSecondPersonUtterance(String authority, CharSequence source, CharSequence target, List alternatives) { TextView view; if (mLastUtterance != null && mLastUtterance.getTag() != null) view = (TextView) mLastUtterance.getTag(); @@ -124,6 +126,7 @@ public class ConversationView extends ScrollView { mLastUtterance.setTag(view); } + view.setTag(R.string.authority_key, authority); view.setTag(R.string.source_key, source); view.setTag(R.string.target_key, target); view.setTag(R.string.alternatives_key, alternatives); @@ -176,9 +179,10 @@ public class ConversationView extends ScrollView { mAlternativesListener = new OnClickListener() { @Override public void onClick(View v) { + String authority = v.getTag(R.string.authority_key).toString(); String source = v.getTag(R.string.source_key).toString(); - Object alternatives = v.getTag(R.string.alternatives_key); - listener.onAlternativesSelected(source, alternatives); + List alternatives = (List) v.getTag(R.string.alternatives_key); + listener.onAlternativesSelected(authority, source, alternatives); } }; } @@ -186,12 +190,13 @@ public class ConversationView extends ScrollView { public void setSpeechInputListener(ASR.Listener listener) { mSpeechListener = listener; } - + public interface OnAlternativesListener { - public void onAlternativesSelected(CharSequence word, Object lexicon); + public void onAlternativesSelected(CharSequence authority, CharSequence word, List althernatives); } public void saveConversation(Bundle state) { + ArrayList authorities = new ArrayList(); ArrayList firstPersonUtterances = new ArrayList(); ArrayList secondPersonUtterances = new ArrayList(); ArrayList translationAlternatives = new ArrayList(); @@ -200,31 +205,36 @@ public class ConversationView extends ScrollView { for (int i = 0; i < childCount; i++) { View child = mContent.getChildAt(i); if (child.getClass() == TextView.class) { + authorities.add(child.getTag(R.string.authority_key).toString()); firstPersonUtterances.add(child.getTag(R.string.source_key).toString()); secondPersonUtterances.add(child.getTag(R.string.target_key).toString()); translationAlternatives.add(child.getTag(R.string.alternatives_key)); } } + state.putStringArrayList("authorities", authorities); state.putStringArrayList("first_person_uterances", firstPersonUtterances); state.putStringArrayList("second_person_uterances", secondPersonUtterances); state.putSerializable("translation_alternatives",(Serializable) translationAlternatives); } public void restoreConversation(Bundle state) { + ArrayList authorities = state.getStringArrayList("authorities"); ArrayList firstPersonUtterances = state.getStringArrayList("first_person_uterances"); ArrayList secondPersonUtterances = state.getStringArrayList("second_person_uterances"); - ArrayList translationAlternatives= (ArrayList) state.getSerializable("translation_alternatives"); + ArrayList> translationAlternatives= (ArrayList>) state.getSerializable("translation_alternatives"); int i = 0; - while (i < firstPersonUtterances.size() && + while (i < authorities.size() && + i < firstPersonUtterances.size() && i < Math.min(secondPersonUtterances.size(), translationAlternatives.size())) { String text = firstPersonUtterances.get(i); addFirstPersonUtterance(text, false); + String authority = authorities.get(i); String translation = secondPersonUtterances.get(i); - Object alternatives = translationAlternatives.get(i); - addSecondPersonUtterance(text, translation, alternatives); + List alternatives = translationAlternatives.get(i); + addSecondPersonUtterance(authority, text, translation, alternatives); i++; } diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java b/src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java index f4f303f64..9ef344997 100644 --- a/src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java +++ b/src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java @@ -1,9 +1,7 @@ package org.grammaticalframework.ui.android; -import java.io.Serializable; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.io.*; +import java.util.*; import android.app.Activity; import android.content.Intent; @@ -11,6 +9,7 @@ import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.speech.SpeechRecognizer; +import android.net.Uri; import android.util.Log; import android.util.Pair; import android.view.Menu; @@ -25,8 +24,7 @@ import android.widget.ImageView; import org.grammaticalframework.ui.android.ASR.State; import org.grammaticalframework.ui.android.LanguageSelector.OnLanguageSelectedListener; import org.grammaticalframework.ui.android.ConversationView.OnAlternativesListener; -import org.grammaticalframework.pgf.ExprProb; -import org.grammaticalframework.pgf.MorphoAnalysis; +import org.grammaticalframework.pgf.*; public class MainActivity extends Activity { @@ -89,10 +87,16 @@ public class MainActivity extends Activity { mConversationView.setOnAlternativesListener(new OnAlternativesListener() { @Override - public void onAlternativesSelected(CharSequence input, Object lexicon) { - Intent myIntent = new Intent(MainActivity.this, AlternativesActivity.class); - myIntent.putExtra("source", input); - myIntent.putExtra("analyses", (Serializable) lexicon); + public void onAlternativesSelected(CharSequence authority, CharSequence input, List alternatives) { + Uri.Builder builder = new Uri.Builder(); + builder.scheme("gf-translator"); + builder.authority(authority.toString()); + builder.appendQueryParameter("source", input.toString()); + for (Expr e : alternatives) { + builder.appendQueryParameter("alternative", e.toString()); + } + + Intent myIntent = new Intent(Intent.ACTION_VIEW, builder.build()); MainActivity.this.startActivity(myIntent); } }); @@ -187,10 +191,16 @@ public class MainActivity extends Activity { editor.commit(); return true; - case R.id.help: + case R.id.semantic_graph: { + Intent myIntent = new Intent(MainActivity.this, SemanticGraphActivity.class); + MainActivity.this.startActivity(myIntent); + return true; + } + case R.id.help: { Intent myIntent = new Intent(MainActivity.this, HelpActivity.class); MainActivity.this.startActivity(myIntent); return true; + } default: return super.onOptionsItemSelected(item); } @@ -278,11 +288,16 @@ public class MainActivity extends Activity { protected void onPostExecute(Pair> res) { String text = res.first; List transl = res.second; - Object alts = null; + + List alts = null; + String authority = null; // filter out duplicates int i = 0; if (list.size() > 0) { + alts = new ArrayList(list.size()); + authority = Translator.WORDS; + while (i < list.size()) { MorphoAnalysis an = list.get(i); boolean found = false; @@ -293,14 +308,16 @@ public class MainActivity extends Activity { } } - if (found) - list.remove(i); - else { - i++; + if (!found) { + alts.add(Expr.readExpr(an.getLemma())); } + + i++; } - alts = list; } else { + alts = new ArrayList(transl.size()); + authority = Translator.SENTENCES; + Set strings = new HashSet(); while (i < transl.size()) { String s = mTranslator.linearize(transl.get(i).getExpr()); @@ -309,20 +326,18 @@ public class MainActivity extends Activity { s = s.substring(2); } - if (strings.contains(s)) - transl.remove(i); - else { + if (!strings.contains(s)) { strings.add(s); - i++; + alts.add(transl.get(i).getExpr()); } - } - alts = transl; - } + i++; + } + } if (DBG) Log.d(TAG, "Speaking: " + res.first); CharSequence text2 = - mConversationView.addSecondPersonUtterance(input, text, alts); + mConversationView.addSecondPersonUtterance(authority, input, text, alts); text2 = text2.toString().replace('[',' ').replace(']',' ').replaceAll("_","").trim(); mTts.speak(getTargetLanguageCode(), text2.toString()); diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/SemanticGraphManager.java b/src/ui/android/src/org/grammaticalframework/ui/android/SemanticGraphManager.java index 0d5d5e227..12f0e2143 100644 --- a/src/ui/android/src/org/grammaticalframework/ui/android/SemanticGraphManager.java +++ b/src/ui/android/src/org/grammaticalframework/ui/android/SemanticGraphManager.java @@ -11,6 +11,7 @@ public class SemanticGraphManager implements Closeable { private SG mDB; public static final String GLOSSES_FILE_NAME = "glosses.txt"; + public static final String TOPICS_FILE_NAME = "topics.txt"; public static final String DATABASE_FILE_NAME = "semantics.db"; public SemanticGraphManager(Context context) { @@ -44,9 +45,14 @@ public class SemanticGraphManager implements Closeable { if (exists) return; + loadFile(GLOSSES_FILE_NAME); + loadFile(TOPICS_FILE_NAME); + } + + private void loadFile(String assetName) throws IOException { BufferedReader br = new BufferedReader( new InputStreamReader( - mContext.getAssets().open(GLOSSES_FILE_NAME))); + mContext.getAssets().open(assetName))); try { mDB.beginTrans(); @@ -67,7 +73,7 @@ public class SemanticGraphManager implements Closeable { } finally { br.close(); } - } + } public void close() { if (mDB != null) { @@ -75,40 +81,9 @@ public class SemanticGraphManager implements Closeable { mDB = null; } } - - public Expr getDefinition(Expr lemma, boolean withExample) { - Expr gloss = null; - Expr example = null; - - try { - createDatabaseFromAssets(); - - { - TripleResult res = mDB.queryTriple(lemma, Expr.readExpr("gloss"), null); - if (res.hasNext()) { - gloss = res.getObject(); - } - res.close(); - } - - if (withExample) { - TripleResult res = mDB.queryTriple(lemma, Expr.readExpr("example"), null); - if (res.hasNext()) { - example = res.getObject(); - } - res.close(); - } - } catch (IOException e) { - // nothing - } catch (SGError e) { - // nothing - } - - if (gloss == null) - return null; - else if (example == null) - return new Expr("MkDefinition", gloss); - else - return new Expr("MkDefinitionEx", gloss, example); + + public TripleResult queryTriple(Expr subj, Expr pred, Expr obj) throws IOException { + createDatabaseFromAssets(); + return mDB.queryTriple(subj, pred, obj); } } diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java b/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java index 13b224b5b..88884f819 100644 --- a/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java +++ b/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java @@ -5,10 +5,12 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; import android.util.Pair; +import android.net.Uri; import android.view.inputmethod.CompletionInfo; import android.database.sqlite.SQLiteDatabase; import android.database.Cursor; +import org.grammaticalframework.sg.*; import org.grammaticalframework.pgf.*; import java.io.*; import java.util.*; @@ -54,6 +56,9 @@ public class Translator { private static final String SOURCE_LANG_KEY = "source_lang"; private static final String TARGET_LANG_KEY = "target_lang"; + public static final String WORDS = "words"; + public static final String SENTENCES = "sentences"; + private static final int NUM_ALT_TRANSLATIONS = 10; private SharedPreferences mSharedPref; @@ -345,48 +350,142 @@ public class Translator { return targetLang.bracketedLinearize(expr); } - public String generateLexiconEntry(String lemma) { + public String generateLexiconEntry(Expr lemma) { Concr sourceLang = getSourceConcr(); Concr targetLang = getTargetConcr(); - String cat = getGrammar().getFunctionType(lemma).getCategory(); + String fun = lemma.toString(); + String cat = getGrammar().getFunctionType(fun).getCategory(); - Expr e1 = Expr.readExpr(lemma); - Expr e2 = Expr.readExpr("MkTag (Inflection"+cat+" "+lemma+")"); + Expr e2 = Expr.readExpr("MkTag (Inflection"+cat+" "+fun+")"); if (targetLang.hasLinearization("Inflection"+cat)) { - if (targetLang.hasLinearization(lemma)) - return sourceLang.linearize(e1) + " - " + targetLang.linearize(e2) + ". " + targetLang.linearize(e1); + if (targetLang.hasLinearization(fun)) + return sourceLang.linearize(lemma) + " - " + targetLang.linearize(e2) + ". " + targetLang.linearize(lemma); else - return sourceLang.linearize(e1) + " " + targetLang.linearize(e2)+"."; + return sourceLang.linearize(lemma) + " " + targetLang.linearize(e2)+"."; } else { - if (targetLang.hasLinearization(lemma)) - return sourceLang.linearize(e1) + " - " + targetLang.linearize(e1); + if (targetLang.hasLinearization(fun)) + return sourceLang.linearize(lemma) + " - " + targetLang.linearize(lemma); else - return sourceLang.linearize(e1); + return sourceLang.linearize(lemma); } } - public String getInflectionTable(String lemma) { + private static final Expr gloss_pred = Expr.readExpr("gloss"); + private static final Expr topic_pred = Expr.readExpr("topic"); + private static final Expr example_pred = Expr.readExpr("example"); + + public Expr getDefinition(Expr lemma, boolean withExample) { + Expr gloss = null; + Expr example = null; + Map topics = new TreeMap(); + + try { + TripleResult res = mSGManager.queryTriple(lemma, null, null); + while (res.hasNext()) { + if (res.getPredicate().equals(gloss_pred)) + gloss = res.getObject(); + else if (res.getPredicate().equals(topic_pred)) + updateWordsMap(res.getObject(), topics); + else if (res.getPredicate().equals(example_pred)) + example = res.getObject(); + } + res.close(); + } catch (IOException e) { + // nothing + } catch (SGError e) { + // nothing + } + + Expr topic = null; + if (topics.size() > 0) { + StringBuilder builder = new StringBuilder(); + builder.append('('); + buildWordsHtml(topics, builder); + builder.append(')'); + topic = new Expr(builder.toString()); + } + if (gloss == null) + return topic; + else { + if (topic == null) + topic = new Expr(""); + if (withExample && example != null) + return new Expr("MkDefinitionEx", topic, gloss, example); + else + return new Expr("MkDefinition", topic, gloss); + } + } + + private void updateWordsMap(Expr expr, Map map) { + String word = getTargetConcr().linearize(expr); + + Uri.Builder builder = map.get(word); + if (builder == null) { + builder = new Uri.Builder(); + builder.scheme("gf-translator"); + builder.authority(WORDS); + builder.appendQueryParameter("source", word); + map.put(word,builder); + } + builder.appendQueryParameter("alternative", expr.toString()); + } + + private void buildWordsHtml(Map map, StringBuilder sbuilder) { + boolean first = true; + for (Map.Entry entry : map.entrySet()) { + if (first) + first = false; + else + sbuilder.append(", "); + + sbuilder.append(""+entry.getKey()+""); + } + } + + private Expr getTopicWords(Expr lemma) { + StringBuilder sbuilder = new StringBuilder(); + try { + TripleResult res = mSGManager.queryTriple(null, topic_pred, lemma); + Map map = new TreeMap(); + while (res.hasNext()) { + updateWordsMap(res.getSubject(), map); + } + res.close(); + + StringBuilder builder = new StringBuilder(); + buildWordsHtml(map, builder); + return new Expr(builder.toString()); + } catch (IOException e) { + // nothing + } catch (SGError e) { + // nothing + } + return null; + } + + public String getInflectionTable(Expr lemma) { boolean withExample = (getSourceLanguage().getLangCode().equals("en-US") || getTargetLanguage().getLangCode().equals("en-US")); Expr def = - mSGManager.getDefinition(Expr.readExpr(lemma), withExample); + getDefinition(lemma, withExample); + String fun = lemma.toString(); Concr targetLang = getTargetConcr(); - String cat = getGrammar().getFunctionType(lemma).getCategory(); + String cat = getGrammar().getFunctionType(fun).getCategory(); - if (targetLang.hasLinearization(lemma) && + if (targetLang.hasLinearization(fun) && targetLang.hasLinearization("Inflection"+cat)) { if (def == null) def = Expr.readExpr("NoDefinition"); Expr e = new Expr("MkDocument", def, - Expr.readExpr("Inflection"+cat+" "+lemma), - Expr.readExpr("\"\"")); + new Expr("Inflection"+cat,lemma), + getTopicWords(lemma)); String html = - "" + + "" + targetLang.linearize(e) + ""; return html;