diff options
author | 2018-05-22 10:31:28 -0700 | |
---|---|---|
committer | 2018-05-22 10:31:28 -0700 | |
commit | f97da47c024f01fddc466db4efb3200d0b37ae49 (patch) | |
tree | bf3e9891a01142c2344300e2e7bb532d98a2db7e /tools/EditTextVariations/src | |
parent | a3b17c255d11eab519615ac37507b17f648a33bc (diff) | |
download | latinime-f97da47c024f01fddc466db4efb3200d0b37ae49.tar.gz latinime-f97da47c024f01fddc466db4efb3200d0b37ae49.tar.xz latinime-f97da47c024f01fddc466db4efb3200d0b37ae49.zip |
Opensource a test tool called EditTextVariations
This CL opensouces a testing tool called EditTextVariations that has
been used internally to test IME behaviors on various
EditorInfo#inputType and EditorInfo#imeOptions.
Bug: 80039502
Test: Manually verified as follows.
1. tapas EditTextVariations
2. make -j
3. adb install -r $ANDROID_TARGET_OUT_TESTCASES/EditTextVariations/EditTextVariations.apk
Change-Id: Ia87e655573c2fd1fc09d56e4af90bfb1dfd65f9b
Diffstat (limited to 'tools/EditTextVariations/src')
6 files changed, 820 insertions, 0 deletions
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<Integer> 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<Integer> 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<String> 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<CharSequence> 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<T> { + 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 <T> FinalClassField<T> 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 <T> FinalClassField<T> 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<ThemeItem> THEME_LIST = createThemeList( + THEME_HOLO, THEME_HOLO_LIGHT, THEME_DEVICE_DEFAULT, THEME_DEVICE_DEFAULT_LIGHT, + THEME_MATERIAL, THEME_MATERIAL_LIGHT); + + private static List<ThemeItem> createThemeList(final String... candidateList) { + final ArrayList<ThemeItem> 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<Integer> constant = + FinalClassField.newInstance(android.R.style.class, name, 0); + if (constant.defined) { + list.add(new ThemeItem(name, constant.value)); + } + } + + return Collections.unmodifiableList(list); + } +} |