diff --git a/tools/EditTextVariations/Android.mk b/tools/EditTextVariations/Android.mk
new file mode 100644
index 000000000..1f49aa4a7
--- /dev/null
+++ b/tools/EditTextVariations/Android.mk
@@ -0,0 +1,26 @@
+# Copyright (C) 2013 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.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := EditTextVariations
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tools/EditTextVariations/AndroidManifest.xml b/tools/EditTextVariations/AndroidManifest.xml
new file mode 100644
index 000000000..7694f4db9
--- /dev/null
+++ b/tools/EditTextVariations/AndroidManifest.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/EditTextVariations/assets/Theme.css b/tools/EditTextVariations/assets/Theme.css
new file mode 100644
index 000000000..b7aa514bf
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: black;
+}
+div.placeholder {
+ color: #a0a0a0;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: black;
+ background-color: white;
+ font-size: 18px;
+ line-height: 200%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: none;
+ border-left: none;
+}
+textarea {
+ color: black;
+ background-color: white;
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: none;
+ border-left: none;
+}
diff --git a/tools/EditTextVariations/assets/Theme_Black.css b/tools/EditTextVariations/assets/Theme_Black.css
new file mode 100644
index 000000000..ce663a180
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme_Black.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: black;
+}
+div.placeholder {
+ color: #a0a0a0;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: black;
+ background-color: white;
+ font-size: 18px;
+ line-height: 200%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: none;
+ border-left: none;
+}
+textarea {
+ color: black;
+ background-color: white;
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: none;
+ border-left: none;
+}
diff --git a/tools/EditTextVariations/assets/Theme_Holo.css b/tools/EditTextVariations/assets/Theme_Holo.css
new file mode 100644
index 000000000..a3afe2e00
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme_Holo.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: #16191C;
+}
+div.placeholder {
+ color: #808080;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: white;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 180%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #5E6063;
+ border-left: none;
+}
+textarea {
+ color: white;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #5E6063;
+ border-left: none;
+}
diff --git a/tools/EditTextVariations/assets/Theme_Holo_Light.css b/tools/EditTextVariations/assets/Theme_Holo_Light.css
new file mode 100644
index 000000000..fb3a83c69
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme_Holo_Light.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: #F2F2F2;
+}
+div.placeholder {
+ color: #808080;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: black;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #808080;
+ border-left: none;
+}
+textarea {
+ color: black;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #808080;
+ border-left: none;
+}
diff --git a/tools/EditTextVariations/assets/Theme_Light.css b/tools/EditTextVariations/assets/Theme_Light.css
new file mode 100644
index 000000000..4cce0a002
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme_Light.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: #f3f3f3;
+}
+div.placeholder {
+ color: #a0a0a0;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: black;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 200%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: 1px solid #808080;
+ border-right: 1px solid rgba(0, 0, 0, 0.5);
+ border-bottom: 1px solid #808080;
+ border-left: 1px solid rgba(0, 0, 0, 0.5);
+}
+textarea {
+ color: black;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: 1px solid #808080;
+ border-right: 1px solid rgba(0, 0, 0, 0.5);
+ border-bottom: 1px solid #808080;
+ border-left: 1px solid rgba(0, 0, 0, 0.5);
+}
diff --git a/tools/EditTextVariations/assets/Theme_Material.css b/tools/EditTextVariations/assets/Theme_Material.css
new file mode 100644
index 000000000..3581a8824
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme_Material.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: #212121;
+}
+div.placeholder {
+ color: #909090;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: white;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 180%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #757575;
+ border-left: none;
+}
+textarea {
+ color: white;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #757575;
+ border-left: none;
+}
diff --git a/tools/EditTextVariations/assets/Theme_Material_Light.css b/tools/EditTextVariations/assets/Theme_Material_Light.css
new file mode 100644
index 000000000..1a78a2d4a
--- /dev/null
+++ b/tools/EditTextVariations/assets/Theme_Material_Light.css
@@ -0,0 +1,56 @@
+
+
+body {
+ background-color: #FAFAFA;
+}
+div.placeholder {
+ color: #7D7D7D;
+ font-size: 18px;
+ margin: 0px 0px -34px 0px;
+ padding: 4px 0px 4px 0px
+}
+div.input {
+ border: none;
+ margin: 4px 0px 4px -8px;
+}
+input {
+ color: white;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 180%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #737373;
+ border-left: none;
+}
+textarea {
+ color: white;
+ background-color: rgba(0, 0, 0, 0.0);
+ font-size: 18px;
+ line-height: 150%;
+ vertical-align: center;
+ padding-left: 8px;
+ border-top: none;
+ border-right: none;
+ border-bottom: 1px solid #737373;
+ border-left: none;
+}
diff --git a/tools/EditTextVariations/assets/webview.html b/tools/EditTextVariations/assets/webview.html
new file mode 100644
index 000000000..daf0fdb73
--- /dev/null
+++ b/tools/EditTextVariations/assets/webview.html
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/EditTextVariations/res/drawable-hdpi/ic_launcher.png b/tools/EditTextVariations/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 000000000..e0923a605
Binary files /dev/null and b/tools/EditTextVariations/res/drawable-hdpi/ic_launcher.png differ
diff --git a/tools/EditTextVariations/res/drawable-mdpi/ic_launcher.png b/tools/EditTextVariations/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 000000000..9bc091481
Binary files /dev/null and b/tools/EditTextVariations/res/drawable-mdpi/ic_launcher.png differ
diff --git a/tools/EditTextVariations/res/drawable-xhdpi/ic_launcher.png b/tools/EditTextVariations/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..d60ac3dc0
Binary files /dev/null and b/tools/EditTextVariations/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/tools/EditTextVariations/res/drawable-xxhdpi/ic_launcher.png b/tools/EditTextVariations/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..f3069d74f
Binary files /dev/null and b/tools/EditTextVariations/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/tools/EditTextVariations/res/layout/main.xml b/tools/EditTextVariations/res/layout/main.xml
new file mode 100644
index 000000000..99abfb07e
--- /dev/null
+++ b/tools/EditTextVariations/res/layout/main.xml
@@ -0,0 +1,298 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tools/EditTextVariations/res/values-v11/donottranslate.xml b/tools/EditTextVariations/res/values-v11/donottranslate.xml
new file mode 100644
index 000000000..5b7eb23fc
--- /dev/null
+++ b/tools/EditTextVariations/res/values-v11/donottranslate.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ Theme_Holo_Light
+
diff --git a/tools/EditTextVariations/res/values-v14/themes.xml b/tools/EditTextVariations/res/values-v14/themes.xml
new file mode 100644
index 000000000..22c6016ff
--- /dev/null
+++ b/tools/EditTextVariations/res/values-v14/themes.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/tools/EditTextVariations/res/values-v27/themes.xml b/tools/EditTextVariations/res/values-v27/themes.xml
new file mode 100644
index 000000000..8fd3aae4f
--- /dev/null
+++ b/tools/EditTextVariations/res/values-v27/themes.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
diff --git a/tools/EditTextVariations/res/values/countries.xml b/tools/EditTextVariations/res/values/countries.xml
new file mode 100644
index 000000000..6d7e5c137
--- /dev/null
+++ b/tools/EditTextVariations/res/values/countries.xml
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+ - Afghanistan
+ - Albania
+ - Algeria
+ - American Samoa
+ - Andorra
+ - Angola
+ - Anguilla
+ - Antarctica
+ - Antigua and Barbuda
+ - Argentina
+ - Armenia
+ - Aruba
+ - Australia
+ - Austria
+ - Azerbaijan
+ - Bahrain
+ - Bangladesh
+ - Barbados
+ - Belarus
+ - Belgium
+ - Belize
+ - Benin
+ - Bermuda
+ - Bhutan
+ - Bolivia
+ - Bosnia and Herzegovina
+ - Botswana
+ - Bouvet Island
+ - Brazil
+ - British Indian Ocean Territory
+ - British Virgin Islands
+ - Brunei
+ - Bulgaria
+ - Burkina Faso
+ - Burundi
+ - "Cote d'Ivoire"
+ - Cambodia
+ - Cameroon
+ - Canada
+ - Cape Verde
+ - Cayman Islands
+ - Central African Republic
+ - Chad
+ - Chile
+ - China
+ - Christmas Island
+ - Cocos (Keeling) Islands
+ - Colombia
+ - Comoros
+ - Congo
+ - Cook Islands
+ - Costa Rica
+ - Croatia
+ - Cuba
+ - Cyprus
+ - Czech Republic
+ - Democratic Republic of the Congo
+ - Denmark
+ - Djibouti
+ - Dominica
+ - Dominican Republic
+ - East Timor
+ - Ecuador
+ - Egypt
+ - El Salvador
+ - Equatorial Guinea
+ - Eritrea
+ - Estonia
+ - Ethiopia
+ - Faeroe Islands
+ - Falkland Islands
+ - Fiji
+ - Finland
+ - Republic of Macedonia
+ - France
+ - French Guiana
+ - French Polynesia
+ - French Southern Territories
+ - Gabon
+ - Georgia
+ - Germany
+ - Ghana
+ - Gibraltar
+ - Greece
+ - Greenland
+ - Grenada
+ - Guadeloupe
+ - Guam
+ - Guatemala
+ - Guinea
+ - Guinea-Bissau
+ - Guyana
+ - Haiti
+ - Heard Island and McDonald Islands
+ - Honduras
+ - Hong Kong
+ - Hungary
+ - Iceland
+ - India
+ - Indonesia
+ - Iran
+ - Iraq
+ - Ireland
+ - Israel
+ - Italy
+ - Jamaica
+ - Japan
+ - Jordan
+ - Kazakhstan
+ - Kenya
+ - Kiribati
+ - Kuwait
+ - Kyrgyzstan
+ - Laos
+ - Latvia
+ - Lebanon
+ - Lesotho
+ - Liberia
+ - Libya
+ - Liechtenstein
+ - Lithuania
+ - Luxembourg
+ - Macau
+ - Madagascar
+ - Malawi
+ - Malaysia
+ - Maldives
+ - Mali
+ - Malta
+ - Marshall Islands
+ - Martinique
+ - Mauritania
+ - Mauritius
+ - Mayotte
+ - Mexico
+ - Micronesia
+ - Moldova
+ - Monaco
+ - Mongolia
+ - Montserrat
+ - Morocco
+ - Mozambique
+ - Myanmar
+ - Namibia
+ - Nauru
+ - Nepal
+ - Netherlands
+ - Netherlands Antilles
+ - New Caledonia
+ - New Zealand
+ - Nicaragua
+ - Niger
+ - Nigeria
+ - Niue
+ - Norfolk Island
+ - North Korea
+ - Northern Marianas
+ - Norway
+ - Oman
+ - Pakistan
+ - Palau
+ - Panama
+ - Papua New Guinea
+ - Paraguay
+ - Peru
+ - Philippines
+ - Pitcairn Islands
+ - Poland
+ - Portugal
+ - Puerto Rico
+ - Qatar
+ - Reunion
+ - Romania
+ - Russia
+ - Rwanda
+ - Sao Tome and Principe
+ - Saint Helena
+ - Saint Kitts and Nevis
+ - Saint Lucia
+ - Saint Pierre and Miquelon
+ - Saint Vincent and the Grenadines
+ - Samoa
+ - San Marino
+ - Saudi Arabia
+ - Senegal
+ - Seychelles
+ - Sierra Leone
+ - Singapore
+ - Slovakia
+ - Slovenia
+ - Solomon Islands
+ - Somalia
+ - South Africa
+ - South Georgia and the South Sandwich Islands
+ - South Korea
+ - Spain
+ - Sri Lanka
+ - Sudan
+ - Suriname
+ - Svalbard and Jan Mayen
+ - Swaziland
+ - Sweden
+ - Switzerland
+ - Syria
+ - Taiwan
+ - Tajikistan
+ - Tanzania
+ - Thailand
+ - The Bahamas
+ - The Gambia
+ - Togo
+ - Tokelau
+ - Tonga
+ - Trinidad and Tobago
+ - Tunisia
+ - Turkey
+ - Turkmenistan
+ - Turks and Caicos Islands
+ - Tuvalu
+ - Virgin Islands
+ - Uganda
+ - Ukraine
+ - United Arab Emirates
+ - United Kingdom
+ - United States
+ - United States Minor Outlying Islands
+ - Uruguay
+ - Uzbekistan
+ - Vanuatu
+ - Vatican City
+ - Venezuela
+ - Vietnam
+ - Wallis and Futuna
+ - Western Sahara
+ - Yemen
+ - Zambia
+ - Zimbabwe
+ - Yemen
+
+
diff --git a/tools/EditTextVariations/res/values/strings.xml b/tools/EditTextVariations/res/values/strings.xml
new file mode 100644
index 000000000..02387f2ff
--- /dev/null
+++ b/tools/EditTextVariations/res/values/strings.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+ EditTextVariations
+
+ Change Theme
+
+ Version %s
+
+ Navigate On
+
+ Navigate Off
+
+ Keyboard Visible
+
+ Keyboard Hidden
+
+ Custom
+
diff --git a/tools/EditTextVariations/res/values/themes.xml b/tools/EditTextVariations/res/values/themes.xml
new file mode 100644
index 000000000..036a7111b
--- /dev/null
+++ b/tools/EditTextVariations/res/values/themes.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/EchoingTextWatcher.java b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/EchoingTextWatcher.java
new file mode 100644
index 000000000..1c652c2a2
--- /dev/null
+++ b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/EchoingTextWatcher.java
@@ -0,0 +1,86 @@
+/*
+ * 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.tools.edittextvariations;
+
+import android.annotation.SuppressLint;
+import android.os.Handler;
+import android.os.Message;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.widget.EditText;
+
+import java.util.Locale;
+
+final class EchoingTextWatcher implements TextWatcher {
+ private static final int SET_TEXT_DELAY = 500;
+
+ final EditText mEditText;
+ CharSequence mExpected;
+
+ @SuppressLint("HandlerLeak")
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(final Message msg) {
+ final String toBeappended = (String) msg.obj;
+ final CharSequence current = mEditText.getText();
+ final CharSequence newText = TextUtils.concat(current, toBeappended);
+ mExpected = newText;
+ mEditText.setText(newText);
+ mEditText.setSelection(newText.length());
+ }
+ };
+
+ @SuppressWarnings("unused")
+ public static void attachTo(final EditText editText) {
+ final EchoingTextWatcher watcher = new EchoingTextWatcher(editText);
+ }
+
+ public EchoingTextWatcher(final EditText editText) {
+ mEditText = editText;
+ editText.addTextChangedListener(this);
+ }
+
+ @Override
+ public void afterTextChanged(final Editable ss) {
+ }
+
+ @Override
+ public void beforeTextChanged(final CharSequence s, final int start, final int count,
+ final int after) {
+ }
+
+ @Override
+ public void onTextChanged(final CharSequence s, final int start, final int before,
+ final int count) {
+ if (count == 0 || before > 0 || TextUtils.equals(s, mExpected)) {
+ return;
+ }
+ final int len = s.length();
+ if (len > 0) {
+ final String last = s.subSequence(len - 1, len).toString();
+ final char lastChar = last.charAt(0);
+ if (Character.isUpperCase(lastChar)) {
+ final String lowerCase = last.toLowerCase(Locale.getDefault());
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0, lowerCase), SET_TEXT_DELAY);
+ } else if (Character.isLowerCase(lastChar)) {
+ final String upperCase = last.toUpperCase(Locale.getDefault());
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0, upperCase), SET_TEXT_DELAY);
+ }
+ }
+ }
+}
diff --git a/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/EditTextVariations.java b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/EditTextVariations.java
new file mode 100644
index 000000000..44e0a4d55
--- /dev/null
+++ b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/EditTextVariations.java
@@ -0,0 +1,473 @@
+/*
+ * Copyright (C) 2010 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.tools.edittextvariations;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class EditTextVariations extends Activity implements TextView.OnEditorActionListener,
+ DialogInterface.OnClickListener {
+ private static final String TAG = EditTextVariations.class.getSimpleName();
+ private static final boolean DEBUG_INPUT_TEXT = false;
+
+ private static final int MENU_CHANGE_THEME = 0;
+ private static final int MENU_VERSION = 1;
+ private static final int MENU_NAVIGATE_ON = 2;
+ private static final int MENU_NAVIGATE_OFF = 3;
+ private static final int MENU_SOFTINPUT_VISIBLE = 4;
+ private static final int MENU_SOFTINPUT_HIDDEN = 5;
+ private static final String PREF_THEME = "theme";
+ private static final String PREF_NAVIGATE = "navigate";
+ private static final String PREF_SOFTINPUT = "softinput";
+
+ private SharedPreferences prefs;
+ private View[] fields;
+
+ private static final FinalClassField ApplicationInfo_FLAG_SUPPORTS_RTL =
+ FinalClassField.newInstance(ApplicationInfo.class, "FLAG_SUPPORTS_RTL", 1 << 22);
+
+ // This flag should be defined IceCreamSandwich and later.
+ // Note that Froyo and Gingerbread have hidden IME_FLAG_NO_FULLSCREEN as
+ // value 0x80000000.
+ private static final FinalClassField EditorInfo_IME_FLAG_FORCE_ASCII =
+ FinalClassField.newInstance(EditorInfo.class, "IME_FLAG_FORCE_ASCII",
+ Build.VERSION.SDK_INT >= /* ICE_CREAM_SANDWICH */14 ? 0x80000000 : 0);
+
+ private ArrayAdapter mAutoCompleteAdapter;
+
+ /** Called when the activity is first created. */
+ @SuppressLint("SetJavaScriptEnabled")
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ getApplicationInfo().flags |= ApplicationInfo_FLAG_SUPPORTS_RTL.value;
+ prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ loadTheme();
+ loadSoftInputMode();
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ final String[] countries = getResources().getStringArray(R.array.countries_array);
+ mAutoCompleteAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_dropdown_item_1line, countries);
+
+ final boolean navigateMode = getNavigateMode();
+ final ViewGroup vg = (ViewGroup) findViewById(R.id.edit_text_list);
+ final int n = vg.getChildCount();
+ fields = new View[n];
+ for (int i = 0; i < n; i++) {
+ final View v = vg.getChildAt(i);
+ if (v instanceof EditText) {
+ final int id = v.getId();
+ final EditText e = (EditText) v;
+ int inputType = e.getInputType();
+ int imeOptions = e.getImeOptions();
+ if (id == R.id.text_auto_correct_previous) {
+ imeOptions &= ~EditorInfo.IME_MASK_ACTION;
+ imeOptions |= EditorInfo.IME_ACTION_PREVIOUS;
+ }
+ if (id == R.id.text_force_ascii_flag) {
+ imeOptions |= EditorInfo_IME_FLAG_FORCE_ASCII.value;
+ }
+ if (id == R.id.text_null) {
+ inputType = InputType.TYPE_NULL;
+ }
+ if (id == R.id.text_restarting) {
+ EchoingTextWatcher.attachTo(e);
+ }
+ if (navigateMode && i > 0) {
+ imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
+ }
+ if (navigateMode && i < n - 1) {
+ imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT;
+ }
+
+ e.setInputType(inputType);
+ e.setImeOptions(imeOptions);
+ setupHintText(e);
+ if (navigateMode) {
+ e.setOnEditorActionListener(this);
+ }
+ }
+ if (v instanceof AutoCompleteTextView) {
+ final AutoCompleteTextView e = (AutoCompleteTextView) v;
+ e.setAdapter(mAutoCompleteAdapter);
+ e.setThreshold(1);
+ }
+ if (v instanceof WebView) {
+ final WebView wv = (WebView) v;
+ wv.getSettings().setJavaScriptEnabled(true);
+ wv.addJavascriptInterface(new Object() {
+ @JavascriptInterface
+ public String name() {
+ return getThemeName();
+ }
+ }, "theme");
+ wv.loadUrl("file:///android_asset/webview.html");
+ }
+ fields[i] = v;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ menu.add(Menu.NONE, MENU_NAVIGATE_ON, 0, getString(R.string.menu_navigate_on));
+ menu.add(Menu.NONE, MENU_NAVIGATE_OFF, 1, getString(R.string.menu_navigate_off));
+ menu.add(Menu.NONE, MENU_SOFTINPUT_VISIBLE, 2, getString(R.string.menu_softinput_visible));
+ menu.add(Menu.NONE, MENU_SOFTINPUT_HIDDEN, 3, getString(R.string.menu_softinput_hidden));
+ menu.add(Menu.NONE, MENU_CHANGE_THEME, 4, R.string.menu_change_theme);
+ try {
+ final PackageInfo pinfo = getPackageManager().getPackageInfo(getPackageName(), 0);
+ menu.add(Menu.NONE, MENU_VERSION, 5,
+ getString(R.string.menu_version, pinfo.versionName))
+ .setEnabled(false);
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ final int itemId = item.getItemId();
+ if (itemId == MENU_CHANGE_THEME) {
+ final List items = new ArrayList<>();
+ for (final ThemeItem theme : ThemeItem.THEME_LIST) {
+ items.add(theme.name);
+ }
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.menu_change_theme);
+ builder.setCancelable(true);
+ builder.setNegativeButton(android.R.string.cancel, null);
+ builder.setItems(items.toArray(new CharSequence[items.size()]), this);
+ builder.show();
+ } else if (itemId == MENU_NAVIGATE_ON || itemId == MENU_NAVIGATE_OFF) {
+ saveNavigateMode(itemId == MENU_NAVIGATE_ON);
+ restartActivity();
+ } else if (itemId == MENU_SOFTINPUT_VISIBLE || itemId == MENU_SOFTINPUT_HIDDEN) {
+ saveSoftInputMode(itemId == MENU_SOFTINPUT_VISIBLE);
+ restartActivity();
+ }
+ return true;
+ }
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ saveTheme(ThemeItem.THEME_LIST.get(which));
+ restartActivity();
+ }
+
+ private void restartActivity() {
+ final Intent intent = getIntent();
+ finish();
+ startActivity(intent);
+ }
+
+ private static void setupHintText(final EditText e) {
+ final int imeOptions = e.getImeOptions();
+ String hint = (e instanceof MultiLineShortMessageEditText) ? "*" : "";
+ hint += inputTypeToString(e.getInputType());
+ String text;
+ if (e.getImeActionLabel() != null) {
+ text = "actionLabel<" + e.getImeActionLabel() + ":" + e.getImeActionId() + ">";
+ } else {
+ text = actionName(imeOptions & EditorInfo.IME_MASK_ACTION);
+ }
+ text = appendFlagText(text,
+ (imeOptions & EditorInfo.IME_FLAG_NO_EXTRACT_UI) != 0, "flagNoExtractUi");
+ text = appendFlagText(text,
+ (imeOptions & EditorInfo.IME_FLAG_NO_FULLSCREEN) != 0, "flagNoFullscreen");
+ text = appendFlagText(text,
+ (imeOptions & EditorInfo_IME_FLAG_FORCE_ASCII.value) != 0, "flagForceAscii");
+ text = appendFlagText(text,
+ (imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0, ">");
+ text = appendFlagText(text,
+ (imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0, "<");
+ if (text.length() > 0)
+ hint += " " + text;
+ final String privateOptions = e.getPrivateImeOptions();
+ if (!TextUtils.isEmpty(privateOptions)) {
+ hint += " (";
+ String sep = "";
+ for (final String opt : privateOptions.trim().split(",")) {
+ final String[] elem = opt.trim().split("\\.");
+ hint += sep + elem[elem.length - 1];
+ sep = ",";
+ }
+ hint += ")";
+ }
+ if (DEBUG_INPUT_TEXT) {
+ Log.d(TAG, String.format("class=0x%08x variation=0x%08x flags=0x%08x hint=%s",
+ e.getInputType() & InputType.TYPE_MASK_CLASS,
+ e.getInputType() & InputType.TYPE_MASK_VARIATION,
+ e.getInputType() & InputType.TYPE_MASK_FLAGS, hint));
+ }
+ if (e.getId() == R.id.text_restarting) {
+ hint += " restarting";
+ }
+ e.setHint(hint);
+ }
+
+ private void saveBooleanPreference(final String key, final boolean value) {
+ final SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(key, value);
+ editor.apply();
+ }
+
+ private void saveStringPreference(final String key, final String value) {
+ final SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(key, value);
+ editor.apply();
+ }
+
+ private void saveNavigateMode(final boolean enabled) {
+ saveBooleanPreference(PREF_NAVIGATE, enabled);
+ }
+
+ private boolean getNavigateMode() {
+ return prefs.getBoolean(PREF_NAVIGATE, false);
+ }
+
+ private void saveSoftInputMode(final boolean visible) {
+ saveBooleanPreference(PREF_SOFTINPUT, visible);
+ }
+
+ private void loadSoftInputMode() {
+ final boolean visible = prefs.getBoolean(PREF_SOFTINPUT, false);
+ final Window w = getWindow();
+ w.setSoftInputMode(visible
+ ? WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE
+ : WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
+ }
+
+ private void saveTheme(final ThemeItem theme) {
+ saveStringPreference(PREF_THEME, theme.name);
+ }
+
+ String getThemeName() {
+ return prefs.getString(PREF_THEME, ThemeItem.getDefaultThemeName());
+ }
+
+ private void loadTheme() {
+ final String themeName = getThemeName();
+ for (final ThemeItem theme : ThemeItem.THEME_LIST) {
+ if (themeName.equals(theme.name)) {
+ setTheme(theme.id);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public boolean onEditorAction(final TextView v, final int action, final KeyEvent event) {
+ for (int i = 0; i < fields.length; i++) {
+ if (v == fields[i]) {
+ final int direction;
+ if (action == EditorInfo.IME_ACTION_PREVIOUS) {
+ direction = -1;
+ } else {
+ direction = +1;
+ }
+
+ final int target = i + direction;
+ if (target < 0 || target >= fields.length)
+ return false;
+
+ final View targetView = fields[target];
+ targetView.requestFocus();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String actionName(final int action) {
+ switch (action & EditorInfo.IME_MASK_ACTION) {
+ case EditorInfo.IME_ACTION_UNSPECIFIED:
+ return "actionUnspecified";
+ case EditorInfo.IME_ACTION_NONE:
+ return "actionNone";
+ case EditorInfo.IME_ACTION_GO:
+ return "actionGo";
+ case EditorInfo.IME_ACTION_SEARCH:
+ return "actionSearch";
+ case EditorInfo.IME_ACTION_SEND:
+ return "actionSend";
+ case EditorInfo.IME_ACTION_NEXT:
+ return "actionNext";
+ case EditorInfo.IME_ACTION_DONE:
+ return "actionDone";
+ case EditorInfo.IME_ACTION_PREVIOUS:
+ return "actionPrevious";
+ default:
+ return "actionUnknown(" + action + ")";
+ }
+ }
+
+ private static String inputTypeToString(final int inputType) {
+ if (inputType == InputType.TYPE_NULL) {
+ return "TYPE_NULL";
+ }
+ final int clazz = inputType & InputType.TYPE_MASK_CLASS;
+ final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+ final int flags = inputType & InputType.TYPE_MASK_FLAGS;
+ String base = "unknown(class=" + clazz + " variation=" + variation + " flag=0x"
+ + Integer.toHexString(flags);
+
+ switch (clazz) {
+ case InputType.TYPE_CLASS_TEXT:
+ switch (variation) {
+ case InputType.TYPE_TEXT_VARIATION_NORMAL:
+ base = "text";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_URI:
+ base = "textUri";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS:
+ base = "textEmailAddress";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT:
+ base = "textEmailSubject";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE:
+ base = "textShortMessage";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE:
+ base = "textLongMessage";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_PERSON_NAME:
+ base = "textPersonName";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS:
+ base = "textPostalAddress";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_PASSWORD:
+ base = "textPassword";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD:
+ base = "textVisiblePassword";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT:
+ base = "textWebEditText";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_FILTER:
+ base = "textFilter";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_PHONETIC:
+ base = "textPhonetic";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS:
+ base = "textWebEmailAddress";
+ break;
+ case InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD:
+ base = "textWebPassword";
+ break;
+ }
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) != 0,
+ "textCapCharacters");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0,
+ "textCapWords");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) != 0,
+ "textCapSentences");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) != 0,
+ "textAutoCorrect");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0,
+ "textAutoComplete");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0,
+ "textMultiLine");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0,
+ "textImeMultiLine");
+ base = appendFlagText(base, (flags & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) != 0,
+ "textNoSuggestions");
+ break;
+
+ case InputType.TYPE_CLASS_NUMBER:
+ if (variation == InputType.TYPE_NUMBER_VARIATION_NORMAL) {
+ base = "number";
+ } else if (variation == InputType.TYPE_NUMBER_VARIATION_PASSWORD) {
+ base = "numberPassword";
+ }
+ base = appendFlagText(base, (flags & InputType.TYPE_NUMBER_FLAG_SIGNED) != 0,
+ "numberSigned");
+ base = appendFlagText(base, (flags & InputType.TYPE_NUMBER_FLAG_DECIMAL) != 0,
+ "numberDecimal");
+ break;
+
+ case InputType.TYPE_CLASS_PHONE:
+ base = "phone";
+ break;
+
+ case InputType.TYPE_CLASS_DATETIME:
+ switch (variation) {
+ case InputType.TYPE_DATETIME_VARIATION_NORMAL:
+ base = "datetime";
+ break;
+ case InputType.TYPE_DATETIME_VARIATION_DATE:
+ base = "date";
+ break;
+ case InputType.TYPE_DATETIME_VARIATION_TIME:
+ base = "time";
+ break;
+ }
+ break;
+ }
+
+ return base;
+ }
+
+ private static String appendFlagText(final String text, final boolean flag, final String name) {
+ if (flag) {
+ if (text.length() == 0 || name.startsWith(text))
+ return name;
+ return text + "|" + name;
+ }
+ return text;
+ }
+}
diff --git a/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/FinalClassField.java b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/FinalClassField.java
new file mode 100644
index 000000000..14c556a67
--- /dev/null
+++ b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/FinalClassField.java
@@ -0,0 +1,64 @@
+/*
+ * 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.tools.edittextvariations;
+
+import java.lang.reflect.Field;
+
+public final class FinalClassField {
+ public final boolean defined;
+ public final String name;
+ public final String className;
+ public final T value;
+
+ @SuppressWarnings("unchecked")
+ private FinalClassField(final Field field, final String className, final String fieldName,
+ final T compatValue) {
+ this.defined = field != null;
+ this.name = fieldName;
+ this.className = className;
+ T v = null;
+ try {
+ final Object obj = field.get(null);
+ v = (T) obj;
+ } catch (final Exception e) {
+ v = compatValue;
+ }
+ this.value = v;
+ }
+
+ public static FinalClassField newInstance(final Class> definedClass, final String name,
+ final T compatValue) {
+ if (definedClass == null)
+ throw new NullPointerException("defined class");
+ String className = definedClass.getCanonicalName();
+ try {
+ return new FinalClassField<>(
+ definedClass.getField(name), className, name, compatValue);
+ } catch (Exception e) {
+ return new FinalClassField<>(null, className, name, compatValue);
+ }
+ }
+
+ public static FinalClassField newInstance(final String className, final String fieldName,
+ final T compatValue) {
+ try {
+ return newInstance(Class.forName(className), fieldName, compatValue);
+ } catch (ClassNotFoundException e) {
+ return new FinalClassField<>(null, className, fieldName, compatValue);
+ }
+ }
+}
diff --git a/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/InstanceMethod.java b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/InstanceMethod.java
new file mode 100644
index 000000000..05dc0d6dc
--- /dev/null
+++ b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/InstanceMethod.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 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.tools.edittextvariations;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public final class InstanceMethod {
+ public final boolean defined;
+ public final String name;
+ public final String className;
+
+ private final Class> clazz;
+ private final Method method;
+
+ private InstanceMethod(final Class> receiverClass, final Method instanceMethod,
+ final String receiverName, final String methodName) {
+ this.defined = instanceMethod != null;
+ this.clazz = receiverClass;
+ this.method = instanceMethod;
+ this.name = methodName;
+ this.className = receiverName;
+ }
+
+ public Object invoke(final Object receiverObject, final Object... args) {
+ if (!defined)
+ throw new RuntimeException("method " + name + " not defined");
+ if (receiverObject == null)
+ throw new NullPointerException("receiver object");
+ if (clazz.isInstance(receiverObject)) {
+ try {
+ if (args.length == 0) {
+ return method.invoke(receiverObject);
+ }
+ return method.invoke(clazz, args);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException("IllegalArgumentException");
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("IllegalAccessException");
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException("InvocationTargetException");
+ }
+ }
+ throw new RuntimeException("receiver type not matched: method=" + name
+ + " actual receiver=" + receiverObject.getClass().getCanonicalName());
+ }
+
+ public static InstanceMethod newInstance(final Class> receiverClass, final String methodName,
+ final Class>... parameterTypes) {
+ if (receiverClass == null)
+ throw new NullPointerException("receiver class");
+ final String className = receiverClass.getCanonicalName();
+ try {
+ return new InstanceMethod(receiverClass,
+ receiverClass.getMethod(methodName, parameterTypes), className, methodName);
+ } catch (Exception e) {
+ return new InstanceMethod(receiverClass, null, className, methodName);
+ }
+ }
+
+ public static InstanceMethod newInstance(final String className, final String methodName,
+ final Class>... parameterTypes) {
+ try {
+ return newInstance(Class.forName(className), methodName, parameterTypes);
+ } catch (ClassNotFoundException e) {
+ return new InstanceMethod(null, null, className, methodName);
+ }
+ }
+}
diff --git a/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/MultiLineShortMessageEditText.java b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/MultiLineShortMessageEditText.java
new file mode 100644
index 000000000..7ab700776
--- /dev/null
+++ b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/MultiLineShortMessageEditText.java
@@ -0,0 +1,46 @@
+/*
+ * 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.tools.edittextvariations;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+
+public final class MultiLineShortMessageEditText extends EditText {
+
+ public MultiLineShortMessageEditText(final Context context) {
+ super(context);
+ }
+
+ public MultiLineShortMessageEditText(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MultiLineShortMessageEditText(final Context context, final AttributeSet attrs,
+ final int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(final EditorInfo outAttrs) {
+ final InputConnection ic = super.onCreateInputConnection(outAttrs);
+ outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ return ic;
+ }
+}
diff --git a/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/ThemeItem.java b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/ThemeItem.java
new file mode 100644
index 000000000..f3c6d4f54
--- /dev/null
+++ b/tools/EditTextVariations/src/com/android/inputmethod/tools/edittextvariations/ThemeItem.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 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.tools.edittextvariations;
+
+import android.os.Build;
+
+import com.android.inputmethod.tools.edittextvariations.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public final class ThemeItem {
+ public final int id;
+ public final String name;
+
+ private ThemeItem(final String name, final int resId) {
+ this.id = resId;
+ this.name = name;
+ }
+
+ private static final String THEME_DEFAULT = "Default";
+ private static final String THEME_HOLO = "Theme_Holo";
+ private static final String THEME_HOLO_LIGHT = "Theme_Holo_Light";
+ private static final String THEME_DEVICE_DEFAULT = "Theme_DeviceDefault";
+ private static final String THEME_DEVICE_DEFAULT_LIGHT = "Theme_DeviceDefault_Light";
+ private static final String THEME_MATERIAL = "Theme_Material";
+ private static final String THEME_MATERIAL_LIGHT = "Theme_Material_Light";
+
+ public static String getDefaultThemeName() {
+ return THEME_DEFAULT;
+ }
+
+ public static final List THEME_LIST = createThemeList(
+ THEME_HOLO, THEME_HOLO_LIGHT, THEME_DEVICE_DEFAULT, THEME_DEVICE_DEFAULT_LIGHT,
+ THEME_MATERIAL, THEME_MATERIAL_LIGHT);
+
+ private static List createThemeList(final String... candidateList) {
+ final ArrayList list = new ArrayList<>();
+
+ // Default theme is always available as it's defined in our resource.
+ list.add(new ThemeItem(THEME_DEFAULT, R.style.defaultActivityTheme));
+
+ for (final String name : candidateList) {
+ final FinalClassField constant =
+ FinalClassField.newInstance(android.R.style.class, name, 0);
+ if (constant.defined) {
+ list.add(new ThemeItem(name, constant.value));
+ }
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+}