summaryrefslogtreecommitdiffstats
path: root/samples/SoftKeyboard
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:29:09 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:29:09 -0800
commit52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98 (patch)
tree2eb01432fa3da41550dd622d29fb672509122b51 /samples/SoftKeyboard
parentd4aee0c0caa00aa02d4c50ed28151591ac0456b5 (diff)
downloadandroid_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.tar.gz
android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.tar.bz2
android_development-52d4c30ca52320ec92d1d1ddc8db3f07f69c4f98.zip
auto import from //depot/cupcake/@135843
Diffstat (limited to 'samples/SoftKeyboard')
-rwxr-xr-xsamples/SoftKeyboard/Android.mk12
-rwxr-xr-xsamples/SoftKeyboard/AndroidManifest.xml12
-rw-r--r--samples/SoftKeyboard/res/drawable/sym_keyboard_delete.pngbin0 -> 465 bytes
-rwxr-xr-xsamples/SoftKeyboard/res/drawable/sym_keyboard_done.pngbin0 -> 771 bytes
-rw-r--r--samples/SoftKeyboard/res/drawable/sym_keyboard_return.pngbin0 -> 337 bytes
-rwxr-xr-xsamples/SoftKeyboard/res/drawable/sym_keyboard_search.pngbin0 -> 1029 bytes
-rw-r--r--samples/SoftKeyboard/res/drawable/sym_keyboard_shift.pngbin0 -> 1029 bytes
-rw-r--r--samples/SoftKeyboard/res/drawable/sym_keyboard_space.pngbin0 -> 436 bytes
-rwxr-xr-xsamples/SoftKeyboard/res/layout/input.xml27
-rw-r--r--samples/SoftKeyboard/res/values-land/dimens.xml23
-rw-r--r--samples/SoftKeyboard/res/values/colors.xml25
-rw-r--r--samples/SoftKeyboard/res/values/dimens.xml25
-rw-r--r--samples/SoftKeyboard/res/values/strings.xml31
-rw-r--r--samples/SoftKeyboard/res/xml/method.xml23
-rwxr-xr-xsamples/SoftKeyboard/res/xml/qwerty.xml82
-rwxr-xr-xsamples/SoftKeyboard/res/xml/symbols.xml81
-rwxr-xr-xsamples/SoftKeyboard/res/xml/symbols_shift.xml80
-rwxr-xr-xsamples/SoftKeyboard/src/com/example/android/softkeyboard/CandidateView.java321
-rw-r--r--samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboard.java104
-rw-r--r--samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboardView.java46
-rw-r--r--samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java674
21 files changed, 1566 insertions, 0 deletions
diff --git a/samples/SoftKeyboard/Android.mk b/samples/SoftKeyboard/Android.mk
new file mode 100755
index 000000000..883bf2fd7
--- /dev/null
+++ b/samples/SoftKeyboard/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := SoftKeyboard
+
+include $(BUILD_PACKAGE)
diff --git a/samples/SoftKeyboard/AndroidManifest.xml b/samples/SoftKeyboard/AndroidManifest.xml
new file mode 100755
index 000000000..61b513109
--- /dev/null
+++ b/samples/SoftKeyboard/AndroidManifest.xml
@@ -0,0 +1,12 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.softkeyboard">
+ <application android:label="@string/ime_name">
+ <service android:name="SoftKeyboard"
+ android:permission="android.permission.BIND_INPUT_METHOD">
+ <intent-filter>
+ <action android:name="android.view.InputMethod" />
+ </intent-filter>
+ <meta-data android:name="android.view.im" android:resource="@xml/method" />
+ </service>
+ </application>
+</manifest>
diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_delete.png b/samples/SoftKeyboard/res/drawable/sym_keyboard_delete.png
new file mode 100644
index 000000000..6cee59682
--- /dev/null
+++ b/samples/SoftKeyboard/res/drawable/sym_keyboard_delete.png
Binary files differ
diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_done.png b/samples/SoftKeyboard/res/drawable/sym_keyboard_done.png
new file mode 100755
index 000000000..c0d6d1394
--- /dev/null
+++ b/samples/SoftKeyboard/res/drawable/sym_keyboard_done.png
Binary files differ
diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_return.png b/samples/SoftKeyboard/res/drawable/sym_keyboard_return.png
new file mode 100644
index 000000000..cbe2b152f
--- /dev/null
+++ b/samples/SoftKeyboard/res/drawable/sym_keyboard_return.png
Binary files differ
diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_search.png b/samples/SoftKeyboard/res/drawable/sym_keyboard_search.png
new file mode 100755
index 000000000..127755d6b
--- /dev/null
+++ b/samples/SoftKeyboard/res/drawable/sym_keyboard_search.png
Binary files differ
diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_shift.png b/samples/SoftKeyboard/res/drawable/sym_keyboard_shift.png
new file mode 100644
index 000000000..d05962846
--- /dev/null
+++ b/samples/SoftKeyboard/res/drawable/sym_keyboard_shift.png
Binary files differ
diff --git a/samples/SoftKeyboard/res/drawable/sym_keyboard_space.png b/samples/SoftKeyboard/res/drawable/sym_keyboard_space.png
new file mode 100644
index 000000000..09b94d9e6
--- /dev/null
+++ b/samples/SoftKeyboard/res/drawable/sym_keyboard_space.png
Binary files differ
diff --git a/samples/SoftKeyboard/res/layout/input.xml b/samples/SoftKeyboard/res/layout/input.xml
new file mode 100755
index 000000000..1b57468df
--- /dev/null
+++ b/samples/SoftKeyboard/res/layout/input.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<com.example.android.softkeyboard.LatinKeyboardView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard"
+ android:layout_alignParentBottom="true"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
diff --git a/samples/SoftKeyboard/res/values-land/dimens.xml b/samples/SoftKeyboard/res/values-land/dimens.xml
new file mode 100644
index 000000000..b5f3bc128
--- /dev/null
+++ b/samples/SoftKeyboard/res/values-land/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<resources>
+ <dimen name="key_height">46dip</dimen>
+</resources>
diff --git a/samples/SoftKeyboard/res/values/colors.xml b/samples/SoftKeyboard/res/values/colors.xml
new file mode 100644
index 000000000..74d103af0
--- /dev/null
+++ b/samples/SoftKeyboard/res/values/colors.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+<resources>
+ <color name="candidate_normal">#FF000000</color>
+ <color name="candidate_recommended">#FFE35900</color>
+ <color name="candidate_other">#ff808080</color>
+ <color name="candidate_background">#bbffffff</color>
+</resources> \ No newline at end of file
diff --git a/samples/SoftKeyboard/res/values/dimens.xml b/samples/SoftKeyboard/res/values/dimens.xml
new file mode 100644
index 000000000..caf615cfa
--- /dev/null
+++ b/samples/SoftKeyboard/res/values/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<resources>
+ <dimen name="key_height">50dip</dimen>
+ <dimen name="candidate_font_height">16sp</dimen>
+ <dimen name="candidate_vertical_padding">6sp</dimen>
+</resources> \ No newline at end of file
diff --git a/samples/SoftKeyboard/res/values/strings.xml b/samples/SoftKeyboard/res/values/strings.xml
new file mode 100644
index 000000000..bc645b2c0
--- /dev/null
+++ b/samples/SoftKeyboard/res/values/strings.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Title for Latin keyboard -->
+ <string name="ime_name">Sample Soft Keyboard</string>
+
+ <!-- Symbols that are commonly considered word separators in this language -->
+ <string name="word_separators">\u0020.,;:!?\n()[]*&amp;@{}/&lt;&gt;_+=|&quot;</string>
+
+ <!-- Labels on soft keys -->
+ <string name="label_go_key">Go</string>
+ <string name="label_next_key">Next</string>
+ <string name="label_send_key">Send</string>
+</resources>
diff --git a/samples/SoftKeyboard/res/xml/method.xml b/samples/SoftKeyboard/res/xml/method.xml
new file mode 100644
index 000000000..d246624c4
--- /dev/null
+++ b/samples/SoftKeyboard/res/xml/method.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2008, 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.
+ */
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Search Manager. -->
+
+<input-method xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/samples/SoftKeyboard/res/xml/qwerty.xml b/samples/SoftKeyboard/res/xml/qwerty.xml
new file mode 100755
index 000000000..e81d9f102
--- /dev/null
+++ b/samples/SoftKeyboard/res/xml/qwerty.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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: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"/>
+ <Key android:codes="114" android:keyLabel="r"/>
+ <Key android:codes="116" android:keyLabel="t"/>
+ <Key android:codes="121" android:keyLabel="y"/>
+ <Key android:codes="117" android:keyLabel="u"/>
+ <Key android:codes="105" android:keyLabel="i"/>
+ <Key android:codes="111" android:keyLabel="o"/>
+ <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"/>
+ <Key android:codes="115" android:keyLabel="s"/>
+ <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"/>
+ <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">
+ <Key android:codes="-3" android:keyIcon="@drawable/sym_keyboard_done"
+ android:keyWidth="20%p" android:keyEdgeFlags="left"/>
+ <Key android:codes="-2" android:keyLabel="123" android:keyWidth="15%p"/>
+ <Key android:codes="32" android:keyIcon="@drawable/sym_keyboard_space"
+ android:keyWidth="30%p" android:isRepeatable="true"/>
+ <Key android:codes="46,44" android:keyLabel=". ,"
+ android:keyWidth="15%p"/>
+ <Key android:codes="10" android:keyIcon="@drawable/sym_keyboard_return"
+ android:keyWidth="20%p" android:keyEdgeFlags="right"/>
+ </Row>
+</Keyboard>
+ \ No newline at end of file
diff --git a/samples/SoftKeyboard/res/xml/symbols.xml b/samples/SoftKeyboard/res/xml/symbols.xml
new file mode 100755
index 000000000..a28d752bd
--- /dev/null
+++ b/samples/SoftKeyboard/res/xml/symbols.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/>
+ <Key android:codes="50" android:keyLabel="2"/>
+ <Key android:codes="51" android:keyLabel="3"/>
+ <Key android:codes="52" android:keyLabel="4"/>
+ <Key android:codes="53" android:keyLabel="5"/>
+ <Key android:codes="54" android:keyLabel="6"/>
+ <Key android:codes="55" android:keyLabel="7"/>
+ <Key android:codes="56" android:keyLabel="8"/>
+ <Key android:codes="57" android:keyLabel="9"/>
+ <Key android:codes="48" android:keyLabel="0" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="64" android:keyLabel="\@" android:keyEdgeFlags="left"/>
+ <Key android:codes="35" android:keyLabel="\#"/>
+ <Key android:codes="36" android:keyLabel="$"/>
+ <Key android:codes="37" android:keyLabel="%"/>
+ <Key android:codes="38" android:keyLabel="&amp;"/>
+ <Key android:codes="42" android:keyLabel="*"/>
+ <Key android:codes="45" android:keyLabel="-"/>
+ <Key android:codes="61" android:keyLabel="="/>
+ <Key android:codes="40" android:keyLabel="("/>
+ <Key android:codes="41" android:keyLabel=")" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="33" android:keyLabel="!" />
+ <Key android:codes="34" android:keyLabel="&quot;"/>
+ <Key android:codes="39" android:keyLabel="\'"/>
+ <Key android:codes="58" android:keyLabel=":"/>
+ <Key android:codes="59" android:keyLabel=";"/>
+ <Key android:codes="47" android:keyLabel="/" />
+ <Key android:codes="63" android:keyLabel="\?"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="-3" android:keyIcon="@drawable/sym_keyboard_done"
+ android:keyWidth="20%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>
+</Keyboard> \ No newline at end of file
diff --git a/samples/SoftKeyboard/res/xml/symbols_shift.xml b/samples/SoftKeyboard/res/xml/symbols_shift.xml
new file mode 100755
index 000000000..d7139f340
--- /dev/null
+++ b/samples/SoftKeyboard/res/xml/symbols_shift.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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:android="http://schemas.android.com/apk/res/android"
+ android:keyWidth="10%p"
+ android:horizontalGap="0px"
+ android:verticalGap="0px"
+ android:keyHeight="@dimen/key_height"
+ >
+
+ <Row>
+ <Key android:codes="126" android:keyLabel="~" android:keyEdgeFlags="left"/>
+ <Key android:codes="177" android:keyLabel="±"/>
+ <Key android:codes="215" android:keyLabel="×"/>
+ <Key android:codes="247" android:keyLabel="÷"/>
+ <Key android:codes="8226" android:keyLabel="•"/>
+ <Key android:codes="176" android:keyLabel="°"/>
+ <Key android:codes="96" android:keyLabel="`"/>
+ <Key android:codes="180" android:keyLabel="´"/>
+ <Key android:codes="123" android:keyLabel="{"/>
+ <Key android:codes="125" android:keyLabel="}" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="169" android:keyLabel="©" android:keyEdgeFlags="left"/>
+ <Key android:codes="163" android:keyLabel="£"/>
+ <Key android:codes="8364" android:keyLabel="€"/>
+ <Key android:codes="94" android:keyLabel="^"/>
+ <Key android:codes="174" android:keyLabel="®"/>
+ <Key android:codes="165" android:keyLabel="¥"/>
+ <Key android:codes="95" android:keyLabel="_"/>
+ <Key android:codes="43" android:keyLabel="+"/>
+ <Key android:codes="91" android:keyLabel="["/>
+ <Key android:codes="93" android:keyLabel="]" android:keyEdgeFlags="right"/>
+ </Row>
+
+ <Row>
+ <Key android:codes="-1" android:keyIcon="@drawable/sym_keyboard_shift"
+ android:keyWidth="15%p" android:isModifier="true"
+ android:isSticky="true" android:keyEdgeFlags="left"/>
+ <Key android:codes="161" android:keyLabel="¡" />
+ <Key android:codes="60" android:keyLabel="&lt;"/>
+ <Key android:codes="62" android:keyLabel="&gt;"/>
+ <Key android:codes="162" android:keyLabel="¢"/>
+ <Key android:codes="124" android:keyLabel="|"/>
+ <Key android:codes="92" android:keyLabel="\\" />
+ <Key android:codes="191" android:keyLabel="¿"/>
+ <Key android:codes="-5" android:keyIcon="@drawable/sym_keyboard_delete"
+ android:keyWidth="15%p" android:keyEdgeFlags="right"
+ android:isRepeatable="true"/>
+ </Row>
+
+ <Row android:rowEdgeFlags="bottom">
+ <Key android:codes="-3" android:keyIcon="@drawable/sym_keyboard_done"
+ android:keyWidth="20%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>
+</Keyboard>
diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/CandidateView.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/CandidateView.java
new file mode 100755
index 000000000..7cadead8a
--- /dev/null
+++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/CandidateView.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ *
+ * 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.example.android.softkeyboard;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CandidateView extends View {
+
+ private static final int OUT_OF_BOUNDS = -1;
+
+ private SoftKeyboard mService;
+ private List<String> mSuggestions;
+ private int mSelectedIndex;
+ private int mTouchX = OUT_OF_BOUNDS;
+ private Drawable mSelectionHighlight;
+ private boolean mTypedWordValid;
+
+ private Rect mBgPadding;
+
+ private static final int MAX_SUGGESTIONS = 32;
+ private static final int SCROLL_PIXELS = 20;
+
+ private int[] mWordWidth = new int[MAX_SUGGESTIONS];
+ private int[] mWordX = new int[MAX_SUGGESTIONS];
+
+ private static final int X_GAP = 10;
+
+ private static final List<String> EMPTY_LIST = new ArrayList<String>();
+
+ private int mColorNormal;
+ private int mColorRecommended;
+ private int mColorOther;
+ private int mVerticalPadding;
+ private Paint mPaint;
+ private boolean mScrolled;
+ private int mTargetScrollX;
+
+ private int mTotalWidth;
+
+ private GestureDetector mGestureDetector;
+
+ /**
+ * Construct a CandidateView for showing suggested words for completion.
+ * @param context
+ * @param attrs
+ */
+ public CandidateView(Context context) {
+ super(context);
+ mSelectionHighlight = context.getResources().getDrawable(
+ android.R.drawable.list_selector_background);
+ mSelectionHighlight.setState(new int[] {
+ android.R.attr.state_enabled,
+ android.R.attr.state_focused,
+ android.R.attr.state_window_focused,
+ android.R.attr.state_pressed
+ });
+
+ Resources r = context.getResources();
+
+ setBackgroundColor(r.getColor(R.color.candidate_background));
+
+ mColorNormal = r.getColor(R.color.candidate_normal);
+ mColorRecommended = r.getColor(R.color.candidate_recommended);
+ mColorOther = r.getColor(R.color.candidate_other);
+ mVerticalPadding = r.getDimensionPixelSize(R.dimen.candidate_vertical_padding);
+
+ mPaint = new Paint();
+ mPaint.setColor(mColorNormal);
+ mPaint.setAntiAlias(true);
+ mPaint.setTextSize(r.getDimensionPixelSize(R.dimen.candidate_font_height));
+ mPaint.setStrokeWidth(0);
+
+ mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2,
+ float distanceX, float distanceY) {
+ mScrolled = true;
+ int sx = getScrollX();
+ sx += distanceX;
+ if (sx < 0) {
+ sx = 0;
+ }
+ if (sx + getWidth() > mTotalWidth) {
+ sx -= distanceX;
+ }
+ mTargetScrollX = sx;
+ scrollTo(sx, getScrollY());
+ invalidate();
+ return true;
+ }
+ });
+ setHorizontalFadingEdgeEnabled(true);
+ setWillNotDraw(false);
+ setHorizontalScrollBarEnabled(false);
+ setVerticalScrollBarEnabled(false);
+ }
+
+ /**
+ * A connection back to the service to communicate with the text field
+ * @param listener
+ */
+ public void setService(SoftKeyboard listener) {
+ mService = listener;
+ }
+
+ @Override
+ public int computeHorizontalScrollRange() {
+ return mTotalWidth;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int measuredWidth = resolveSize(50, widthMeasureSpec);
+
+ // Get the desired height of the icon menu view (last row of items does
+ // not have a divider below)
+ Rect padding = new Rect();
+ mSelectionHighlight.getPadding(padding);
+ final int desiredHeight = ((int)mPaint.getTextSize()) + mVerticalPadding
+ + padding.top + padding.bottom;
+
+ // Maximum possible width and desired height
+ setMeasuredDimension(measuredWidth,
+ resolveSize(desiredHeight, heightMeasureSpec));
+ }
+
+ /**
+ * If the canvas is null, then only touch calculations are performed to pick the target
+ * candidate.
+ */
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (canvas != null) {
+ super.onDraw(canvas);
+ }
+ mTotalWidth = 0;
+ if (mSuggestions == null) return;
+
+ if (mBgPadding == null) {
+ mBgPadding = new Rect(0, 0, 0, 0);
+ if (getBackground() != null) {
+ getBackground().getPadding(mBgPadding);
+ }
+ }
+ int x = 0;
+ final int count = mSuggestions.size();
+ final int height = getHeight();
+ final Rect bgPadding = mBgPadding;
+ final Paint paint = mPaint;
+ final int touchX = mTouchX;
+ final int scrollX = getScrollX();
+ final boolean scrolled = mScrolled;
+ final boolean typedWordValid = mTypedWordValid;
+ final int y = (int) (((height - mPaint.getTextSize()) / 2) - mPaint.ascent());
+
+ for (int i = 0; i < count; i++) {
+ String suggestion = mSuggestions.get(i);
+ float textWidth = paint.measureText(suggestion);
+ final int wordWidth = (int) textWidth + X_GAP * 2;
+
+ mWordX[i] = x;
+ mWordWidth[i] = wordWidth;
+ paint.setColor(mColorNormal);
+ if (touchX + scrollX >= x && touchX + scrollX < x + wordWidth && !scrolled) {
+ if (canvas != null) {
+ canvas.translate(x, 0);
+ mSelectionHighlight.setBounds(0, bgPadding.top, wordWidth, height);
+ mSelectionHighlight.draw(canvas);
+ canvas.translate(-x, 0);
+ }
+ mSelectedIndex = i;
+ }
+
+ if (canvas != null) {
+ if ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid)) {
+ paint.setFakeBoldText(true);
+ paint.setColor(mColorRecommended);
+ } else if (i != 0) {
+ paint.setColor(mColorOther);
+ }
+ canvas.drawText(suggestion, x + X_GAP, y, paint);
+ paint.setColor(mColorOther);
+ canvas.drawLine(x + wordWidth + 0.5f, bgPadding.top,
+ x + wordWidth + 0.5f, height + 1, paint);
+ paint.setFakeBoldText(false);
+ }
+ x += wordWidth;
+ }
+ mTotalWidth = x;
+ if (mTargetScrollX != getScrollX()) {
+ scrollToTarget();
+ }
+ }
+
+ private void scrollToTarget() {
+ int sx = getScrollX();
+ if (mTargetScrollX > sx) {
+ sx += SCROLL_PIXELS;
+ if (sx >= mTargetScrollX) {
+ sx = mTargetScrollX;
+ requestLayout();
+ }
+ } else {
+ sx -= SCROLL_PIXELS;
+ if (sx <= mTargetScrollX) {
+ sx = mTargetScrollX;
+ requestLayout();
+ }
+ }
+ scrollTo(sx, getScrollY());
+ invalidate();
+ }
+
+ public void setSuggestions(List<String> suggestions, boolean completions,
+ boolean typedWordValid) {
+ clear();
+ if (suggestions != null) {
+ mSuggestions = new ArrayList<String>(suggestions);
+ }
+ mTypedWordValid = typedWordValid;
+ scrollTo(0, 0);
+ mTargetScrollX = 0;
+ // Compute the total width
+ onDraw(null);
+ invalidate();
+ requestLayout();
+ }
+
+ public void clear() {
+ mSuggestions = EMPTY_LIST;
+ mTouchX = OUT_OF_BOUNDS;
+ mSelectedIndex = -1;
+ invalidate();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent me) {
+
+ if (mGestureDetector.onTouchEvent(me)) {
+ return true;
+ }
+
+ int action = me.getAction();
+ int x = (int) me.getX();
+ int y = (int) me.getY();
+ mTouchX = x;
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mScrolled = false;
+ invalidate();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (y <= 0) {
+ // Fling up!?
+ if (mSelectedIndex >= 0) {
+ mService.pickSuggestionManually(mSelectedIndex);
+ mSelectedIndex = -1;
+ }
+ }
+ invalidate();
+ break;
+ case MotionEvent.ACTION_UP:
+ if (!mScrolled) {
+ if (mSelectedIndex >= 0) {
+ mService.pickSuggestionManually(mSelectedIndex);
+ }
+ }
+ mSelectedIndex = -1;
+ removeHighlight();
+ requestLayout();
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * For flick through from keyboard, call this method with the x coordinate of the flick
+ * gesture.
+ * @param x
+ */
+ public void takeSuggestionAt(float x) {
+ mTouchX = (int) x;
+ // To detect candidate
+ onDraw(null);
+ if (mSelectedIndex >= 0) {
+ mService.pickSuggestionManually(mSelectedIndex);
+ }
+ invalidate();
+ }
+
+ private void removeHighlight() {
+ mTouchX = OUT_OF_BOUNDS;
+ invalidate();
+ }
+}
diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboard.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboard.java
new file mode 100644
index 000000000..179844234
--- /dev/null
+++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboard.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ *
+ * 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.example.android.softkeyboard;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.Keyboard.Key;
+import android.inputmethodservice.Keyboard.Row;
+import android.view.inputmethod.EditorInfo;
+
+public class LatinKeyboard extends Keyboard {
+
+ private Key mEnterKey;
+
+ public LatinKeyboard(Context context, int xmlLayoutResId) {
+ super(context, xmlLayoutResId);
+ }
+
+ public LatinKeyboard(Context context, int layoutTemplateResId,
+ CharSequence characters, int columns, int horizontalPadding) {
+ super(context, layoutTemplateResId, characters, columns, horizontalPadding);
+ }
+
+ @Override
+ protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
+ XmlResourceParser parser) {
+ Key key = new LatinKey(res, parent, x, y, parser);
+ if (key.codes[0] == 10) {
+ mEnterKey = 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_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_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;
+ }
+ }
+
+ static class LatinKey extends Keyboard.Key {
+
+ public LatinKey(Resources res, Keyboard.Row parent, int x, int y, XmlResourceParser parser) {
+ super(res, parent, x, y, parser);
+ }
+
+ /**
+ * Overriding this method so that we can reduce the target area for the key that
+ * closes the keyboard.
+ */
+ @Override
+ public boolean isInside(int x, int y) {
+ return super.isInside(x, codes[0] == KEYCODE_CANCEL ? y - 10 : y);
+ }
+ }
+
+}
diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboardView.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboardView.java
new file mode 100644
index 000000000..7464607d8
--- /dev/null
+++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/LatinKeyboardView.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ *
+ * 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.example.android.softkeyboard;
+
+import android.content.Context;
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.KeyboardView;
+import android.inputmethodservice.Keyboard.Key;
+import android.util.AttributeSet;
+
+public class LatinKeyboardView extends KeyboardView {
+
+ static final int KEYCODE_OPTIONS = -100;
+
+ public LatinKeyboardView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected boolean onLongPress(Key key) {
+ if (key.codes[0] == Keyboard.KEYCODE_CANCEL) {
+ getOnKeyboardActionListener().onKey(KEYCODE_OPTIONS, null);
+ return true;
+ } else {
+ return super.onLongPress(key);
+ }
+ }
+}
diff --git a/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java b/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java
new file mode 100644
index 000000000..656efdfb7
--- /dev/null
+++ b/samples/SoftKeyboard/src/com/example/android/softkeyboard/SoftKeyboard.java
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2008-2009 Google Inc.
+ *
+ * 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.example.android.softkeyboard;
+
+import android.inputmethodservice.InputMethodService;
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.KeyboardView;
+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 android.view.inputmethod.InputMethodManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Example of writing an input method for a soft keyboard. This code is
+ * focused on simplicity over completeness, so it should in no way be considered
+ * to be a complete soft keyboard implementation. Its purpose is to provide
+ * a basic example for how you would get started writing an input method, to
+ * be fleshed out as appropriate.
+ */
+public class SoftKeyboard extends InputMethodService
+ implements KeyboardView.OnKeyboardActionListener {
+ static final boolean DEBUG = false;
+
+ /**
+ * This boolean indicates the optional example code for performing
+ * processing of hard keys in addition to regular text generation
+ * from on-screen interaction. It would be used for input methods that
+ * perform language translations (such as converting text entered on
+ * a QWERTY keyboard to Chinese), but may not be used for input methods
+ * that are primarily intended to be used for on-screen text entry.
+ */
+ static final boolean PROCESS_HARD_KEYS = true;
+
+ private KeyboardView mInputView;
+ private CandidateView mCandidateView;
+ private CompletionInfo[] mCompletions;
+
+ private StringBuilder mComposing = new StringBuilder();
+ private boolean mPredictionOn;
+ private boolean mCompletionOn;
+ private int mLastDisplayWidth;
+ private boolean mCapsLock;
+ private long mLastShiftTime;
+ private long mMetaState;
+
+ private LatinKeyboard mSymbolsKeyboard;
+ private LatinKeyboard mSymbolsShiftedKeyboard;
+ private LatinKeyboard mQwertyKeyboard;
+
+ private LatinKeyboard mCurKeyboard;
+
+ private String mWordSeparators;
+
+ /**
+ * Main initialization of the input method component. Be sure to call
+ * to super class.
+ */
+ @Override public void onCreate() {
+ super.onCreate();
+ mWordSeparators = getResources().getString(R.string.word_separators);
+ }
+
+ /**
+ * This is the point where you can do all of your UI initialization. It
+ * is called after creation and any configuration change.
+ */
+ @Override public void onInitializeInterface() {
+ if (mQwertyKeyboard != null) {
+ // Configuration changes can happen after the keyboard gets recreated,
+ // so we need to be able to re-build the keyboards if the available
+ // space has changed.
+ int displayWidth = getMaxWidth();
+ if (displayWidth == mLastDisplayWidth) return;
+ mLastDisplayWidth = displayWidth;
+ }
+ mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
+ mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
+ mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
+ }
+
+ /**
+ * Called by the framework when your view for creating input needs to
+ * be generated. This will be called the first time your input method
+ * is displayed, and every time it needs to be re-created such as due to
+ * a configuration change.
+ */
+ @Override public View onCreateInputView() {
+ mInputView = (KeyboardView) getLayoutInflater().inflate(
+ R.layout.input, null);
+ mInputView.setOnKeyboardActionListener(this);
+ mInputView.setKeyboard(mQwertyKeyboard);
+ return mInputView;
+ }
+
+ /**
+ * Called by the framework when your view for showing candidates needs to
+ * be generated, like {@link #onCreateInputView}.
+ */
+ @Override public View onCreateCandidatesView() {
+ mCandidateView = new CandidateView(this);
+ mCandidateView.setService(this);
+ return mCandidateView;
+ }
+
+ /**
+ * This is the main point where we do our initialization of the input method
+ * to begin operating on an application. At this point we have been
+ * bound to the client, and are now receiving all of the detailed information
+ * about the target of our edits.
+ */
+ @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;
+
+ // We are now going to initialize our state based on the type of
+ // text being edited.
+ switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) {
+ case EditorInfo.TYPE_CLASS_NUMBER:
+ case EditorInfo.TYPE_CLASS_DATETIME:
+ // Numbers and dates default to the symbols keyboard, with
+ // no extra features.
+ mCurKeyboard = mSymbolsKeyboard;
+ break;
+
+ case EditorInfo.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 EditorInfo.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 = mQwertyKeyboard;
+ mPredictionOn = true;
+
+ // We now look for a few special variations of text that will
+ // modify our behavior.
+ int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
+ if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD) {
+ // Do not display predictions / what the user is typing
+ // when they are entering a password.
+ mPredictionOn = false;
+ }
+
+ if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+ || variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
+ // Our predictions are not useful for e-mail addresses
+ // or URIs.
+ mPredictionOn = false;
+ }
+
+ if ((attribute.inputType&EditorInfo.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 fullscreen 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 = mQwertyKeyboard;
+ }
+
+ // Update the label on the enter key, depending on what the application
+ // says it will do.
+ mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);
+ }
+
+ /**
+ * This is called when the user is done editing a field. We can use
+ * this to reset our state.
+ */
+ @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 = mQwertyKeyboard;
+ if (mInputView != null) {
+ mInputView.closing();
+ }
+ }
+
+ @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();
+ }
+
+ /**
+ * Deal with the editor reporting movement of its cursor.
+ */
+ @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd,
+ int newSelStart, int newSelEnd,
+ int candidatesStart, int 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();
+ }
+ }
+ }
+
+ /**
+ * This tells us about completions that the editor has determined based
+ * on the current text in it. We want to use this in fullscreen mode
+ * to show the completions ourself, since the editor can not be seen
+ * in that situation.
+ */
+ @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 != null ? completions.length : 0); 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;
+ }
+
+ boolean dead = false;
+
+ if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ dead = true;
+ 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;
+ }
+
+ /**
+ * Use this to monitor key events being delivered to the application.
+ * We get first crack at them, and can either resume them or let them
+ * continue to the app.
+ */
+ @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(Keyboard.KEYCODE_DELETE, null);
+ return true;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_ENTER:
+ // Let the underlying text editor always handle these.
+ return false;
+
+ default:
+ // For all other keys, if we want to do transformations on
+ // text being entered with a hard keyboard, we need to process
+ // it and do the appropriate action.
+ if (PROCESS_HARD_KEYS) {
+ if (keyCode == KeyEvent.KEYCODE_SPACE
+ && (event.getMetaState()&KeyEvent.META_ALT_ON) != 0) {
+ // A silly example: in our input method, Alt+Space
+ // is a shortcut for 'android' in lower case.
+ InputConnection ic = getCurrentInputConnection();
+ if (ic != null) {
+ // First, tell the editor that it is no longer in the
+ // shift state, since we are consuming this.
+ ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);
+ keyDownUp(KeyEvent.KEYCODE_A);
+ keyDownUp(KeyEvent.KEYCODE_N);
+ keyDownUp(KeyEvent.KEYCODE_D);
+ keyDownUp(KeyEvent.KEYCODE_R);
+ keyDownUp(KeyEvent.KEYCODE_O);
+ keyDownUp(KeyEvent.KEYCODE_I);
+ keyDownUp(KeyEvent.KEYCODE_D);
+ // And we consume this event.
+ return true;
+ }
+ }
+ if (mPredictionOn && translateKeyDown(keyCode, event)) {
+ return true;
+ }
+ }
+ }
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ /**
+ * Use this to monitor key events being delivered to the application.
+ * We get first crack at them, and can either resume them or let them
+ * continue to the app.
+ */
+ @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
+ // If we want to do transformations on text being entered with a hard
+ // keyboard, we need to process the up events to update the meta key
+ // state we are tracking.
+ if (PROCESS_HARD_KEYS) {
+ if (mPredictionOn) {
+ mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,
+ keyCode, event);
+ }
+ }
+
+ return super.onKeyUp(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 && mQwertyKeyboard == mInputView.getKeyboard()) {
+ int caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);
+ mInputView.setShifted(mCapsLock || caps != 0);
+ }
+ }
+
+ /**
+ * Helper to determine if a given character code is alphabetic.
+ */
+ private boolean isAlphabet(int code) {
+ if (Character.isLetter(code)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 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));
+ }
+
+ /**
+ * Helper to send a character to the editor as raw key events.
+ */
+ private void sendKey(int keyCode) {
+ switch (keyCode) {
+ case '\n':
+ keyDownUp(KeyEvent.KEYCODE_ENTER);
+ break;
+ default:
+ if (keyCode >= '0' && keyCode <= '9') {
+ keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
+ } else {
+ getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
+ }
+ break;
+ }
+ }
+
+ // Implementation of KeyboardViewListener
+
+ public void onKey(int primaryCode, int[] keyCodes) {
+ if (isWordSeparator(primaryCode)) {
+ // Handle separator
+ if (mComposing.length() > 0) {
+ commitTyped(getCurrentInputConnection());
+ }
+ sendKey(primaryCode);
+ updateShiftKeyState(getCurrentInputEditorInfo());
+ } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
+ handleBackspace();
+ } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
+ handleShift();
+ } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {
+ handleClose();
+ return;
+ } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {
+ // Show a menu or somethin'
+ } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE
+ && mInputView != null) {
+ Keyboard current = mInputView.getKeyboard();
+ if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
+ current = mQwertyKeyboard;
+ } else {
+ current = mSymbolsKeyboard;
+ }
+ mInputView.setKeyboard(current);
+ if (current == mSymbolsKeyboard) {
+ current.setShifted(false);
+ }
+ } 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());
+ setSuggestions(list, true, true);
+ } 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 (isFullscreenMode()) {
+ 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, mComposing.length());
+ 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;
+ }
+
+ Keyboard currentKeyboard = mInputView.getKeyboard();
+ if (mQwertyKeyboard == 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);
+ }
+ }
+ if (isAlphabet(primaryCode) && mPredictionOn) {
+ mComposing.append((char) primaryCode);
+ getCurrentInputConnection().setComposingText(mComposing, mComposing.length());
+ updateShiftKeyState(getCurrentInputEditorInfo());
+ updateCandidates();
+ } else {
+ getCurrentInputConnection().commitText(
+ String.valueOf((char) primaryCode), 1);
+ }
+ }
+
+ private void handleClose() {
+ commitTyped(getCurrentInputConnection());
+ dismissSoftInput(0);
+ mInputView.closing();
+ }
+
+ private void checkToggleCapsLock() {
+ long now = System.currentTimeMillis();
+ if (mLastShiftTime + 800 > now) {
+ mCapsLock = !mCapsLock;
+ mLastShiftTime = 0;
+ } else {
+ mLastShiftTime = now;
+ }
+ }
+
+ private String getWordSeparators() {
+ return mWordSeparators;
+ }
+
+ public boolean isWordSeparator(int code) {
+ String separators = getWordSeparators();
+ return separators.contains(String.valueOf((char)code));
+ }
+
+ 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) {
+ }
+}