summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorkr.angelov <kr.angelov@gmail.com>2013-11-13 10:45:20 +0000
committerkr.angelov <kr.angelov@gmail.com>2013-11-13 10:45:20 +0000
commitab1856046ffca7187d7d806a454729d9fb1bbecc (patch)
tree597f4487fd607d771a99f220509d647e7627564f /src/ui
parentfa4c327463f01eae2e0fda7deb82c4e9f40797cf (diff)
now the Android App has a translation keyboard which allows the translations to be done from inside another application
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/android/AndroidManifest.xml7
-rw-r--r--src/ui/android/res/drawable-hdpi/btn_close.pngbin0 -> 2220 bytes
-rw-r--r--src/ui/android/res/drawable-hdpi/sym_keyboard_delete.pngbin0 -> 885 bytes
-rw-r--r--src/ui/android/res/drawable-hdpi/sym_keyboard_return.pngbin0 -> 536 bytes
-rw-r--r--src/ui/android/res/drawable-hdpi/sym_keyboard_search.pngbin0 -> 1623 bytes
-rw-r--r--src/ui/android/res/drawable-hdpi/sym_keyboard_shift.pngbin0 -> 1247 bytes
-rw-r--r--src/ui/android/res/drawable-hdpi/sym_keyboard_space.pngbin0 -> 859 bytes
-rw-r--r--src/ui/android/res/drawable-mdpi/sym_keyboard_delete.pngbin0 -> 465 bytes
-rw-r--r--src/ui/android/res/drawable-mdpi/sym_keyboard_done.pngbin0 -> 771 bytes
-rw-r--r--src/ui/android/res/drawable-mdpi/sym_keyboard_return.pngbin0 -> 337 bytes
-rw-r--r--src/ui/android/res/drawable-mdpi/sym_keyboard_search.pngbin0 -> 1029 bytes
-rw-r--r--src/ui/android/res/drawable-mdpi/sym_keyboard_shift.pngbin0 -> 1029 bytes
-rw-r--r--src/ui/android/res/drawable-mdpi/sym_keyboard_space.pngbin0 -> 436 bytes
-rw-r--r--src/ui/android/res/layout/input.xml9
-rw-r--r--src/ui/android/res/layout/keyboard_languages_options.xml20
-rw-r--r--src/ui/android/res/values/dimens.xml3
-rw-r--r--src/ui/android/res/values/strings.xml11
-rw-r--r--src/ui/android/res/xml/cyrillic.xml76
-rw-r--r--src/ui/android/res/xml/method.xml6
-rw-r--r--src/ui/android/res/xml/popup_keyboard.xml5
-rw-r--r--src/ui/android/res/xml/qwerty.xml74
-rw-r--r--src/ui/android/res/xml/symbols.xml73
-rw-r--r--src/ui/android/res/xml/symbols_shift.xml71
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java4
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/Language.java9
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/LexicalEntryActivity.java2
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java14
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/Translator.java11
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/TranslatorInputMethodService.java581
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboard.java103
-rw-r--r--src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboardView.java113
31 files changed, 1181 insertions, 11 deletions
diff --git a/src/ui/android/AndroidManifest.xml b/src/ui/android/AndroidManifest.xml
index d9f983e65..47a0073c7 100644
--- a/src/ui/android/AndroidManifest.xml
+++ b/src/ui/android/AndroidManifest.xml
@@ -25,6 +25,13 @@
</intent-filter>
</activity>
<activity android:name="LexicalEntryActivity"></activity>
+ <service android:name="TranslatorInputMethodService"
+ android:permission="android.permission.BIND_INPUT_METHOD">
+ <intent-filter>
+ <action android:name="android.view.InputMethod" />
+ </intent-filter>
+ <meta-data android:name="android.view.im" android:resource="@xml/method" />
+ </service>
</application>
</manifest>
diff --git a/src/ui/android/res/drawable-hdpi/btn_close.png b/src/ui/android/res/drawable-hdpi/btn_close.png
new file mode 100644
index 000000000..47f11e5bf
--- /dev/null
+++ b/src/ui/android/res/drawable-hdpi/btn_close.png
Binary files differ
diff --git a/src/ui/android/res/drawable-hdpi/sym_keyboard_delete.png b/src/ui/android/res/drawable-hdpi/sym_keyboard_delete.png
new file mode 100644
index 000000000..5139c7179
--- /dev/null
+++ b/src/ui/android/res/drawable-hdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/src/ui/android/res/drawable-hdpi/sym_keyboard_return.png b/src/ui/android/res/drawable-hdpi/sym_keyboard_return.png
new file mode 100644
index 000000000..5a5670c32
--- /dev/null
+++ b/src/ui/android/res/drawable-hdpi/sym_keyboard_return.png
Binary files differ
diff --git a/src/ui/android/res/drawable-hdpi/sym_keyboard_search.png b/src/ui/android/res/drawable-hdpi/sym_keyboard_search.png
new file mode 100644
index 000000000..e72cde3bb
--- /dev/null
+++ b/src/ui/android/res/drawable-hdpi/sym_keyboard_search.png
Binary files differ
diff --git a/src/ui/android/res/drawable-hdpi/sym_keyboard_shift.png b/src/ui/android/res/drawable-hdpi/sym_keyboard_shift.png
new file mode 100644
index 000000000..275769618
--- /dev/null
+++ b/src/ui/android/res/drawable-hdpi/sym_keyboard_shift.png
Binary files differ
diff --git a/src/ui/android/res/drawable-hdpi/sym_keyboard_space.png b/src/ui/android/res/drawable-hdpi/sym_keyboard_space.png
new file mode 100644
index 000000000..cef2daa5d
--- /dev/null
+++ b/src/ui/android/res/drawable-hdpi/sym_keyboard_space.png
Binary files differ
diff --git a/src/ui/android/res/drawable-mdpi/sym_keyboard_delete.png b/src/ui/android/res/drawable-mdpi/sym_keyboard_delete.png
new file mode 100644
index 000000000..6cee59682
--- /dev/null
+++ b/src/ui/android/res/drawable-mdpi/sym_keyboard_delete.png
Binary files differ
diff --git a/src/ui/android/res/drawable-mdpi/sym_keyboard_done.png b/src/ui/android/res/drawable-mdpi/sym_keyboard_done.png
new file mode 100644
index 000000000..c0d6d1394
--- /dev/null
+++ b/src/ui/android/res/drawable-mdpi/sym_keyboard_done.png
Binary files differ
diff --git a/src/ui/android/res/drawable-mdpi/sym_keyboard_return.png b/src/ui/android/res/drawable-mdpi/sym_keyboard_return.png
new file mode 100644
index 000000000..cbe2b152f
--- /dev/null
+++ b/src/ui/android/res/drawable-mdpi/sym_keyboard_return.png
Binary files differ
diff --git a/src/ui/android/res/drawable-mdpi/sym_keyboard_search.png b/src/ui/android/res/drawable-mdpi/sym_keyboard_search.png
new file mode 100644
index 000000000..127755d6b
--- /dev/null
+++ b/src/ui/android/res/drawable-mdpi/sym_keyboard_search.png
Binary files differ
diff --git a/src/ui/android/res/drawable-mdpi/sym_keyboard_shift.png b/src/ui/android/res/drawable-mdpi/sym_keyboard_shift.png
new file mode 100644
index 000000000..d05962846
--- /dev/null
+++ b/src/ui/android/res/drawable-mdpi/sym_keyboard_shift.png
Binary files differ
diff --git a/src/ui/android/res/drawable-mdpi/sym_keyboard_space.png b/src/ui/android/res/drawable-mdpi/sym_keyboard_space.png
new file mode 100644
index 000000000..09b94d9e6
--- /dev/null
+++ b/src/ui/android/res/drawable-mdpi/sym_keyboard_space.png
Binary files differ
diff --git a/src/ui/android/res/layout/input.xml b/src/ui/android/res/layout/input.xml
new file mode 100644
index 000000000..fdef07a53
--- /dev/null
+++ b/src/ui/android/res/layout/input.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<org.grammaticalframework.ui.android.TranslatorKeyboardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard"
+ android:layout_alignParentBottom="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
diff --git a/src/ui/android/res/layout/keyboard_languages_options.xml b/src/ui/android/res/layout/keyboard_languages_options.xml
new file mode 100644
index 000000000..0b45b739c
--- /dev/null
+++ b/src/ui/android/res/layout/keyboard_languages_options.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:padding="5dp"
+ android:layout_margin="1dp"
+ >
+ <ImageButton android:id="@+id/closeButton"
+ android:background="@android:color/transparent"
+ android:src="@drawable/btn_close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_marginStart="8dp"
+ android:padding="5dp"
+ android:clickable="true"
+ />
+</LinearLayout> \ No newline at end of file
diff --git a/src/ui/android/res/values/dimens.xml b/src/ui/android/res/values/dimens.xml
index 55c1e5908..55088756c 100644
--- a/src/ui/android/res/values/dimens.xml
+++ b/src/ui/android/res/values/dimens.xml
@@ -3,5 +3,8 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="key_height">50dip</dimen>
+ <dimen name="candidate_font_height">16sp</dimen>
+ <dimen name="candidate_vertical_padding">6sp</dimen>
</resources>
diff --git a/src/ui/android/res/values/strings.xml b/src/ui/android/res/values/strings.xml
index 57e20027d..e7c4e560f 100644
--- a/src/ui/android/res/values/strings.xml
+++ b/src/ui/android/res/values/strings.xml
@@ -9,4 +9,15 @@
<string name="mic_input">Speech Input</string>
<string name="keyboard_input">Keyboard Input</string>
<string name="global_preferences_key">org.grammaticalframework.ui.android.GLOBAL_PREFERENCES</string>
+
+ <!-- Labels on soft keys -->
+ <string name="label_done_key">Done</string>
+ <string name="label_go_key">Go</string>
+ <string name="label_next_key">Next</string>
+ <string name="label_previous_key">Previous</string>
+ <string name="label_send_key">Send</string>
+
+ <!-- Labels for subtype -->
+ <string name="normalKeyboardMode">normalKeyboardMode</string>
+ <string name="internalKeyboardMode">internalKeyboardMode</string>
</resources>
diff --git a/src/ui/android/res/xml/cyrillic.xml b/src/ui/android/res/xml/cyrillic.xml
new file mode 100644
index 000000000..2e444507b
--- /dev/null
+++ b/src/ui/android/res/xml/cyrillic.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="9%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:codes="1103" android:keyLabel="я" android:keyEdgeFlags="left"/>
+ <Key android:codes="1074" android:keyLabel="в"/>
+ <Key android:codes="1077" android:keyLabel="е" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ёєэ"/>
+ <Key android:codes="1088" android:keyLabel="р"/>
+ <Key android:codes="1090" android:keyLabel="т" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ћ"/>
+ <Key android:codes="1098" android:keyLabel="ъ"/>
+ <Key android:codes="1091" android:keyLabel="у" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ў"/>
+ <Key android:codes="1080" android:keyLabel="и" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ії"/>
+ <Key android:codes="1086" android:keyLabel="о"/>
+ <Key android:codes="1087" android:keyLabel="п"/>
+ <Key android:codes="1095" android:keyLabel="ч" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ҷҹ" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="1072" android:keyLabel="а" android:keyEdgeFlags="left"/>
+ <Key android:codes="1089" android:keyLabel="с"/>
+ <Key android:codes="1076" android:keyLabel="д" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ђ"/>
+ <Key android:codes="1092" android:keyLabel="ф"/>
+ <Key android:codes="1075" android:keyLabel="г" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ґѓ"/>
+ <Key android:codes="1093" android:keyLabel="х"/>
+ <Key android:codes="1081" android:keyLabel="й" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ј"/>
+ <Key android:codes="1082" android:keyLabel="к" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ќ"/>
+ <Key android:codes="1083" android:keyLabel="л" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="љ"/>
+ <Key android:codes="1096" android:keyLabel="ш"/>
+ <Key android:codes="1097" android:keyLabel="щ" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="14%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="1079" android:keyLabel="з"/>
+ <Key android:codes="1100" android:keyLabel="ь" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ыѣ"/>
+ <Key android:codes="1094" android:keyLabel="ц"/>
+ <Key android:codes="1078" android:keyLabel="ж" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="җџ"/>
+ <Key android:codes="1073" android:keyLabel="б"/>
+ <Key android:codes="1085" android:keyLabel="н" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="њ"/>
+ <Key android:codes="1084" android:keyLabel="м"/>
+ <Key android:codes="1102" android:keyLabel="ю"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/normalKeyboardMode">
+ <Key android:codes="-100" android:keyLabel="Sr" android:keyWidth="13%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="-200" android:keyLabel="Tr" android:keyWidth="13%p"/>
+ <Key android:codes="-2" android:keyLabel="123" android:keyWidth="13%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="29%p" android:isRepeatable="true"/>
+ <Key android:codes="46,44" android:keyLabel=". ,"
+ android:keyWidth="14%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="19%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/internalKeyboardMode">
+ <Key android:codes="-2" android:keyLabel="123" android:keyWidth="15%p" android:horizontalGap="10%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="30%p" android:isRepeatable="true"/>
+ <Key android:codes="46,44" android:keyLabel=". ,"
+ android:keyWidth="15%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+</Keyboard> \ No newline at end of file
diff --git a/src/ui/android/res/xml/method.xml b/src/ui/android/res/xml/method.xml
new file mode 100644
index 000000000..af83761ca
--- /dev/null
+++ b/src/ui/android/res/xml/method.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Search Manager. -->
+
+<input-method xmlns:android="http://schemas.android.com/apk/res/android">
+</input-method>
diff --git a/src/ui/android/res/xml/popup_keyboard.xml b/src/ui/android/res/xml/popup_keyboard.xml
new file mode 100644
index 000000000..521d3d278
--- /dev/null
+++ b/src/ui/android/res/xml/popup_keyboard.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:keyHeight="10%p">
+</Keyboard> \ No newline at end of file
diff --git a/src/ui/android/res/xml/qwerty.xml b/src/ui/android/res/xml/qwerty.xml
new file mode 100644
index 000000000..6e0b95975
--- /dev/null
+++ b/src/ui/android/res/xml/qwerty.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/>
+ <Key android:codes="119" android:keyLabel="w"/>
+ <Key android:codes="101" android:keyLabel="e" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="èéêë"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ýÿ"/>
+ <Key android:codes="117" android:keyLabel="u" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ùúûü"/>
+ <Key android:codes="105" android:keyLabel="i" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ìíîï"/>
+ <Key android:codes="111" android:keyLabel="o" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="òóôõöœø"/>
+ <Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="97" android:keyLabel="a" android:horizontalGap="5%p"
+ android:keyEdgeFlags="left" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="àáâãäåæ"/>
+ <Key android:codes="115" android:keyLabel="s" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ß"/>
+ <Key android:codes="100" android:keyLabel="d"/>
+ <Key android:codes="102" android:keyLabel="f"/>
+ <Key android:codes="103" android:keyLabel="g"/>
+ <Key android:codes="104" android:keyLabel="h"/>
+ <Key android:codes="106" android:keyLabel="j"/>
+ <Key android:codes="107" android:keyLabel="k"/>
+ <Key android:codes="108" android:keyLabel="l" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="122" android:keyLabel="z"/>
+ <Key android:codes="120" android:keyLabel="x"/>
+ <Key android:codes="99" android:keyLabel="c"/>
+ <Key android:codes="118" android:keyLabel="v"/>
+ <Key android:codes="98" android:keyLabel="b"/>
+ <Key android:codes="110" android:keyLabel="n" android:popupKeyboard="@xml/popup_keyboard" android:popupCharacters="ñ"/>
+ <Key android:codes="109" android:keyLabel="m"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/normalKeyboardMode">
+ <Key android:codes="-100" android:keyLabel="Sr" android:keyWidth="13%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="-200" android:keyLabel="Tr" android:keyWidth="13%p"/>
+ <Key android:codes="-2" android:keyLabel="123" android:keyWidth="13%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="29%p" android:isRepeatable="true"/>
+ <Key android:codes="46,44" android:keyLabel=". ,"
+ android:keyWidth="14%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="19%p" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/internalKeyboardMode">
+ <Key android:codes="-2" android:keyLabel="123" android:keyWidth="15%p" android:horizontalGap="10%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="30%p" android:isRepeatable="true"/>
+ <Key android:codes="46,44" android:keyLabel=". ,"
+ android:keyWidth="15%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+</Keyboard>
+ \ No newline at end of file
diff --git a/src/ui/android/res/xml/symbols.xml b/src/ui/android/res/xml/symbols.xml
new file mode 100644
index 000000000..72deff01c
--- /dev/null
+++ b/src/ui/android/res/xml/symbols.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:codes="50" android:keyLabel="2"/>
+ <Key android:codes="51" android:keyLabel="3"/>
+ <Key android:codes="52" android:keyLabel="4"/>
+ <Key android:codes="53" android:keyLabel="5"/>
+ <Key android:codes="54" android:keyLabel="6"/>
+ <Key android:codes="55" android:keyLabel="7"/>
+ <Key android:codes="56" android:keyLabel="8"/>
+ <Key android:codes="57" android:keyLabel="9"/>
+ <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="64" android:keyLabel="\@" android:keyEdgeFlags="left"/>
+ <Key android:codes="35" android:keyLabel="\#"/>
+ <Key android:codes="36" android:keyLabel="$"/>
+ <Key android:codes="37" android:keyLabel="%"/>
+ <Key android:codes="38" android:keyLabel="&amp;"/>
+ <Key android:codes="42" android:keyLabel="*"/>
+ <Key android:codes="45" android:keyLabel="-"/>
+ <Key android:codes="61" android:keyLabel="="/>
+ <Key android:codes="40" android:keyLabel="("/>
+ <Key android:codes="41" android:keyLabel=")" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="33" android:keyLabel="!" />
+ <Key android:codes="34" android:keyLabel="&quot;"/>
+ <Key android:codes="39" android:keyLabel="\'"/>
+ <Key android:codes="58" android:keyLabel=":"/>
+ <Key android:codes="59" android:keyLabel=";"/>
+ <Key android:codes="47" android:keyLabel="/" />
+ <Key android:codes="63" android:keyLabel="\?"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/normalKeyboardMode">
+ <Key android:codes="-200" android:keyLabel="Tr" android:horizontalGap="5%p"
+ android:keyWidth="13%p" android:keyEdgeFlags="left" />
+ <Key android:codes="-2" android:keyLabel="ABC" android:keyWidth="15%p" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" android:keyWidth="30%p"
+ android:isRepeatable="true"/>
+ <Key android:codes="44" android:keyLabel="," android:keyWidth="15%p" />
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"
+ />
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/internalKeyboardMode">
+ <Key android:codes="-2" android:keyLabel="ABC" android:keyWidth="15%p" android:horizontalGap="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" android:keyWidth="30%p"
+ android:isRepeatable="true"/>
+ <Key android:codes="44" android:keyLabel="," android:keyWidth="15%p" />
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"
+ />
+ </Row>
+</Keyboard> \ No newline at end of file
diff --git a/src/ui/android/res/xml/symbols_shift.xml b/src/ui/android/res/xml/symbols_shift.xml
new file mode 100644
index 000000000..b55e6f521
--- /dev/null
+++ b/src/ui/android/res/xml/symbols_shift.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:codes="126" android:keyLabel="~" android:keyEdgeFlags="left"/>
+ <Key android:codes="177" android:keyLabel="±"/>
+ <Key android:codes="215" android:keyLabel="×"/>
+ <Key android:codes="247" android:keyLabel="÷"/>
+ <Key android:codes="8226" android:keyLabel="•"/>
+ <Key android:codes="176" android:keyLabel="°"/>
+ <Key android:codes="96" android:keyLabel="`"/>
+ <Key android:codes="180" android:keyLabel="´"/>
+ <Key android:codes="123" android:keyLabel="{"/>
+ <Key android:codes="125" android:keyLabel="}" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="169" android:keyLabel="©" android:keyEdgeFlags="left"/>
+ <Key android:codes="163" android:keyLabel="£"/>
+ <Key android:codes="8364" android:keyLabel="€"/>
+ <Key android:codes="94" android:keyLabel="^"/>
+ <Key android:codes="174" android:keyLabel="®"/>
+ <Key android:codes="165" android:keyLabel="¥"/>
+ <Key android:codes="95" android:keyLabel="_"/>
+ <Key android:codes="43" android:keyLabel="+"/>
+ <Key android:codes="91" android:keyLabel="["/>
+ <Key android:codes="93" android:keyLabel="]" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="161" android:keyLabel="¡" />
+ <Key android:codes="60" android:keyLabel="&lt;"/>
+ <Key android:codes="62" android:keyLabel="&gt;"/>
+ <Key android:codes="162" android:keyLabel="¢"/>
+ <Key android:codes="124" android:keyLabel="|"/>
+ <Key android:codes="92" android:keyLabel="\\" />
+ <Key android:codes="191" android:keyLabel="¿"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/normalKeyboardMode">
+ <Key android:codes="-200" android:keyLabel="Tr" android:horizontalGap="5%p"
+ android:keyWidth="13%p" android:keyEdgeFlags="left" />
+ <Key android:codes="-2" android:keyLabel="ABC" android:keyWidth="15%p" />
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" android:keyWidth="30%p"
+ android:isRepeatable="true"/>
+ <Key android:codes="8230" android:keyLabel="…" android:keyWidth="15%p" />
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right" />
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom" android:keyboardMode="@string/internalKeyboardMode">
+ <Key android:codes="-2" android:keyLabel="ABC" android:keyWidth="15%p" android:horizontalGap="10%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space" android:keyWidth="30%p"
+ android:isRepeatable="true"/>
+ <Key android:codes="8230" android:keyLabel="…" android:keyWidth="15%p" />
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right" />
+ </Row>
+</Keyboard>
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 cda719604..0a1004462 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/ConversationView.java
@@ -1,6 +1,7 @@
package org.grammaticalframework.ui.android;
import android.content.Context;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -88,6 +89,9 @@ public class ConversationView extends ScrollView {
return false;
}
});
+ Bundle extras = edittext.getInputExtras(true);
+ extras.putBoolean("show_language_toggle", false);
+
mContent.addView(view);
post(new Runnable() {
public void run() {
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/Language.java b/src/ui/android/src/org/grammaticalframework/ui/android/Language.java
index 996846e82..6b63bb8f2 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/Language.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/Language.java
@@ -9,12 +9,15 @@ public class Language implements Serializable {
private final String mLangName;
private final String mConcrete;
private final int mInflResource;
+ private final int mKeyboardResource;
- public Language(String langCode, String langName, String concrete, int inflResource) {
+ public Language(String langCode, String langName, String concrete,
+ int inflResource, int keyboardResource) {
mLangCode = langCode;
mLangName = langName;
mConcrete = concrete;
mInflResource = inflResource;
+ mKeyboardResource = keyboardResource;
}
public String getLangCode() {
@@ -28,6 +31,10 @@ public class Language implements Serializable {
public int getInflectionResource() {
return mInflResource;
}
+
+ public int getKeyboardResource() {
+ return mKeyboardResource;
+ }
String getConcrete() {
return mConcrete;
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/LexicalEntryActivity.java b/src/ui/android/src/org/grammaticalframework/ui/android/LexicalEntryActivity.java
index 8c8777e2f..8d9a41955 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/LexicalEntryActivity.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/LexicalEntryActivity.java
@@ -45,7 +45,7 @@ public class LexicalEntryActivity extends ListActivity {
mTranslator = ((GFTranslator) getApplicationContext()).getTranslator();
mShowLanguageView = (LanguageSelector) findViewById(R.id.show_language);
- mShowLanguageView.setLanguages(mTranslator.getAvailableSourceLanguages());
+ mShowLanguageView.setLanguages(mTranslator.getAvailableLanguages());
mShowLanguageView.setOnLanguageSelectedListener(new OnLanguageSelectedListener() {
@Override
public void onLanguageSelected(Language language) {
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 ab14bbfe2..9cbeb6930 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/MainActivity.java
@@ -101,14 +101,14 @@ public class MainActivity extends Activity {
mTranslator = ((GFTranslator) getApplicationContext()).getTranslator();
- mSourceLanguageView.setLanguages(mTranslator.getAvailableSourceLanguages());
+ mSourceLanguageView.setLanguages(mTranslator.getAvailableLanguages());
mSourceLanguageView.setOnLanguageSelectedListener(new OnLanguageSelectedListener() {
@Override
public void onLanguageSelected(Language language) {
onSourceLanguageSelected(language);
}
});
- mTargetLanguageView.setLanguages(mTranslator.getAvailableTargetLanguages());
+ mTargetLanguageView.setLanguages(mTranslator.getAvailableLanguages());
mTargetLanguageView.setOnLanguageSelectedListener(new OnLanguageSelectedListener() {
@Override
public void onLanguageSelected(Language language) {
@@ -192,10 +192,16 @@ public class MainActivity extends Activity {
void onSourceLanguageSelected(Language language) {
mTranslator.setSourceLanguage(language);
+ if (TranslatorInputMethodService.getInstance() != null) {
+ TranslatorInputMethodService.getInstance().handleChangeSourceLanguage(language);
+ }
}
void onTargetLanguageSelected(Language language) {
mTranslator.setTargetLanguage(language);
+ if (TranslatorInputMethodService.getInstance() != null) {
+ TranslatorInputMethodService.getInstance().handleChangeTargetLanguage(language);
+ }
}
public String getSourceLanguageCode() {
@@ -211,6 +217,10 @@ public class MainActivity extends Activity {
Language newTarget = mTranslator.getSourceLanguage();
mSourceLanguageView.setSelectedLanguage(newSource);
mTargetLanguageView.setSelectedLanguage(newTarget);
+
+ if (TranslatorInputMethodService.getInstance() != null) {
+ TranslatorInputMethodService.getInstance().handleSwitchLanguages();
+ }
}
private void startRecognition() {
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 f3a247844..e8ef4738e 100644
--- a/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/Translator.java
@@ -33,8 +33,9 @@ public class Translator {
new Language("fi-FI", "Finnish", "TranslateFin", 0),
new Language("sv-SE", "Swedish", "TranslateSwe", R.xml.inflection_sv),
*/
- new Language("en-US", "English", "ParseEng", R.xml.inflection_en),
- new Language("bg-BG", "Bulgarian", "ParseBul", R.xml.inflection_bg),
+ new Language("en-US", "English", "ParseEng", R.xml.inflection_en, R.xml.qwerty),
+ new Language("bg-BG", "Bulgarian", "ParseBul", R.xml.inflection_bg, R.xml.cyrillic),
+ new Language("sv-SE", "Swedish", "ParseSwe", R.xml.inflection_sv, R.xml.qwerty),
};
private Language mSourceLanguage;
@@ -78,11 +79,7 @@ public class Translator {
mTargetLanguage = getPrefLang(TARGET_LANG_KEY, 1);
}
- public List<Language> getAvailableSourceLanguages() {
- return Arrays.asList(mLanguages);
- }
-
- public List<Language> getAvailableTargetLanguages() {
+ public List<Language> getAvailableLanguages() {
return Arrays.asList(mLanguages);
}
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorInputMethodService.java b/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorInputMethodService.java
new file mode 100644
index 000000000..29c52c44a
--- /dev/null
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorInputMethodService.java
@@ -0,0 +1,581 @@
+package org.grammaticalframework.ui.android;
+
+import android.inputmethodservice.InputMethodService;
+import android.text.InputType;
+import android.text.method.MetaKeyKeyListener;
+import android.util.Log;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class TranslatorInputMethodService extends InputMethodService
+ implements android.inputmethodservice.KeyboardView.OnKeyboardActionListener {
+
+ private TranslatorKeyboardView mInputView;
+ private CompletionsView mCandidateView;
+ private CompletionInfo[] mCompletions;
+
+ private StringBuilder mComposing = new StringBuilder();
+ private boolean mPredictionOn;
+ private boolean mCompletionOn;
+ private boolean mCapsLock;
+ private long mLastShiftTime;
+ private long mMetaState;
+
+ private TranslatorKeyboard mSymbolsKeyboard;
+ private TranslatorKeyboard mSymbolsShiftedKeyboard;
+ private TranslatorKeyboard mLanguageKeyboard;
+
+ private TranslatorKeyboard mCurKeyboard;
+
+ private int mActionId;
+
+ private Translator mTranslator;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mTranslator = ((GFTranslator) getApplicationContext()).getTranslator();
+
+ mSymbolsKeyboard = null;
+ mSymbolsShiftedKeyboard = null;
+ mLanguageKeyboard = null;
+ }
+
+ @Override
+ public View onCreateInputView() {
+ mInputView = (TranslatorKeyboardView)
+ getLayoutInflater().inflate(R.layout.input, null);
+ mInputView.setOnKeyboardActionListener(this);
+ mInputView.setKeyboard(mCurKeyboard);
+ return mInputView;
+ }
+
+ @Override
+ public View onCreateCandidatesView() {
+ mCandidateView = new CompletionsView(this);
+ mCandidateView.setService(this);
+ return mCandidateView;
+ }
+
+ private int mModeId;
+ private static TranslatorInputMethodService mInstance;
+
+ static TranslatorInputMethodService getInstance() {
+ return mInstance;
+ }
+
+ @Override
+ public void onStartInput(EditorInfo attribute, boolean restarting) {
+ super.onStartInput(attribute, restarting);
+
+ // Reset our state. We want to do this even if restarting, because
+ // the underlying state of the text editor could have changed in any way.
+ mComposing.setLength(0);
+ updateCandidates();
+
+ if (!restarting) {
+ // Clear shift states.
+ mMetaState = 0;
+ }
+
+ mPredictionOn = false;
+ mCompletionOn = false;
+ mCompletions = null;
+
+ int res =
+ mTranslator.getSourceLanguage().getKeyboardResource();
+ mModeId = R.string.normalKeyboardMode;
+ if (attribute.extras != null &&
+ !attribute.extras.getBoolean("show_language_toggle", true)) {
+ mModeId = R.string.internalKeyboardMode;
+ }
+ mLanguageKeyboard = new TranslatorKeyboard(this, res, mModeId);
+ mSymbolsKeyboard = new TranslatorKeyboard(this, R.xml.symbols, mModeId);
+ mSymbolsShiftedKeyboard = new TranslatorKeyboard(this, R.xml.symbols_shift, mModeId);
+
+ // We are now going to initialize our state based on the type of
+ // text being edited.
+ switch (attribute.inputType & InputType.TYPE_MASK_CLASS) {
+ case InputType.TYPE_CLASS_NUMBER:
+ case InputType.TYPE_CLASS_DATETIME:
+ // Numbers and dates default to the symbols keyboard, with
+ // no extra features.
+ mCurKeyboard = mSymbolsKeyboard;
+ break;
+
+ case InputType.TYPE_CLASS_PHONE:
+ // Phones will also default to the symbols keyboard, though
+ // often you will want to have a dedicated phone keyboard.
+ mCurKeyboard = mSymbolsKeyboard;
+ break;
+
+ case InputType.TYPE_CLASS_TEXT:
+ // This is general text editing. We will default to the
+ // normal alphabetic keyboard, and assume that we should
+ // be doing predictive text (showing candidates as the
+ // user types).
+ mCurKeyboard = mLanguageKeyboard;
+ mPredictionOn = true;
+
+ // We now look for a few special variations of text that will
+ // modify our behavior.
+ int variation = attribute.inputType & InputType.TYPE_MASK_VARIATION;
+ if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
+ // Do not display predictions / what the user is typing
+ // when they are entering a password.
+ mPredictionOn = false;
+ }
+
+ if (variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ || variation == InputType.TYPE_TEXT_VARIATION_URI
+ || variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+ // Our predictions are not useful for e-mail addresses
+ // or URIs.
+ mPredictionOn = false;
+ }
+
+ if ((attribute.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
+ // If this is an auto-complete text view, then our predictions
+ // will not be shown and instead we will allow the editor
+ // to supply their own. We only show the editor's
+ // candidates when in full-screen mode, otherwise relying
+ // own it displaying its own UI.
+ mPredictionOn = false;
+ mCompletionOn = isFullscreenMode();
+ }
+
+ // We also want to look at the current state of the editor
+ // to decide whether our alphabetic keyboard should start out
+ // shifted.
+ updateShiftKeyState(attribute);
+ break;
+
+ default:
+ // For all unknown input types, default to the alphabetic
+ // keyboard with no special features.
+ mCurKeyboard = mLanguageKeyboard;
+ updateShiftKeyState(attribute);
+ }
+
+ mActionId = attribute.imeOptions & EditorInfo.IME_MASK_ACTION;
+ mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
+
+ mInstance = this;
+ }
+
+ @Override
+ public void onFinishInput() {
+ super.onFinishInput();
+
+ // Clear current composing text and candidates.
+ mComposing.setLength(0);
+ updateCandidates();
+
+ // We only hide the candidates window when finishing input on
+ // a particular editor, to avoid popping the underlying application
+ // up and down if the user is entering text into the bottom of
+ // its window.
+ setCandidatesViewShown(false);
+
+ mCurKeyboard = mLanguageKeyboard;
+ if (mInputView != null) {
+ mInputView.closing();
+ }
+
+ mInstance = null;
+ }
+
+ @Override
+ public void onStartInputView(EditorInfo attribute, boolean restarting) {
+ super.onStartInputView(attribute, restarting);
+ // Apply the selected keyboard to the input view.
+ mInputView.setKeyboard(mCurKeyboard);
+ mInputView.closing();
+ }
+
+ @Override
+ public void onUpdateSelection(int oldSelStart, int oldSelEnd,
+ int newSelStart, int newSelEnd,
+ int candidatesStart, int candidatesEnd) {
+ super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
+ candidatesStart, candidatesEnd);
+
+ // If the current selection in the text view changes, we should
+ // clear whatever candidate text we have.
+ if (mComposing.length() > 0 && (newSelStart != candidatesEnd
+ || newSelEnd != candidatesEnd)) {
+ mComposing.setLength(0);
+ updateCandidates();
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ ic.finishComposingText();
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayCompletions(CompletionInfo[] completions) {
+ if (mCompletionOn) {
+ mCompletions = completions;
+ if (completions == null) {
+ setSuggestions(null, false, false);
+ return;
+ }
+
+ List<String> stringList = new ArrayList<String>();
+ for (int i = 0; i < completions.length; i++) {
+ CompletionInfo ci = completions[i];
+ if (ci != null) stringList.add(ci.getText().toString());
+ }
+ setSuggestions(stringList, true, true);
+ }
+ }
+
+ /**
+ * This translates incoming hard key events in to edit operations on an
+ * InputConnection. It is only needed when using the
+ * PROCESS_HARD_KEYS option.
+ */
+ private boolean translateKeyDown(int keyCode, KeyEvent event) {
+ mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,
+ keyCode, event);
+ int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));
+ mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
+ InputConnection ic = getCurrentInputConnection();
+ if (c == 0 || ic == null) {
+ return false;
+ }
+
+ if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
+ }
+
+ if (mComposing.length() > 0) {
+ char accent = mComposing.charAt(mComposing.length() -1 );
+ int composed = KeyEvent.getDeadChar(accent, c);
+
+ if (composed != 0) {
+ c = composed;
+ mComposing.setLength(mComposing.length()-1);
+ }
+ }
+
+ onKey(c, null);
+
+ return true;
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BACK:
+ // The InputMethodService already takes care of the back
+ // key for us, to dismiss the input method if it is shown.
+ // However, our keyboard could be showing a pop-up window
+ // that back should dismiss, so we first allow it to do that.
+ if (event.getRepeatCount() == 0 && mInputView != null) {
+ if (mInputView.handleBack()) {
+ return true;
+ }
+ }
+ break;
+
+ case KeyEvent.KEYCODE_DEL:
+ // Special handling of the delete key: if we currently are
+ // composing text for the user, we want to modify that instead
+ // of let the application to the delete itself.
+ if (mComposing.length() > 0) {
+ onKey(TranslatorKeyboard.KEYCODE_DELETE, null);
+ return true;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_ENTER:
+ // Let the underlying text editor always handle these.
+ return false;
+
+ default:
+ if (mPredictionOn && translateKeyDown(keyCode, event)) {
+ return true;
+ }
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Helper function to commit any text being composed in to the editor.
+ */
+ private void commitTyped(InputConnection inputConnection) {
+ if (mComposing.length() > 0) {
+ inputConnection.commitText(mComposing, mComposing.length());
+ mComposing.setLength(0);
+ updateCandidates();
+ }
+ }
+
+ /**
+ * Helper to update the shift state of our keyboard based on the initial
+ * editor state.
+ */
+ private void updateShiftKeyState(EditorInfo attr) {
+ if (attr != null
+ && mInputView != null && mLanguageKeyboard == mInputView.getKeyboard()) {
+ int caps = 0;
+ EditorInfo ei = getCurrentInputEditorInfo();
+ if (ei != null && ei.inputType != InputType.TYPE_NULL) {
+ caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
+ }
+ mInputView.setShifted(mCapsLock || caps != 0);
+ }
+ }
+
+ /**
+ * Helper to send a key down / key up pair to the current editor.
+ */
+ private void keyDownUp(int keyEventCode) {
+ getCurrentInputConnection().sendKeyEvent(
+ new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
+ getCurrentInputConnection().sendKeyEvent(
+ new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
+ }
+
+ // Implementation of KeyboardViewListener
+ public void onKey(int primaryCode, int[] keyCodes) {
+ if (primaryCode == TranslatorKeyboard.KEYCODE_DELETE) {
+ handleBackspace();
+ } else if (primaryCode == TranslatorKeyboard.KEYCODE_SHIFT) {
+ handleShift();
+ } else if (primaryCode == TranslatorKeyboard.KEYCODE_SOURCE_LANGUAGE
+ && mInputView != null) {
+ Language newSource = mTranslator.getTargetLanguage();
+ Language newTarget = mTranslator.getSourceLanguage();
+ mTranslator.setSourceLanguage(newSource);
+ mTranslator.setTargetLanguage(newTarget);
+ handleSwitchLanguages();
+ } else if (primaryCode < TranslatorKeyboard.KEYCODE_SOURCE_LANGUAGE &&
+ primaryCode > TranslatorKeyboard.KEYCODE_SOURCE_LANGUAGE-TranslatorKeyboard.MAX_LANGUAGE_KEYCODES) {
+ Language newSource =
+ mTranslator.getAvailableLanguages().get(TranslatorKeyboard.KEYCODE_SOURCE_LANGUAGE-primaryCode-1);
+ mTranslator.setSourceLanguage(newSource);
+ handleChangeSourceLanguage(newSource);
+ } else if (primaryCode == TranslatorKeyboard.KEYCODE_TARGET_LANGUAGE) {
+ String translation = mTranslator.translate(mComposing.toString());
+ getCurrentInputConnection().commitText(translation, 1);
+ return;
+ } else if (primaryCode < TranslatorKeyboard.KEYCODE_TARGET_LANGUAGE &&
+ primaryCode > TranslatorKeyboard.KEYCODE_TARGET_LANGUAGE-TranslatorKeyboard.MAX_LANGUAGE_KEYCODES) {
+ Language newTarget =
+ mTranslator.getAvailableLanguages().get(TranslatorKeyboard.KEYCODE_TARGET_LANGUAGE-primaryCode-1);
+ mTranslator.setTargetLanguage(newTarget);
+ handleChangeTargetLanguage(newTarget);
+ } else if (primaryCode == TranslatorKeyboard.KEYCODE_MODE_CHANGE
+ && mInputView != null) {
+ TranslatorKeyboard current = (TranslatorKeyboard) mInputView.getKeyboard();
+ if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
+ current = mLanguageKeyboard;
+ } else {
+ current = mSymbolsKeyboard;
+ }
+ mInputView.setKeyboard(current);
+ if (current == mSymbolsKeyboard) {
+ current.setShifted(false);
+ }
+ } else if (primaryCode == 10) {
+ getCurrentInputConnection().performEditorAction(mActionId);
+ } else if (primaryCode == ' ' && mComposing.length() == 0) {
+ getCurrentInputConnection().commitText(" ", 1);
+ } else {
+ handleCharacter(primaryCode, keyCodes);
+ }
+ }
+
+ public void onText(CharSequence text) {
+ InputConnection ic = getCurrentInputConnection();
+ if (ic == null) return;
+ ic.beginBatchEdit();
+ if (mComposing.length() > 0) {
+ commitTyped(ic);
+ }
+ ic.commitText(text, 0);
+ ic.endBatchEdit();
+ updateShiftKeyState(getCurrentInputEditorInfo());
+ }
+
+ /**
+ * Update the list of available candidates from the current composing
+ * text. This will need to be filled in by however you are determining
+ * candidates.
+ */
+ private void updateCandidates() {
+ if (!mCompletionOn) {
+ if (mComposing.length() > 0) {
+ ArrayList<String> list = new ArrayList<String>();
+ list.add(mComposing.toString());
+ list.add("alfa");
+ list.add("beta");
+ setSuggestions(list, true, true);
+ Log.d("KEYBOARD", mComposing.toString());
+ } else {
+ setSuggestions(null, false, false);
+ }
+ }
+ }
+
+ public void setSuggestions(List<String> suggestions, boolean completions,
+ boolean typedWordValid) {
+ if (suggestions != null && suggestions.size() > 0) {
+ setCandidatesViewShown(true);
+ } else if (isExtractViewShown()) {
+ setCandidatesViewShown(true);
+ }
+ if (mCandidateView != null) {
+ mCandidateView.setSuggestions(suggestions, completions, typedWordValid);
+ }
+ }
+
+ private void handleBackspace() {
+ final int length = mComposing.length();
+ if (length > 1) {
+ mComposing.delete(length - 1, length);
+ getCurrentInputConnection().setComposingText(mComposing, 1);
+ updateCandidates();
+ } else if (length > 0) {
+ mComposing.setLength(0);
+ getCurrentInputConnection().commitText("", 0);
+ updateCandidates();
+ } else {
+ keyDownUp(KeyEvent.KEYCODE_DEL);
+ }
+ updateShiftKeyState(getCurrentInputEditorInfo());
+ }
+
+ private void handleShift() {
+ if (mInputView == null) {
+ return;
+ }
+
+ TranslatorKeyboard currentKeyboard = (TranslatorKeyboard) mInputView.getKeyboard();
+ if (mLanguageKeyboard == currentKeyboard) {
+ // Alphabet keyboard
+ checkToggleCapsLock();
+ mInputView.setShifted(mCapsLock || !mInputView.isShifted());
+ } else if (currentKeyboard == mSymbolsKeyboard) {
+ mSymbolsKeyboard.setShifted(true);
+ mInputView.setKeyboard(mSymbolsShiftedKeyboard);
+ mSymbolsShiftedKeyboard.setShifted(true);
+ } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
+ mSymbolsShiftedKeyboard.setShifted(false);
+ mInputView.setKeyboard(mSymbolsKeyboard);
+ mSymbolsKeyboard.setShifted(false);
+ }
+ }
+
+ private void handleCharacter(int primaryCode, int[] keyCodes) {
+ if (isInputViewShown()) {
+ if (mInputView.isShifted()) {
+ primaryCode = Character.toUpperCase(primaryCode);
+ }
+ }
+
+ mComposing.append((char) primaryCode);
+ getCurrentInputConnection().setComposingText(mComposing, 1);
+ updateShiftKeyState(getCurrentInputEditorInfo());
+
+ if (mPredictionOn) {
+ updateCandidates();
+ }
+ }
+
+ private void handleClose() {
+ commitTyped(getCurrentInputConnection());
+ requestHideSelf(0);
+ mInputView.closing();
+ }
+
+ void handleChangeSourceLanguage(Language newSource) {
+ mLanguageKeyboard =
+ new TranslatorKeyboard(this, newSource.getKeyboardResource(), mModeId);
+ mSymbolsKeyboard.updateLanguageKeyLabels();
+ mSymbolsShiftedKeyboard.updateLanguageKeyLabels();
+ mInputView.setKeyboard(mLanguageKeyboard);
+ }
+
+ void handleChangeTargetLanguage(Language newTarget) {
+ mLanguageKeyboard.updateLanguageKeyLabels();
+ mSymbolsKeyboard.updateLanguageKeyLabels();
+ mSymbolsShiftedKeyboard.updateLanguageKeyLabels();
+ mInputView.invalidateAllKeys();
+ }
+
+ void handleSwitchLanguages() {
+ Language newSource = mTranslator.getSourceLanguage();
+ mLanguageKeyboard =
+ new TranslatorKeyboard(this, newSource.getKeyboardResource(), mModeId);
+ mInputView.setKeyboard(mLanguageKeyboard);
+ }
+
+ private void checkToggleCapsLock() {
+ long now = System.currentTimeMillis();
+ if (mLastShiftTime + 800 > now) {
+ mCapsLock = !mCapsLock;
+ mLastShiftTime = 0;
+ } else {
+ mLastShiftTime = now;
+ }
+ }
+
+ public void pickDefaultCandidate() {
+ pickSuggestionManually(0);
+ }
+
+ public void pickSuggestionManually(int index) {
+ if (mCompletionOn && mCompletions != null && index >= 0
+ && index < mCompletions.length) {
+ CompletionInfo ci = mCompletions[index];
+ getCurrentInputConnection().commitCompletion(ci);
+ if (mCandidateView != null) {
+ mCandidateView.clear();
+ }
+ updateShiftKeyState(getCurrentInputEditorInfo());
+ } else if (mComposing.length() > 0) {
+ // If we were generating candidate suggestions for the current
+ // text, we would commit one of them here. But for this sample,
+ // we will just commit the current text.
+ commitTyped(getCurrentInputConnection());
+ }
+ }
+
+ public void swipeRight() {
+ if (mCompletionOn) {
+ pickDefaultCandidate();
+ }
+ }
+
+ public void swipeLeft() {
+ handleBackspace();
+ }
+
+ public void swipeDown() {
+ handleClose();
+ }
+
+ public void swipeUp() {
+ }
+
+ public void onPress(int primaryCode) {
+ }
+
+ public void onRelease(int primaryCode) {
+ }
+}
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboard.java b/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboard.java
new file mode 100644
index 000000000..cd29d6914
--- /dev/null
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboard.java
@@ -0,0 +1,103 @@
+package org.grammaticalframework.ui.android;
+
+import java.util.Locale;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.view.inputmethod.EditorInfo;
+import android.inputmethodservice.Keyboard;
+
+public class TranslatorKeyboard extends Keyboard {
+
+ private Key mEnterKey;
+ private Key mSourceLanguageKey;
+ private Key mTargetLanguageKey;
+
+ static final int KEYCODE_SOURCE_LANGUAGE = -100;
+ static final int KEYCODE_TARGET_LANGUAGE = -200;
+ static final int MAX_LANGUAGE_KEYCODES = 99;
+
+ private Translator mTranslator;
+
+ public TranslatorKeyboard(Context context, int xmlLayoutResId, int modeId) {
+ super(context, xmlLayoutResId, modeId);
+
+ mTranslator = ((GFTranslator) context.getApplicationContext()).getTranslator();
+ updateLanguageKeyLabels();
+ }
+
+ public void updateLanguageKeyLabels() {
+ if (mSourceLanguageKey != null)
+ mSourceLanguageKey.label = getLanguageKeyLabel(mTranslator.getSourceLanguage());
+
+ if (mTargetLanguageKey != null)
+ mTargetLanguageKey.label = getLanguageKeyLabel(mTranslator.getTargetLanguage());
+ }
+
+ public static String getLanguageKeyLabel(Language lang) {
+ return
+ LocaleUtils.parseJavaLocale(lang.getLangCode(), Locale.getDefault())
+ .getISO3Language();
+ }
+
+ @Override
+ protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
+ XmlResourceParser parser) {
+ Key key = new Key(res, parent, x, y, parser);
+ if (key.codes[0] == 10) {
+ mEnterKey = key;
+ } else if (key.codes[0] == KEYCODE_SOURCE_LANGUAGE) {
+ mSourceLanguageKey = key;
+ } else if (key.codes[0] == KEYCODE_TARGET_LANGUAGE) {
+ mTargetLanguageKey = key;
+ }
+ return key;
+ }
+
+ /**
+ * This looks at the ime options given by the current editor, to set the
+ * appropriate label on the keyboard's enter key (if it has one).
+ */
+ void setImeOptions(Resources res, int options) {
+ if (mEnterKey == null) {
+ return;
+ }
+
+ switch (options&(EditorInfo.IME_MASK_ACTION|EditorInfo.IME_FLAG_NO_ENTER_ACTION)) {
+ case EditorInfo.IME_ACTION_DONE:
+ mEnterKey.iconPreview = null;
+ mEnterKey.icon = null;
+ mEnterKey.label = res.getText(R.string.label_done_key);
+ break;
+ case EditorInfo.IME_ACTION_GO:
+ mEnterKey.iconPreview = null;
+ mEnterKey.icon = null;
+ mEnterKey.label = res.getText(R.string.label_go_key);
+ break;
+ case EditorInfo.IME_ACTION_NEXT:
+ mEnterKey.iconPreview = null;
+ mEnterKey.icon = null;
+ mEnterKey.label = res.getText(R.string.label_next_key);
+ break;
+ case EditorInfo.IME_ACTION_PREVIOUS:
+ mEnterKey.iconPreview = null;
+ mEnterKey.icon = null;
+ mEnterKey.label = res.getText(R.string.label_previous_key);
+ break;
+ case EditorInfo.IME_ACTION_SEARCH:
+ mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_search);
+ mEnterKey.label = null;
+ break;
+ case EditorInfo.IME_ACTION_SEND:
+ mEnterKey.iconPreview = null;
+ mEnterKey.icon = null;
+ mEnterKey.label = res.getText(R.string.label_send_key);
+ break;
+ default:
+ mEnterKey.icon = res.getDrawable(R.drawable.sym_keyboard_return);
+ mEnterKey.label = null;
+ break;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboardView.java b/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboardView.java
new file mode 100644
index 000000000..6bca2ad59
--- /dev/null
+++ b/src/ui/android/src/org/grammaticalframework/ui/android/TranslatorKeyboardView.java
@@ -0,0 +1,113 @@
+package org.grammaticalframework.ui.android;
+
+import java.util.Locale;
+
+import org.grammaticalframework.ui.android.TranslatorKeyboard;
+
+import android.content.Context;
+import android.inputmethodservice.Keyboard.Key;
+import android.inputmethodservice.KeyboardView;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+
+public class TranslatorKeyboardView extends KeyboardView {
+
+ private Translator mTranslator;
+
+ public TranslatorKeyboardView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mTranslator = ((GFTranslator) context.getApplicationContext()).getTranslator();
+ }
+
+ public TranslatorKeyboardView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mTranslator = ((GFTranslator) context.getApplicationContext()).getTranslator();
+ }
+
+ private PopupWindow mLanguagesPopup = null;
+ private Key mLanguagesKey = null;
+
+ private void showLanguageOptions(Key popupKey) {
+ if (mLanguagesPopup == null) {
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ LinearLayout popupContainer = (LinearLayout)
+ inflater.inflate(R.layout.keyboard_languages_options, null);
+
+ int index = 0;
+ for (Language lang : mTranslator.getAvailableLanguages()) {
+ Button item = new Button(getContext());
+ item.setText(TranslatorKeyboard.getLanguageKeyLabel(lang));
+ item.setTag(index);
+ item.setOnClickListener(this);
+ popupContainer.addView(item, index++);
+ }
+
+ popupContainer.measure(
+ MeasureSpec.makeMeasureSpec(getWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec(getHeight(), MeasureSpec.AT_MOST));
+
+ mLanguagesPopup = new PopupWindow(getContext());
+ mLanguagesPopup.setWidth(popupContainer.getMeasuredWidth());
+ mLanguagesPopup.setHeight(popupContainer.getMeasuredHeight());
+ mLanguagesPopup.setContentView(popupContainer);
+
+ int[] windowOffset = new int[2];
+ getLocationInWindow(windowOffset);
+ int popupX = popupKey.x + popupKey.width - popupContainer.getMeasuredWidth();
+ int popupY = popupKey.y - popupContainer.getMeasuredHeight();
+ final int x = popupX + popupContainer.getPaddingRight() + windowOffset[0];
+ final int y = popupY + popupContainer.getPaddingBottom() + windowOffset[1];
+ mLanguagesPopup.showAtLocation(this, Gravity.NO_GRAVITY, x, y);
+
+ View closeButton = popupContainer.findViewById(R.id.closeButton);
+ if (closeButton != null) closeButton.setOnClickListener(this);
+ }
+
+ mLanguagesKey = popupKey;
+ }
+
+ private void dismissLanguages() {
+ if (mLanguagesPopup != null) {
+ mLanguagesPopup.dismiss();
+ mLanguagesPopup = null;
+ mLanguagesKey = null;
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ super.onClick(v);
+
+ if (v.getTag() != null) {
+ if (mLanguagesKey.codes[0] == TranslatorKeyboard.KEYCODE_SOURCE_LANGUAGE ||
+ mLanguagesKey.codes[0] == TranslatorKeyboard.KEYCODE_TARGET_LANGUAGE) {
+ int keyCode = mLanguagesKey.codes[0] - ((Integer) v.getTag()) - 1;
+ getOnKeyboardActionListener().onKey(keyCode, new int[] {keyCode});
+ }
+ }
+
+ dismissLanguages();
+ }
+
+ public void closing() {
+ super.closing();
+ dismissLanguages();
+ }
+
+ @Override
+ protected boolean onLongPress(Key key) {
+ if (key.codes[0] == TranslatorKeyboard.KEYCODE_SOURCE_LANGUAGE ||
+ key.codes[0] == TranslatorKeyboard.KEYCODE_TARGET_LANGUAGE) {
+ showLanguageOptions(key);
+ return true;
+ } else {
+ return super.onLongPress(key);
+ }
+ }
+}