aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/res/values-land/dimens.xml6
-rw-r--r--java/res/values-land/keyboard-heights.xml34
-rw-r--r--java/res/values-sw600dp-land/dimens.xml7
-rw-r--r--java/res/values-sw600dp-land/keyboard-heights.xml28
-rw-r--r--java/res/values-sw600dp/dimens.xml7
-rw-r--r--java/res/values-sw600dp/keyboard-heights.xml28
-rw-r--r--java/res/values-sw768dp-land/dimens.xml6
-rw-r--r--java/res/values-sw768dp-land/keyboard-heights.xml28
-rw-r--r--java/res/values-sw768dp/dimens.xml6
-rw-r--r--java/res/values-sw768dp/keyboard-heights.xml28
-rw-r--r--java/res/values/attrs.xml5
-rw-r--r--java/res/values/dimens.xml6
-rw-r--r--java/res/values/keyboard-heights.xml34
-rw-r--r--java/res/values/styles.xml1
-rw-r--r--java/res/xml-sw600dp-land/kbd_thai.xml28
-rw-r--r--java/res/xml-sw600dp/kbd_thai.xml1
-rw-r--r--java/res/xml-sw768dp-land/kbd_thai.xml28
-rw-r--r--java/res/xml-sw768dp-land/kbd_thai_symbols.xml28
-rw-r--r--java/res/xml-sw768dp-land/kbd_thai_symbols_shift.xml28
-rw-r--r--java/res/xml-sw768dp/kbd_thai.xml28
-rw-r--r--java/res/xml-sw768dp/kbd_thai_symbols.xml1
-rw-r--r--java/res/xml-sw768dp/kbd_thai_symbols_shift.xml1
-rw-r--r--java/src/com/android/inputmethod/keyboard/Keyboard.java21
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java63
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java9
-rw-r--r--java/src/com/android/inputmethod/latin/ResearchLogger.java304
-rw-r--r--java/src/com/android/inputmethod/latin/Utils.java82
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java157
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java7
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java7
30 files changed, 882 insertions, 135 deletions
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 6cdcf891c..550d29f76 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -19,8 +19,9 @@
-->
<resources>
- <!-- keyboardHeight = key_height*4 + key_bottom_gap*3, key_height=0.260in -->
- <dimen name="keyboardHeight">1.100in</dimen>
+ <!-- Preferable keyboard height in absolute scale: 1.100in -->
+ <!-- This keyboardHeight value should match with keyboard-heights.xml -->
+ <dimen name="keyboardHeight">176.0dp</dimen>
<fraction name="minKeyboardHeight">45%p</fraction>
<!-- key_height + key_bottom_gap = popup_key_height -->
<!-- <dimen name="key_height">0.260in</dimen>-->
@@ -31,7 +32,6 @@
<fraction name="key_bottom_gap">4.330%p</fraction>
<fraction name="key_horizontal_gap">0.405%p</fraction>
- <dimen name="keyboardHeight_stone">0.984in</dimen>
<fraction name="key_bottom_gap_stone">5.010%p</fraction>
<fraction name="key_horizontal_gap_stone">1.159%p</fraction>
diff --git a/java/res/values-land/keyboard-heights.xml b/java/res/values-land/keyboard-heights.xml
new file mode 100644
index 000000000..12c3e3951
--- /dev/null
+++ b/java/res/values-land/keyboard-heights.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Preferable keyboard height in absolute scale: 1.100in -->
+<resources>
+ <!-- Build.HARDWARE,keyboard_height_in_dp -->
+ <string-array name="keyboard_heights" translatable="false">
+ <!-- Droid -->
+ <item>sholes,194.3333</item>
+ <!-- Nexus One -->
+ <item>mahimahi,186.2667</item>
+ <!-- Nexus S -->
+ <item>herring,171.9385</item>
+ <!-- Galaxy Nexus -->
+ <item>tuna,173.4207</item>
+ </string-array>
+</resources>
diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml
index 5dce47ee3..c6c6f2b3b 100644
--- a/java/res/values-sw600dp-land/dimens.xml
+++ b/java/res/values-sw600dp-land/dimens.xml
@@ -19,8 +19,9 @@
-->
<resources>
- <!-- keyboardHeight = key_height*4 + key_bottom_gap*3 -->
- <dimen name="keyboardHeight">45.0mm</dimen>
+ <!-- Preferable keyboard height in absolute scale: 45.0mm -->
+ <!-- This keyboardHeight value should match with keyboard-heights.xml -->
+ <dimen name="keyboardHeight">283.5dp</dimen>
<fraction name="minKeyboardHeight">45%p</fraction>
<fraction name="keyboard_top_padding">2.444%p</fraction>
@@ -28,13 +29,13 @@
<fraction name="key_bottom_gap">4.911%p</fraction>
<fraction name="key_horizontal_gap">1.284%p</fraction>
- <dimen name="keyboardHeight_stone">45.0mm</dimen>
<fraction name="key_bottom_gap_stone">4.355%p</fraction>
<fraction name="key_horizontal_gap_stone">1.505%p</fraction>
<fraction name="key_bottom_gap_gb">5.200%p</fraction>
<fraction name="key_horizontal_gap_gb">1.447%p</fraction>
+ <fraction name="key_bottom_gap_ics">4.0%p</fraction>
<fraction name="keyboard_bottom_padding_ics">0.0%p</fraction>
<dimen name="popup_key_height">13.0mm</dimen>
diff --git a/java/res/values-sw600dp-land/keyboard-heights.xml b/java/res/values-sw600dp-land/keyboard-heights.xml
new file mode 100644
index 000000000..93f9824d1
--- /dev/null
+++ b/java/res/values-sw600dp-land/keyboard-heights.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Preferable keyboard height in absolute scale: 45.0mm -->
+<resources>
+ <!-- Build.HARDWARE,keyboard_height_in_dp -->
+ <string-array name="keyboard_heights" translatable="false">
+ <!-- Xoom -->
+ <item>stingray,265.4378</item>
+ </string-array>
+</resources>
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index 0f256a302..ebe388263 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -19,8 +19,9 @@
-->
<resources>
- <!-- keyboardHeight = key_height*4 + key_bottom_gap*3 -->
- <dimen name="keyboardHeight">48.0mm</dimen>
+ <!-- Preferable keyboard height in absolute scale: 48.0mm -->
+ <!-- This keyboardHeight value should match with keyboard-heights.xml -->
+ <dimen name="keyboardHeight">302.4dp</dimen>
<fraction name="maxKeyboardHeight">50%p</fraction>
<fraction name="minKeyboardHeight">-35.0%p</fraction>
@@ -31,13 +32,13 @@
<fraction name="key_bottom_gap">3.750%p</fraction>
<fraction name="key_horizontal_gap">1.857%p</fraction>
- <dimen name="keyboardHeight_stone">48.0mm</dimen>
<fraction name="key_bottom_gap_stone">3.75%p</fraction>
<fraction name="key_horizontal_gap_stone">1.602%p</fraction>
<fraction name="key_bottom_gap_gb">4.625%p</fraction>
<fraction name="key_horizontal_gap_gb">2.113%p</fraction>
+ <fraction name="key_bottom_gap_ics">4.0%p</fraction>
<fraction name="keyboard_bottom_padding_ics">0.0%p</fraction>
<dimen name="more_keys_keyboard_key_horizontal_padding">6dp</dimen>
diff --git a/java/res/values-sw600dp/keyboard-heights.xml b/java/res/values-sw600dp/keyboard-heights.xml
new file mode 100644
index 000000000..77e52be2f
--- /dev/null
+++ b/java/res/values-sw600dp/keyboard-heights.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Preferable keyboard height in absolute scale: 48.0mm -->
+<resources>
+ <!-- Build.HARDWARE,keyboard_height_in_dp -->
+ <string-array name="keyboard_heights" translatable="false">
+ <!-- Xoom -->
+ <item>stingray,283.1337</item>
+ </string-array>
+</resources>
diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml
index 535c62308..597ed5102 100644
--- a/java/res/values-sw768dp-land/dimens.xml
+++ b/java/res/values-sw768dp-land/dimens.xml
@@ -19,8 +19,9 @@
-->
<resources>
- <!-- keyboardHeight = key_height*4 + key_bottom_gap*3, key_height=14.5mm -->
- <dimen name="keyboardHeight">58.0mm</dimen>
+ <!-- Preferable keyboard height in absolute scale: 58.0mm -->
+ <!-- This keyboardHeight value should match with keyboard-heights.xml -->
+ <dimen name="keyboardHeight">365.4dp</dimen>
<fraction name="minKeyboardHeight">45%p</fraction>
<fraction name="keyboard_top_padding">1.896%p</fraction>
@@ -29,7 +30,6 @@
<fraction name="key_bottom_gap">4.103%p</fraction>
<fraction name="key_horizontal_gap">1.034%p</fraction>
- <dimen name="keyboardHeight_stone">58.0mm</dimen>
<fraction name="key_bottom_gap_stone">3.379%p</fraction>
<fraction name="key_horizontal_gap_stone">1.062%p</fraction>
diff --git a/java/res/values-sw768dp-land/keyboard-heights.xml b/java/res/values-sw768dp-land/keyboard-heights.xml
new file mode 100644
index 000000000..692c5a0fb
--- /dev/null
+++ b/java/res/values-sw768dp-land/keyboard-heights.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Preferable keyboard height in absolute scale: 58.0mm -->
+<resources>
+ <!-- Build.HARDWARE,keyboard_height_in_dp -->
+ <string-array name="keyboard_heights" translatable="false">
+ <!-- Xoom -->
+ <item>stingray,342.1198</item>
+ </string-array>
+</resources>
diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml
index 7aefa26af..a9f0c00aa 100644
--- a/java/res/values-sw768dp/dimens.xml
+++ b/java/res/values-sw768dp/dimens.xml
@@ -19,8 +19,9 @@
-->
<resources>
- <!-- keyboardHeight = key_height*4 + key_bottom_gap*3, key_height=12mm -->
- <dimen name="keyboardHeight">48.0mm</dimen>
+ <!-- Preferable keyboard height in absolute scale: 48.0mm -->
+ <!-- This keyboardHeight value should match with keyboard-heights.xml -->
+ <dimen name="keyboardHeight">302.4dp</dimen>
<fraction name="maxKeyboardHeight">50%p</fraction>
<fraction name="minKeyboardHeight">-35.0%p</fraction>
@@ -30,7 +31,6 @@
<fraction name="key_bottom_gap">4.270%p</fraction>
<fraction name="key_horizontal_gap">1.551%p</fraction>
- <dimen name="keyboardHeight_stone">48.0mm</dimen>
<fraction name="key_bottom_gap_stone">3.75%p</fraction>
<fraction name="key_horizontal_gap_stone">1.059%p</fraction>
diff --git a/java/res/values-sw768dp/keyboard-heights.xml b/java/res/values-sw768dp/keyboard-heights.xml
new file mode 100644
index 000000000..77e52be2f
--- /dev/null
+++ b/java/res/values-sw768dp/keyboard-heights.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Preferable keyboard height in absolute scale: 48.0mm -->
+<resources>
+ <!-- Build.HARDWARE,keyboard_height_in_dp -->
+ <string-array name="keyboard_heights" translatable="false">
+ <!-- Xoom -->
+ <item>stingray,283.1337</item>
+ </string-array>
+</resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index cf55fbe4a..e33f0ba8a 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -202,9 +202,10 @@
<!-- Default height of a row (key height + vertical gap), in pixels or percentage of
keyboard height. -->
<attr name="rowHeight" format="dimension|fraction" />
- <!-- Default horizontal gap between keys. -->
+ <!-- Default horizontal gap between keys, in pixels or percentage of keyboard width. -->
<attr name="horizontalGap" format="dimension|fraction" />
- <!-- Default vertical gap between rows of keys. -->
+ <!-- Default vertical gap between rows of keys, in pixels or percentage of keyboard
+ height. -->
<attr name="verticalGap" format="dimension|fraction" />
<!-- More keys keyboard layout template -->
<attr name="moreKeysTemplate" format="reference" />
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 5f74fa746..9d64a618a 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -19,8 +19,9 @@
-->
<resources>
- <!-- keyboardHeight = row_height*4 + key_bottom_gap*3 -->
- <dimen name="keyboardHeight">1.285in</dimen>
+ <!-- Preferable keyboard height in absolute scale: 1.285in -->
+ <!-- This keyboardHeight value should match with keyboard-heights.xml -->
+ <dimen name="keyboardHeight">205.6dp</dimen>
<fraction name="maxKeyboardHeight">50%p</fraction>
<fraction name="minKeyboardHeight">-61.8%p</fraction>
@@ -35,7 +36,6 @@
<fraction name="key_bottom_gap">6.250%p</fraction>
<fraction name="key_horizontal_gap">1.352%p</fraction>
- <dimen name="keyboardHeight_stone">1.317in</dimen>
<fraction name="keyboard_top_padding_stone">1.556%p</fraction>
<fraction name="keyboard_bottom_padding_stone">0.778%p</fraction>
<fraction name="key_bottom_gap_stone">7.506%p</fraction>
diff --git a/java/res/values/keyboard-heights.xml b/java/res/values/keyboard-heights.xml
new file mode 100644
index 000000000..7d5b58372
--- /dev/null
+++ b/java/res/values/keyboard-heights.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Preferable keyboard height in absolute scale: 1.285in -->
+<resources>
+ <!-- Build.HARDWARE,keyboard_height_in_dp -->
+ <string-array name="keyboard_heights" translatable="false">
+ <!-- Droid -->
+ <item>sholes,227.0167</item>
+ <!-- Nexus One -->
+ <item>mahimahi,217.5932</item>
+ <!-- Nexus S -->
+ <item>herring,200.8554</item>
+ <!-- Galaxy Nexus -->
+ <item>tuna,202.5869</item>
+ </string-array>
+</resources>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 691f98ae2..b08ff3b90 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -173,7 +173,6 @@
>
<!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
<item name="themeId">6</item>
- <item name="keyboardHeight">@dimen/keyboardHeight_stone</item>
<item name="keyboardTopPadding">@fraction/keyboard_top_padding_stone</item>
<item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding_stone</item>
<item name="horizontalGap">@fraction/key_horizontal_gap_stone</item>
diff --git a/java/res/xml-sw600dp-land/kbd_thai.xml b/java/res/xml-sw600dp-land/kbd_thai.xml
new file mode 100644
index 000000000..ac36ea5ff
--- /dev/null
+++ b/java/res/xml-sw600dp-land/kbd_thai.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:rowHeight="20%p"
+ latin:verticalGap="3.20%p"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_thai" />
+</Keyboard>
diff --git a/java/res/xml-sw600dp/kbd_thai.xml b/java/res/xml-sw600dp/kbd_thai.xml
index 06d98e19d..ac36ea5ff 100644
--- a/java/res/xml-sw600dp/kbd_thai.xml
+++ b/java/res/xml-sw600dp/kbd_thai.xml
@@ -21,6 +21,7 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:rowHeight="20%p"
+ latin:verticalGap="3.20%p"
>
<include
latin:keyboardLayout="@xml/rows_thai" />
diff --git a/java/res/xml-sw768dp-land/kbd_thai.xml b/java/res/xml-sw768dp-land/kbd_thai.xml
new file mode 100644
index 000000000..4bfc9cb48
--- /dev/null
+++ b/java/res/xml-sw768dp-land/kbd_thai.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:rowHeight="20%p"
+ latin:verticalGap="2.65%p"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_thai" />
+</Keyboard>
diff --git a/java/res/xml-sw768dp-land/kbd_thai_symbols.xml b/java/res/xml-sw768dp-land/kbd_thai_symbols.xml
new file mode 100644
index 000000000..a3feeaae3
--- /dev/null
+++ b/java/res/xml-sw768dp-land/kbd_thai_symbols.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:rowHeight="20%p"
+ latin:verticalGap="2.65%p"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_thai_symbols" />
+</Keyboard>
diff --git a/java/res/xml-sw768dp-land/kbd_thai_symbols_shift.xml b/java/res/xml-sw768dp-land/kbd_thai_symbols_shift.xml
new file mode 100644
index 000000000..8b4a8ea5b
--- /dev/null
+++ b/java/res/xml-sw768dp-land/kbd_thai_symbols_shift.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:rowHeight="20%p"
+ latin:verticalGap="2.65%p"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_thai_symbols_shift" />
+</Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_thai.xml b/java/res/xml-sw768dp/kbd_thai.xml
new file mode 100644
index 000000000..dd0ac36a6
--- /dev/null
+++ b/java/res/xml-sw768dp/kbd_thai.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:rowHeight="20%p"
+ latin:verticalGap="2.95%p"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_thai" />
+</Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_thai_symbols.xml b/java/res/xml-sw768dp/kbd_thai_symbols.xml
index f02033431..91cf8084f 100644
--- a/java/res/xml-sw768dp/kbd_thai_symbols.xml
+++ b/java/res/xml-sw768dp/kbd_thai_symbols.xml
@@ -21,6 +21,7 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:rowHeight="20%p"
+ latin:verticalGap="2.95%p"
>
<include
latin:keyboardLayout="@xml/rows_thai_symbols" />
diff --git a/java/res/xml-sw768dp/kbd_thai_symbols_shift.xml b/java/res/xml-sw768dp/kbd_thai_symbols_shift.xml
index af24da0f5..85745ac3d 100644
--- a/java/res/xml-sw768dp/kbd_thai_symbols_shift.xml
+++ b/java/res/xml-sw768dp/kbd_thai_symbols_shift.xml
@@ -21,6 +21,7 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:rowHeight="20%p"
+ latin:verticalGap="2.95%p"
>
<include
latin:keyboardLayout="@xml/rows_thai_symbols_shift" />
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 2b1cc43cd..07b9c1e8c 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -31,6 +31,7 @@ import com.android.inputmethod.keyboard.internal.KeyStyles;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.XmlParseUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -715,22 +716,30 @@ public class Keyboard {
R.styleable.Keyboard_Key);
try {
final int displayHeight = mDisplayMetrics.heightPixels;
- final int keyboardHeight = (int)keyboardAttr.getDimension(
- R.styleable.Keyboard_keyboardHeight, displayHeight / 2);
- final int maxKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr,
+ final String keyboardHeightString = Utils.getDeviceOverrideValue(
+ mResources, R.array.keyboard_heights, null);
+ final float keyboardHeight;
+ if (keyboardHeightString != null) {
+ keyboardHeight = Float.parseFloat(keyboardHeightString)
+ * mDisplayMetrics.density;
+ } else {
+ keyboardHeight = keyboardAttr.getDimension(
+ R.styleable.Keyboard_keyboardHeight, displayHeight / 2);
+ }
+ final float maxKeyboardHeight = getDimensionOrFraction(keyboardAttr,
R.styleable.Keyboard_maxKeyboardHeight, displayHeight, displayHeight / 2);
- int minKeyboardHeight = (int)getDimensionOrFraction(keyboardAttr,
+ float minKeyboardHeight = getDimensionOrFraction(keyboardAttr,
R.styleable.Keyboard_minKeyboardHeight, displayHeight, displayHeight / 2);
if (minKeyboardHeight < 0) {
// Specified fraction was negative, so it should be calculated against display
// width.
- minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr,
+ minKeyboardHeight = -getDimensionOrFraction(keyboardAttr,
R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2);
}
final Params params = mParams;
// Keyboard height will not exceed maxKeyboardHeight and will not be less than
// minKeyboardHeight.
- params.mOccupiedHeight = Math.max(
+ params.mOccupiedHeight = (int)Math.max(
Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
params.mOccupiedWidth = params.mId.mWidth;
params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr,
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index b66d1661d..3f6c37477 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -46,6 +46,7 @@ import com.android.inputmethod.keyboard.internal.KeySpecParser;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.ResearchLogger;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.StringUtils;
import com.android.inputmethod.latin.SubtypeUtils;
@@ -66,6 +67,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
SuddenJumpingTouchEventHandler.ProcessMotionEvent {
private static final String TAG = LatinKeyboardView.class.getSimpleName();
+ // TODO: Kill process when the usability study mode was changed.
+ private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
+
/** Listener for {@link KeyboardActionListener}. */
private KeyboardActionListener mKeyboardActionListener;
@@ -653,8 +657,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final int index = me.getActionIndex();
final int id = me.getPointerId(index);
final int x, y;
- final float size = me.getSize(index);
- final float pressure = me.getPressure(index);
if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) {
x = mMoreKeysPanel.translateX((int)me.getX(index));
y = mMoreKeysPanel.translateY((int)me.getY(index));
@@ -662,10 +664,44 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
x = (int)me.getX(index);
y = (int)me.getY(index);
}
- if (LatinImeLogger.sUsabilityStudy) {
+ if (ENABLE_USABILITY_STUDY_LOG) {
+ final String eventTag;
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ eventTag = "[Up]";
+ break;
+ case MotionEvent.ACTION_DOWN:
+ eventTag = "[Down]";
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ eventTag = "[PointerUp]";
+ break;
+ case MotionEvent.ACTION_POINTER_DOWN:
+ eventTag = "[PointerDown]";
+ break;
+ case MotionEvent.ACTION_MOVE: // Skip this as being logged below
+ eventTag = "";
+ break;
+ default:
+ eventTag = "[Action" + action + "]";
+ break;
+ }
+ if (!TextUtils.isEmpty(eventTag)) {
+ final float size = me.getSize(index);
+ final float pressure = me.getPressure(index);
+ UsabilityStudyLogUtils.getInstance().write(
+ eventTag + eventTime + "," + id + "," + x + "," + y + ","
+ + size + "," + pressure);
+ }
+ }
+ if (ResearchLogger.sIsLogging) {
+ // TODO: remove redundant calculations of size and pressure by
+ // removing UsabilityStudyLog code once the ResearchLogger is mature enough
+ final float size = me.getSize(index);
+ final float pressure = me.getPressure(index);
if (action != MotionEvent.ACTION_MOVE) {
// Skip ACTION_MOVE events as they are logged below
- UsabilityStudyLogUtils.getInstance().writeMotionEvent(action, eventTime, id, x,
+ ResearchLogger.getInstance().logMotionEvent(action, eventTime, id, x,
y, size, pressure);
}
}
@@ -714,8 +750,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (action == MotionEvent.ACTION_MOVE) {
for (int i = 0; i < pointerCount; i++) {
+ final int pointerId = me.getPointerId(i);
final PointerTracker tracker = PointerTracker.getPointerTracker(
- me.getPointerId(i), this);
+ pointerId, this);
final int px, py;
if (mMoreKeysPanel != null
&& tracker.mPointerId == mMoreKeysPanelPointerTrackerId) {
@@ -726,9 +763,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
py = (int)me.getY(i);
}
tracker.onMoveEvent(px, py, eventTime);
- if (LatinImeLogger.sUsabilityStudy) {
- UsabilityStudyLogUtils.getInstance().writeMotionEvent(action, eventTime, id,
- px, py, size, pressure);
+ if (ENABLE_USABILITY_STUDY_LOG) {
+ final float pointerSize = me.getSize(i);
+ final float pointerPressure = me.getPressure(i);
+ UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + ","
+ + pointerId + "," + px + "," + py + ","
+ + pointerSize + "," + pointerPressure);
+ }
+ if (ResearchLogger.sIsLogging) {
+ // TODO: earlier comment about redundant calculations applies here too
+ final float pointerSize = me.getSize(i);
+ final float pointerPressure = me.getPressure(i);
+ ResearchLogger.getInstance().logMotionEvent(action, eventTime, pointerId,
+ px, py, pointerSize, pointerPressure);
}
}
} else {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e07bba065..7272006a2 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -439,6 +439,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mPrefs = prefs;
LatinImeLogger.init(this, prefs);
+ ResearchLogger.init(this, prefs);
LanguageSwitcherProxy.init(this, prefs);
InputMethodManagerCompatWrapper.init(this);
SubtypeSwitcher.init(this);
@@ -1006,10 +1007,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
final int touchHeight = inputView.getHeight() + extraHeight
// Extend touchable region below the keyboard.
+ EXTENDED_TOUCHABLE_REGION_HEIGHT;
- if (DEBUG) {
- Log.d(TAG, "Touchable region: y=" + touchY + " width=" + touchWidth
- + " height=" + touchHeight);
- }
setTouchableRegionCompat(outInsets, 0, touchY, touchWidth, touchHeight);
}
outInsets.contentTopInsets = touchY;
@@ -1267,8 +1264,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
}
mLastKeyTime = when;
- if (LatinImeLogger.sUsabilityStudy) {
- UsabilityStudyLogUtils.getInstance().writeKeyEvent(primaryCode, x, y);
+ if (ResearchLogger.sIsLogging) {
+ ResearchLogger.getInstance().logKeyEvent(primaryCode, x, y);
}
final KeyboardSwitcher switcher = mKeyboardSwitcher;
diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java
new file mode 100644
index 000000000..6ba9118d6
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.SharedPreferences;
+import android.inputmethodservice.InputMethodService;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.inputmethod.keyboard.Keyboard;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Logs the use of the LatinIME keyboard.
+ *
+ * This class logs operations on the IME keyboard, including what the user has typed.
+ * Data is stored locally in a file in app-specific storage.
+ *
+ * This functionality is off by default.
+ */
+public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
+ private static final String TAG = ResearchLogger.class.getSimpleName();
+ private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode";
+
+ private static final ResearchLogger sInstance = new ResearchLogger(new LogFileManager());
+ public static boolean sIsLogging = false;
+ private final Handler mLoggingHandler;
+ private InputMethodService mIms;
+ private final Date mDate;
+ private final SimpleDateFormat mDateFormat;
+
+ /**
+ * Isolates management of files. This variable should never be null, but can be changed
+ * to support testing.
+ */
+ private LogFileManager mLogFileManager;
+
+ /**
+ * Manages the file(s) that stores the logs.
+ *
+ * Handles creation, deletion, and provides Readers, Writers, and InputStreams to access
+ * the logs.
+ */
+ public static class LogFileManager {
+ private static final String DEFAULT_FILENAME = "log.txt";
+ private static final String DEFAULT_LOG_DIRECTORY = "researchLogger";
+
+ private static final long LOGFILE_PURGE_INTERVAL = 1000 * 60 * 60 * 24;
+
+ private InputMethodService mIms;
+ private File mFile;
+ private PrintWriter mPrintWriter;
+
+ /* package */ LogFileManager() {
+ }
+
+ public void init(InputMethodService ims) {
+ mIms = ims;
+ }
+
+ public synchronized void createLogFile() {
+ try {
+ createLogFile(DEFAULT_LOG_DIRECTORY, DEFAULT_FILENAME);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, e);
+ }
+ }
+
+ public synchronized void createLogFile(String dir, String filename)
+ throws FileNotFoundException {
+ if (mIms == null) {
+ Log.w(TAG, "InputMethodService is not configured. Logging is off.");
+ return;
+ }
+ File filesDir = mIms.getFilesDir();
+ if (filesDir == null || !filesDir.exists()) {
+ Log.w(TAG, "Storage directory does not exist. Logging is off.");
+ return;
+ }
+ File directory = new File(filesDir, dir);
+ if (!directory.exists()) {
+ boolean wasCreated = directory.mkdirs();
+ if (!wasCreated) {
+ Log.w(TAG, "Log directory cannot be created. Logging is off.");
+ return;
+ }
+ }
+
+ close();
+ mFile = new File(directory, filename);
+ boolean append = true;
+ if (mFile.exists() && mFile.lastModified() + LOGFILE_PURGE_INTERVAL <
+ System.currentTimeMillis()) {
+ append = false;
+ }
+ mPrintWriter = new PrintWriter(new FileOutputStream(mFile, append), true);
+ }
+
+ public synchronized boolean append(String s) {
+ if (mPrintWriter == null) {
+ Log.w(TAG, "PrintWriter is null");
+ return false;
+ } else {
+ mPrintWriter.print(s);
+ return !mPrintWriter.checkError();
+ }
+ }
+
+ public synchronized void reset() {
+ if (mPrintWriter != null) {
+ mPrintWriter.close();
+ mPrintWriter = null;
+ }
+ if (mFile != null && mFile.exists()) {
+ mFile.delete();
+ mFile = null;
+ }
+ }
+
+ public synchronized void close() {
+ if (mPrintWriter != null) {
+ mPrintWriter.close();
+ mPrintWriter = null;
+ mFile = null;
+ }
+ }
+ }
+
+ private ResearchLogger(LogFileManager logFileManager) {
+ mDate = new Date();
+ mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ");
+
+ HandlerThread handlerThread = new HandlerThread("ResearchLogger logging task",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ handlerThread.start();
+ mLoggingHandler = new Handler(handlerThread.getLooper());
+ mLogFileManager = logFileManager;
+ }
+
+ public static ResearchLogger getInstance() {
+ return sInstance;
+ }
+
+ public static void init(InputMethodService ims, SharedPreferences prefs) {
+ sInstance.initInternal(ims, prefs);
+ }
+
+ public void initInternal(InputMethodService ims, SharedPreferences prefs) {
+ mIms = ims;
+ if (mLogFileManager != null) {
+ mLogFileManager.init(ims);
+ mLogFileManager.createLogFile();
+ }
+ if (prefs != null) {
+ sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
+ }
+ prefs.registerOnSharedPreferenceChangeListener(this);
+ }
+
+ /**
+ * Change to a different logFileManager. Will not allow it to be set to null.
+ */
+ /* package */ void setLogFileManager(ResearchLogger.LogFileManager manager) {
+ if (manager == null) {
+ Log.w(TAG, "warning: trying to set null logFileManager. ignoring.");
+ } else {
+ mLogFileManager = manager;
+ }
+ }
+
+ /**
+ * Represents a category of logging events that share the same subfield structure.
+ */
+ private static enum LogGroup {
+ MOTION_EVENT("m"),
+ KEY("k"),
+ CORRECTION("c"),
+ STATE_CHANGE("s");
+
+ private final String mLogString;
+
+ private LogGroup(String logString) {
+ mLogString = logString;
+ }
+ }
+
+ public void logMotionEvent(final int action, final long eventTime, final int id,
+ final int x, final int y, final float size, final float pressure) {
+ final String eventTag;
+ switch (action) {
+ case MotionEvent.ACTION_CANCEL: eventTag = "[Cancel]"; break;
+ case MotionEvent.ACTION_UP: eventTag = "[Up]"; break;
+ case MotionEvent.ACTION_DOWN: eventTag = "[Down]"; break;
+ case MotionEvent.ACTION_POINTER_UP: eventTag = "[PointerUp]"; break;
+ case MotionEvent.ACTION_POINTER_DOWN: eventTag = "[PointerDown]"; break;
+ case MotionEvent.ACTION_MOVE: eventTag = "[Move]"; break;
+ case MotionEvent.ACTION_OUTSIDE: eventTag = "[Outside]"; break;
+ default: eventTag = "[Action" + action + "]"; break;
+ }
+ if (!TextUtils.isEmpty(eventTag)) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(eventTag);
+ sb.append('\t'); sb.append(eventTime);
+ sb.append('\t'); sb.append(id);
+ sb.append('\t'); sb.append(x);
+ sb.append('\t'); sb.append(y);
+ sb.append('\t'); sb.append(size);
+ sb.append('\t'); sb.append(pressure);
+ write(LogGroup.MOTION_EVENT, sb.toString());
+ }
+ }
+
+ public void logKeyEvent(int code, int x, int y) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(Keyboard.printableCode(code));
+ sb.append('\t'); sb.append(x);
+ sb.append('\t'); sb.append(y);
+ write(LogGroup.KEY, sb.toString());
+
+ LatinImeLogger.onPrintAllUsabilityStudyLogs();
+ }
+
+ public void logCorrection(String subgroup, String before, String after, int position) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(subgroup);
+ sb.append('\t'); sb.append(before);
+ sb.append('\t'); sb.append(after);
+ sb.append('\t'); sb.append(position);
+ write(LogGroup.CORRECTION, sb.toString());
+ }
+
+ public void logStateChange(String subgroup, String details) {
+ write(LogGroup.STATE_CHANGE, subgroup + "\t" + details);
+ }
+
+ private void write(final LogGroup logGroup, final String log) {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ final long currentTime = System.currentTimeMillis();
+ mDate.setTime(currentTime);
+ final long upTime = SystemClock.uptimeMillis();
+
+ final String printString = String.format("%s\t%d\t%s\t%s\n",
+ mDateFormat.format(mDate), upTime, logGroup.mLogString, log);
+ if (LatinImeLogger.sDBG) {
+ Log.d(TAG, "Write: " + '[' + logGroup.mLogString + ']' + log);
+ }
+ if (mLogFileManager.append(printString)) {
+ // success
+ } else {
+ if (LatinImeLogger.sDBG) {
+ Log.w(TAG, "Unable to write to log.");
+ }
+ }
+ }
+ });
+ }
+
+ public void clearAll() {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (LatinImeLogger.sDBG) {
+ Log.d(TAG, "Delete log file.");
+ }
+ mLogFileManager.reset();
+ }
+ });
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ if (key == null || prefs == null) {
+ return;
+ }
+ sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index a3589da0a..be64c2fd8 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -220,6 +220,7 @@ public class Utils {
}
public static class UsabilityStudyLogUtils {
+ // TODO: remove code duplication with ResearchLog class
private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
private static final String FILENAME = "log.txt";
private static final UsabilityStudyLogUtils sInstance =
@@ -262,73 +263,28 @@ public class Utils {
}
}
- /**
- * Represents a category of logging events that share the same subfield structure.
- */
- public static enum LogGroup {
- MOTION_EVENT("m"),
- KEY("k"),
- CORRECTION("c"),
- STATE_CHANGE("s");
-
- private final String mLogString;
-
- private LogGroup(String logString) {
- mLogString = logString;
- }
+ public static void writeBackSpace(int x, int y) {
+ UsabilityStudyLogUtils.getInstance().write("<backspace>\t" + x + "\t" + y);
}
- public void writeMotionEvent(final int action, final long eventTime, final int id,
- final int x, final int y, final float size, final float pressure) {
- final String eventTag;
- switch (action) {
- case MotionEvent.ACTION_CANCEL: eventTag = "[Cancel]"; break;
- case MotionEvent.ACTION_UP: eventTag = "[Up]"; break;
- case MotionEvent.ACTION_DOWN: eventTag = "[Down]"; break;
- case MotionEvent.ACTION_POINTER_UP: eventTag = "[PointerUp]"; break;
- case MotionEvent.ACTION_POINTER_DOWN: eventTag = "[PointerDown]"; break;
- case MotionEvent.ACTION_MOVE: eventTag = "[Move]"; break;
- case MotionEvent.ACTION_OUTSIDE: eventTag = "[Outside]"; break;
- default: eventTag = "[Action" + action + "]"; break;
- }
- if (!TextUtils.isEmpty(eventTag)) {
- StringBuilder sb = new StringBuilder();
- sb.append(eventTag);
- sb.append('\t'); sb.append(eventTime);
- sb.append('\t'); sb.append(id);
- sb.append('\t'); sb.append(x);
- sb.append('\t'); sb.append(y);
- sb.append('\t'); sb.append(size);
- sb.append('\t'); sb.append(pressure);
- write(LogGroup.MOTION_EVENT, sb.toString());
+ public void writeChar(char c, int x, int y) {
+ String inputChar = String.valueOf(c);
+ switch (c) {
+ case '\n':
+ inputChar = "<enter>";
+ break;
+ case '\t':
+ inputChar = "<tab>";
+ break;
+ case ' ':
+ inputChar = "<space>";
+ break;
}
- }
-
- public void writeKeyEvent(int code, int x, int y) {
- final StringBuilder sb = new StringBuilder();
- sb.append(Keyboard.printableCode(code));
- sb.append('\t'); sb.append(x);
- sb.append('\t'); sb.append(y);
- write(LogGroup.KEY, sb.toString());
-
- // TODO: replace with a cleaner flush+retrieve mechanism
+ UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y);
LatinImeLogger.onPrintAllUsabilityStudyLogs();
}
- public void writeCorrection(String subgroup, String before, String after, int position) {
- final StringBuilder sb = new StringBuilder();
- sb.append(subgroup);
- sb.append('\t'); sb.append(before);
- sb.append('\t'); sb.append(after);
- sb.append('\t'); sb.append(position);
- write(LogGroup.CORRECTION, sb.toString());
- }
-
- public void writeStateChange(String subgroup, String details) {
- write(LogGroup.STATE_CHANGE, subgroup + "\t" + details);
- }
-
- private void write(final LogGroup logGroup, final String log) {
+ public void write(final String log) {
mLoggingHandler.post(new Runnable() {
@Override
public void run() {
@@ -336,8 +292,8 @@ public class Utils {
final long currentTime = System.currentTimeMillis();
mDate.setTime(currentTime);
- final String printString = String.format("%s\t%d\t%s\t%s\n",
- mDateFormat.format(mDate), currentTime, logGroup.mLogString, log);
+ final String printString = String.format("%s\t%d\t%s\n",
+ mDateFormat.format(mDate), currentTime, log);
if (LatinImeLogger.sDBG) {
Log.d(USABILITY_TAG, "Write: " + log);
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 70530c338..64fcd7f1a 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -59,7 +59,7 @@ public class FusionDictionary implements Iterable<Word> {
*/
public static class WeightedString {
final String mWord;
- final int mFrequency;
+ int mFrequency;
public WeightedString(String word, int frequency) {
mWord = word;
mFrequency = frequency;
@@ -94,10 +94,10 @@ public class FusionDictionary implements Iterable<Word> {
public static class CharGroup {
public static final int NOT_A_TERMINAL = -1;
final int mChars[];
- final ArrayList<WeightedString> mShortcutTargets;
- final ArrayList<WeightedString> mBigrams;
- final int mFrequency; // NOT_A_TERMINAL == mFrequency indicates this is not a terminal.
- final boolean mIsShortcutOnly; // Only valid if this is a terminal.
+ ArrayList<WeightedString> mShortcutTargets;
+ ArrayList<WeightedString> mBigrams;
+ int mFrequency; // NOT_A_TERMINAL == mFrequency indicates this is not a terminal.
+ boolean mIsShortcutOnly; // Only valid if this is a terminal.
Node mChildren;
// The two following members to help with binary generation
int mCachedSize;
@@ -146,6 +146,102 @@ public class FusionDictionary implements Iterable<Word> {
assert(mChars.length > 0);
return 1 < mChars.length;
}
+
+ /**
+ * Adds a word to the bigram list. Updates the frequency if the word already
+ * exists.
+ */
+ public void addBigram(final String word, final int frequency) {
+ if (mBigrams == null) {
+ mBigrams = new ArrayList<WeightedString>();
+ }
+ WeightedString bigram = getBigram(word);
+ if (bigram != null) {
+ bigram.mFrequency = frequency;
+ } else {
+ bigram = new WeightedString(word, frequency);
+ mBigrams.add(bigram);
+ }
+ }
+
+ /**
+ * Gets the shortcut target for the given word. Returns null if the word is not in the
+ * shortcut list.
+ */
+ public WeightedString getShortcut(final String word) {
+ if (mShortcutTargets != null) {
+ final int size = mShortcutTargets.size();
+ for (int i = 0; i < size; ++i) {
+ WeightedString shortcut = mShortcutTargets.get(i);
+ if (shortcut.mWord.equals(word)) {
+ return shortcut;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the bigram for the given word.
+ * Returns null if the word is not in the bigrams list.
+ */
+ public WeightedString getBigram(final String word) {
+ if (mBigrams != null) {
+ final int size = mBigrams.size();
+ for (int i = 0; i < size; ++i) {
+ WeightedString bigram = mBigrams.get(i);
+ if (bigram.mWord.equals(word)) {
+ return bigram;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Updates the CharGroup with the given properties. Adds the shortcut and bigram lists to
+ * the existing ones if any. Note: unigram, bigram, and shortcut frequencies are only
+ * updated if they are higher than the existing ones.
+ */
+ public void update(int frequency, ArrayList<WeightedString> shortcutTargets,
+ ArrayList<WeightedString> bigrams, boolean isShortcutOnly) {
+ if (frequency > mFrequency) {
+ mFrequency = frequency;
+ }
+ if (shortcutTargets != null) {
+ if (mShortcutTargets == null) {
+ mShortcutTargets = shortcutTargets;
+ } else {
+ final int size = shortcutTargets.size();
+ for (int i = 0; i < size; ++i) {
+ final WeightedString shortcut = shortcutTargets.get(i);
+ final WeightedString existingShortcut = getShortcut(shortcut.mWord);
+ if (existingShortcut == null) {
+ mShortcutTargets.add(shortcut);
+ } else if (existingShortcut.mFrequency < shortcut.mFrequency) {
+ existingShortcut.mFrequency = shortcut.mFrequency;
+ }
+ }
+ }
+ }
+ if (bigrams != null) {
+ if (mBigrams == null) {
+ mBigrams = bigrams;
+ } else {
+ final int size = bigrams.size();
+ for (int i = 0; i < size; ++i) {
+ final WeightedString bigram = bigrams.get(i);
+ final WeightedString existingBigram = getBigram(bigram.mWord);
+ if (existingBigram == null) {
+ mBigrams.add(bigram);
+ } else if (existingBigram.mFrequency < bigram.mFrequency) {
+ existingBigram.mFrequency = bigram.mFrequency;
+ }
+ }
+ }
+ }
+ mIsShortcutOnly = isShortcutOnly;
+ }
}
/**
@@ -259,6 +355,27 @@ public class FusionDictionary implements Iterable<Word> {
}
/**
+ * Helper method to add a new bigram to the dictionary.
+ *
+ * @param word1 the previous word of the context
+ * @param word2 the next word of the context
+ * @param frequency the bigram frequency
+ */
+ public void setBigram(final String word1, final String word2, final int frequency) {
+ CharGroup charGroup = findWordInTree(mRoot, word1);
+ if (charGroup != null) {
+ final CharGroup charGroup2 = findWordInTree(mRoot, word2);
+ if (charGroup2 == null) {
+ // TODO: refactor with the identical code in addNeutralWords
+ add(getCodePoints(word2), 0, null, null, false /* isShortcutOnly */);
+ }
+ charGroup.addBigram(word2, frequency);
+ } else {
+ throw new RuntimeException("First word of bigram not found");
+ }
+ }
+
+ /**
* Add a word to this dictionary.
*
* The shortcuts and bigrams, if any, have to be in the dictionary already. If they aren't,
@@ -306,17 +423,9 @@ public class FusionDictionary implements Iterable<Word> {
if (differentCharIndex == currentGroup.mChars.length) {
if (charIndex + differentCharIndex >= word.length) {
// The new word is a prefix of an existing word, but the node on which it
- // should end already exists as is.
- if (currentGroup.mFrequency > 0) {
- throw new RuntimeException("Such a word already exists in the dictionary : "
- + new String(word, 0, word.length));
- } else {
- final CharGroup newNode = new CharGroup(currentGroup.mChars,
- shortcutTargets, bigrams, frequency, currentGroup.mChildren,
- isShortcutOnly);
- currentNode.mData.set(nodeIndex, newNode);
- checkStack(currentNode);
- }
+ // should end already exists as is. Since the old CharNode was not a terminal,
+ // make it one by filling in its frequency and other attributes
+ currentGroup.update(frequency, shortcutTargets, bigrams, isShortcutOnly);
} else {
// The new word matches the full old word and extends past it.
// We only have to create a new node and add it to the end of this.
@@ -328,19 +437,9 @@ public class FusionDictionary implements Iterable<Word> {
}
} else {
if (0 == differentCharIndex) {
- // Exact same word. Check the frequency is 0 or NOT_A_TERMINAL, and update.
- if (0 != frequency) {
- if (0 < currentGroup.mFrequency) {
- throw new RuntimeException("This word already exists with frequency "
- + currentGroup.mFrequency + " : "
- + new String(word, 0, word.length));
- }
- final CharGroup newGroup = new CharGroup(word,
- currentGroup.mShortcutTargets, currentGroup.mBigrams,
- frequency, currentGroup.mChildren,
- currentGroup.mIsShortcutOnly && isShortcutOnly);
- currentNode.mData.set(nodeIndex, newGroup);
- }
+ // Exact same word. Update the frequency if higher. This will also add the
+ // new bigrams to the existing bigram list if it already exists.
+ currentGroup.update(frequency, shortcutTargets, bigrams, isShortcutOnly);
} else {
// Partial prefix match only. We have to replace the current node with a node
// containing the current prefix and create two new ones for the tails.
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 973a448ee..cd34ba832 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -574,7 +574,12 @@ public class AndroidSpellCheckerService extends SpellCheckerService
// The getXYForCodePointAndScript method returns (Y << 16) + X
final int xy = SpellCheckerProximityInfo.getXYForCodePointAndScript(
codePoint, mScript);
- composer.add(codePoint, xy & 0xFFFF, xy >> 16, null);
+ if (SpellCheckerProximityInfo.NOT_A_COORDINATE_PAIR == xy) {
+ composer.add(codePoint, WordComposer.NOT_A_COORDINATE,
+ WordComposer.NOT_A_COORDINATE, null);
+ } else {
+ composer.add(codePoint, xy & 0xFFFF, xy >> 16, null);
+ }
}
final int capitalizeType = getCapitalizationType(text);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
index 7627700dd..0103e8423 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerProximityInfo.java
@@ -35,6 +35,9 @@ public class SpellCheckerProximityInfo {
// The number of rows in the grid used by the spell checker.
final public static int PROXIMITY_GRID_HEIGHT = 3;
+ final private static int NOT_AN_INDEX = -1;
+ final public static int NOT_A_COORDINATE_PAIR = -1;
+
// Helper methods
final protected static void buildProximityIndices(final int[] proximity,
final TreeMap<Integer, Integer> indices) {
@@ -45,7 +48,7 @@ public class SpellCheckerProximityInfo {
final protected static int computeIndex(final int characterCode,
final TreeMap<Integer, Integer> indices) {
final Integer result = indices.get(characterCode);
- if (null == result) return -1;
+ if (null == result) return NOT_AN_INDEX;
return result;
}
@@ -196,8 +199,10 @@ public class SpellCheckerProximityInfo {
// Returns (Y << 16) + X to avoid creating a temporary object. This is okay because
// X and Y are limited to PROXIMITY_GRID_WIDTH resp. PROXIMITY_GRID_HEIGHT which is very
// inferior to 1 << 16
+ // As an exception, this returns NOT_A_COORDINATE_PAIR if the key is not on the grid
public static int getXYForCodePointAndScript(final int codePoint, final int script) {
final int index = getIndexOfCodeForScript(codePoint, script);
+ if (NOT_AN_INDEX == index) return NOT_A_COORDINATE_PAIR;
final int y = index / PROXIMITY_GRID_WIDTH;
final int x = index % PROXIMITY_GRID_WIDTH;
if (y > PROXIMITY_GRID_HEIGHT) {