now the Android App has a translation keyboard which allows the translations to be done from inside another application
@@ -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>
|
||||
|
||||
BIN
src/ui/android/res/drawable-hdpi/btn_close.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/ui/android/res/drawable-hdpi/sym_keyboard_delete.png
Normal file
|
After Width: | Height: | Size: 885 B |
BIN
src/ui/android/res/drawable-hdpi/sym_keyboard_return.png
Normal file
|
After Width: | Height: | Size: 536 B |
BIN
src/ui/android/res/drawable-hdpi/sym_keyboard_search.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
src/ui/android/res/drawable-hdpi/sym_keyboard_shift.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/ui/android/res/drawable-hdpi/sym_keyboard_space.png
Normal file
|
After Width: | Height: | Size: 859 B |
BIN
src/ui/android/res/drawable-mdpi/sym_keyboard_delete.png
Normal file
|
After Width: | Height: | Size: 465 B |
BIN
src/ui/android/res/drawable-mdpi/sym_keyboard_done.png
Normal file
|
After Width: | Height: | Size: 771 B |
BIN
src/ui/android/res/drawable-mdpi/sym_keyboard_return.png
Normal file
|
After Width: | Height: | Size: 337 B |
BIN
src/ui/android/res/drawable-mdpi/sym_keyboard_search.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src/ui/android/res/drawable-mdpi/sym_keyboard_shift.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src/ui/android/res/drawable-mdpi/sym_keyboard_space.png
Normal file
|
After Width: | Height: | Size: 436 B |
9
src/ui/android/res/layout/input.xml
Normal file
@@ -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"
|
||||
/>
|
||||
20
src/ui/android/res/layout/keyboard_languages_options.xml
Normal file
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
76
src/ui/android/res/xml/cyrillic.xml
Normal file
@@ -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>
|
||||
6
src/ui/android/res/xml/method.xml
Normal file
@@ -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>
|
||||
5
src/ui/android/res/xml/popup_keyboard.xml
Normal file
@@ -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>
|
||||
74
src/ui/android/res/xml/qwerty.xml
Normal file
@@ -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>
|
||||
|
||||
73
src/ui/android/res/xml/symbols.xml
Normal file
@@ -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="&"/>
|
||||
<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="""/>
|
||||
<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>
|
||||
71
src/ui/android/res/xml/symbols_shift.xml
Normal file
@@ -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="<"/>
|
||||
<Key android:codes="62" android:keyLabel=">"/>
|
||||
<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>
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||