diff options
36 files changed, 526 insertions, 301 deletions
diff --git a/java/res/values/predefined-subtypes.xml b/java/res/values/predefined-subtypes.xml index 602f53eac..3bf0e617f 100644 --- a/java/res/values/predefined-subtypes.xml +++ b/java/res/values/predefined-subtypes.xml @@ -18,6 +18,9 @@ */ --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <!-- Predefined subtypes (language:layout[:extraValue]) in semicolon separated format --> - <string name="predefined_subtypes" translatable="false">de:qwerty:AsciiCapable;fr:qwertz:AsciiCapable</string> + <!-- Predefined subtypes (language:layout[:extraValue]) --> + <string-array name="predefined_subtypes" translatable="false"> + <item>de:qwerty:AsciiCapable</item> + <item>fr:qwertz:AsciiCapable</item> + </string-array> </resources> diff --git a/java/res/xml-sw600dp/row_symbols4.xml b/java/res/xml-sw600dp/row_symbols4.xml index 73a5b1703..f138d8ef4 100644 --- a/java/res/xml-sw600dp/row_symbols4.xml +++ b/java/res/xml-sw600dp/row_symbols4.xml @@ -41,6 +41,8 @@ latin:moreKeys="!text/more_keys_for_tablet_double_quote" /> <Key latin:keyLabel="_" /> - <!-- Here is empty space. --> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/row_symbols_shift4.xml b/java/res/xml-sw600dp/row_symbols_shift4.xml index 6f3aac7c6..29befa92a 100644 --- a/java/res/xml-sw600dp/row_symbols_shift4.xml +++ b/java/res/xml-sw600dp/row_symbols_shift4.xml @@ -33,6 +33,8 @@ latin:keyXPos="28.0%p" latin:keyboardLayout="@xml/key_space" latin:backgroundType="normal" /> - <!-- Here is empty space. --> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml index 48b304089..f69239456 100644 --- a/java/res/xml-sw600dp/rows_number_normal.xml +++ b/java/res/xml-sw600dp/rows_number_normal.xml @@ -153,5 +153,8 @@ <Key latin:keyLabel="#" latin:keyStyle="numKeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw768dp/row_dvorak4.xml b/java/res/xml-sw768dp/row_dvorak4.xml index 0827815c9..8f9230d4a 100644 --- a/java/res/xml-sw768dp/row_dvorak4.xml +++ b/java/res/xml-sw768dp/row_dvorak4.xml @@ -25,8 +25,10 @@ latin:keyWidth="8.047%p" latin:backgroundType="functional" > + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="5.782%p" /> <include - latin:keyXPos="5.782%p" latin:keyboardLayout="@xml/key_settings" /> <include latin:keyboardLayout="@xml/key_shortcut" /> @@ -42,5 +44,8 @@ latin:keyboardLayout="@xml/key_dash" /> <include latin:keyboardLayout="@xml/key_f2" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw768dp/row_hebrew4.xml b/java/res/xml-sw768dp/row_hebrew4.xml index 180c5641d..ae14f0296 100644 --- a/java/res/xml-sw768dp/row_hebrew4.xml +++ b/java/res/xml-sw768dp/row_hebrew4.xml @@ -25,8 +25,10 @@ latin:keyWidth="8.047%p" latin:backgroundType="functional" > + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="5.782%p" /> <include - latin:keyXPos="5.782%p" latin:keyboardLayout="@xml/key_settings" /> <include latin:keyboardLayout="@xml/key_shortcut" /> @@ -40,5 +42,8 @@ latin:keyboardLayout="@xml/keys_comma_period" /> <include latin:keyboardLayout="@xml/key_f2" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw768dp/row_qwerty4.xml b/java/res/xml-sw768dp/row_qwerty4.xml index 92411f54e..f1f4214ca 100644 --- a/java/res/xml-sw768dp/row_qwerty4.xml +++ b/java/res/xml-sw768dp/row_qwerty4.xml @@ -25,8 +25,10 @@ latin:keyWidth="8.047%p" latin:backgroundType="functional" > + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="5.782%p" /> <include - latin:keyXPos="5.782%p" latin:keyboardLayout="@xml/key_settings" /> <include latin:keyboardLayout="@xml/key_shortcut" /> @@ -42,5 +44,8 @@ latin:keyboardLayout="@xml/key_dash" /> <include latin:keyboardLayout="@xml/key_f2" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw768dp/row_symbols4.xml b/java/res/xml-sw768dp/row_symbols4.xml index 4e1c11994..b801a12a7 100644 --- a/java/res/xml-sw768dp/row_symbols4.xml +++ b/java/res/xml-sw768dp/row_symbols4.xml @@ -25,8 +25,10 @@ latin:keyWidth="8.047%p" latin:backgroundType="functional" > + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="13.829%p" /> <Key - latin:keyXPos="13.829%p" latin:keyLabel="/" /> <include latin:keyboardLayout="@xml/key_f1" /> @@ -39,6 +41,8 @@ latin:moreKeys="!text/more_keys_for_tablet_double_quote" /> <Key latin:keyLabel="_" /> - <!-- Here is empty space. --> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw768dp/row_symbols_shift4.xml b/java/res/xml-sw768dp/row_symbols_shift4.xml index 561351cab..f71864bc3 100644 --- a/java/res/xml-sw768dp/row_symbols_shift4.xml +++ b/java/res/xml-sw768dp/row_symbols_shift4.xml @@ -25,11 +25,14 @@ latin:keyWidth="8.047%p" latin:backgroundType="functional" > - <!-- Here is empty space. --> + <!-- Note: This Spacer prevents the below key from being marked as a left edge key. --> + <Spacer + latin:keyWidth="29.923%p" /> <include - latin:keyXPos="29.923%p" latin:keyboardLayout="@xml/key_space" latin:backgroundType="normal" /> - <!-- Here is empty space. --> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml index 84910a88f..d4d7c722a 100644 --- a/java/res/xml-sw768dp/rows_number_normal.xml +++ b/java/res/xml-sw768dp/rows_number_normal.xml @@ -168,5 +168,8 @@ <Key latin:keyLabel="#" latin:keyStyle="numKeyStyle" /> + <!-- Note: This Spacer prevents the above key from being marked as a right edge key. --> + <Spacer + latin:keyWidth="fillRight" /> </Row> </merge> diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java index 868c8cab5..f5686dcda 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java +++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java @@ -83,11 +83,17 @@ public class KeyDetector { int minDistance = Integer.MAX_VALUE; Key primaryKey = null; for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) { - final boolean isOnKey = key.isOnKey(touchX, touchY); + // An edge key always has its enlarged hitbox to respond to an event that occurred in + // the empty area around the key. (@see Key#markAsLeftEdge(KeyboardParams)} etc.) + if (!key.isOnKey(touchX, touchY)) { + continue; + } final int distance = key.squaredDistanceToEdge(touchX, touchY); + if (distance > minDistance) { + continue; + } // To take care of hitbox overlaps, we compare mCode here too. - if (primaryKey == null || distance < minDistance - || (distance == minDistance && isOnKey && key.mCode > primaryKey.mCode)) { + if (primaryKey == null || distance < minDistance || key.mCode > primaryKey.mCode) { minDistance = distance; primaryKey = key; } diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java index 4b47a261f..509fc1ba3 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java @@ -27,22 +27,22 @@ import android.view.inputmethod.InputMethodSubtype; import java.util.ArrayList; -public class AdditionalSubtype { +public final class AdditionalSubtype { private static final InputMethodSubtype[] EMPTY_SUBTYPE_ARRAY = new InputMethodSubtype[0]; private AdditionalSubtype() { // This utility class is not publicly instantiable. } - public static boolean isAdditionalSubtype(InputMethodSubtype subtype) { + public static boolean isAdditionalSubtype(final InputMethodSubtype subtype) { return subtype.containsExtraValueKey(IS_ADDITIONAL_SUBTYPE); } private static final String LOCALE_AND_LAYOUT_SEPARATOR = ":"; - public static final String PREF_SUBTYPE_SEPARATOR = ";"; + private static final String PREF_SUBTYPE_SEPARATOR = ";"; - public static InputMethodSubtype createAdditionalSubtype( - String localeString, String keyboardLayoutSetName, String extraValue) { + public static InputMethodSubtype createAdditionalSubtype(final String localeString, + final String keyboardLayoutSetName, final String extraValue) { final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; final String layoutDisplayNameExtraValue; if (Build.VERSION.SDK_INT >= /* JELLY_BEAN */ 15 @@ -62,7 +62,7 @@ public class AdditionalSubtype { layoutExtraValue + "," + additionalSubtypeExtraValue, false, false); } - public static String getPrefSubtype(InputMethodSubtype subtype) { + public static String getPrefSubtype(final InputMethodSubtype subtype) { final String localeString = subtype.getLocale(); final String keyboardLayoutSetName = SubtypeLocale.getKeyboardLayoutSetName(subtype); final String layoutExtraValue = KEYBOARD_LAYOUT_SET + "=" + keyboardLayoutSetName; @@ -74,7 +74,7 @@ public class AdditionalSubtype { : basePrefSubtype + LOCALE_AND_LAYOUT_SEPARATOR + extraValue; } - public static InputMethodSubtype createAdditionalSubtype(String prefSubtype) { + public static InputMethodSubtype createAdditionalSubtype(final String prefSubtype) { final String elems[] = prefSubtype.split(LOCALE_AND_LAYOUT_SEPARATOR); if (elems.length < 2 || elems.length > 3) { throw new RuntimeException("Unknown additional subtype specified: " + prefSubtype); @@ -85,7 +85,7 @@ public class AdditionalSubtype { return createAdditionalSubtype(localeString, keyboardLayoutSetName, extraValue); } - public static InputMethodSubtype[] createAdditionalSubtypesArray(String prefSubtypes) { + public static InputMethodSubtype[] createAdditionalSubtypesArray(final String prefSubtypes) { if (TextUtils.isEmpty(prefSubtypes)) { return EMPTY_SUBTYPE_ARRAY; } @@ -103,4 +103,32 @@ public class AdditionalSubtype { } return subtypesList.toArray(new InputMethodSubtype[subtypesList.size()]); } + + public static String createPrefSubtypes(final InputMethodSubtype[] subtypes) { + if (subtypes == null || subtypes.length == 0) { + return ""; + } + final StringBuilder sb = new StringBuilder(); + for (final InputMethodSubtype subtype : subtypes) { + if (sb.length() > 0) { + sb.append(PREF_SUBTYPE_SEPARATOR); + } + sb.append(getPrefSubtype(subtype)); + } + return sb.toString(); + } + + public static String createPrefSubtypes(final String[] prefSubtypes) { + if (prefSubtypes == null || prefSubtypes.length == 0) { + return ""; + } + final StringBuilder sb = new StringBuilder(); + for (final String prefSubtype : prefSubtypes) { + if (sb.length() > 0) { + sb.append(PREF_SUBTYPE_SEPARATOR); + } + sb.append(prefSubtype); + } + return sb.toString(); + } } diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java index d01592a4d..ae51d2537 100644 --- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java +++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java @@ -63,13 +63,13 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { private static final String KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN = "is_subtype_enabler_notification_dialog_open"; private static final String KEY_SUBTYPE_FOR_SUBTYPE_ENABLER = "subtype_for_subtype_enabler"; - static class SubtypeLocaleItem extends Pair<String, String> + static final class SubtypeLocaleItem extends Pair<String, String> implements Comparable<SubtypeLocaleItem> { - public SubtypeLocaleItem(String localeString, String displayName) { + public SubtypeLocaleItem(final String localeString, final String displayName) { super(localeString, displayName); } - public SubtypeLocaleItem(String localeString) { + public SubtypeLocaleItem(final String localeString) { this(localeString, SubtypeLocale.getSubtypeLocaleDisplayName(localeString)); } @@ -79,13 +79,13 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public int compareTo(SubtypeLocaleItem o) { + public int compareTo(final SubtypeLocaleItem o) { return first.compareTo(o.first); } } - static class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> { - public SubtypeLocaleAdapter(Context context) { + static final class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> { + public SubtypeLocaleAdapter(final Context context) { super(context, android.R.layout.simple_spinner_item); setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); @@ -102,7 +102,8 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { addAll(items); } - public static SubtypeLocaleItem createItem(Context context, String localeString) { + public static SubtypeLocaleItem createItem(final Context context, + final String localeString) { if (localeString.equals(SubtypeLocale.NO_LANGUAGE)) { final String displayName = context.getString(R.string.subtype_no_language); return new SubtypeLocaleItem(localeString, displayName); @@ -112,8 +113,8 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } } - static class KeyboardLayoutSetItem extends Pair<String, String> { - public KeyboardLayoutSetItem(InputMethodSubtype subtype) { + static final class KeyboardLayoutSetItem extends Pair<String, String> { + public KeyboardLayoutSetItem(final InputMethodSubtype subtype) { super(SubtypeLocale.getKeyboardLayoutSetName(subtype), SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype)); } @@ -124,8 +125,8 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } } - static class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> { - public KeyboardLayoutSetAdapter(Context context) { + static final class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> { + public KeyboardLayoutSetAdapter(final Context context) { super(context, android.R.layout.simple_spinner_item); setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); @@ -147,7 +148,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter(); } - static class SubtypePreference extends DialogPreference + static final class SubtypePreference extends DialogPreference implements DialogInterface.OnCancelListener { private static final String KEY_PREFIX = "subtype_pref_"; private static final String KEY_NEW_SUBTYPE = KEY_PREFIX + "new"; @@ -159,13 +160,13 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { private Spinner mSubtypeLocaleSpinner; private Spinner mKeyboardLayoutSetSpinner; - public static SubtypePreference newIncompleteSubtypePreference( - Context context, SubtypeDialogProxy proxy) { + public static SubtypePreference newIncompleteSubtypePreference(final Context context, + final SubtypeDialogProxy proxy) { return new SubtypePreference(context, null, proxy); } - public SubtypePreference(Context context, InputMethodSubtype subtype, - SubtypeDialogProxy proxy) { + public SubtypePreference(final Context context, final InputMethodSubtype subtype, + final SubtypeDialogProxy proxy) { super(context, null); setDialogLayoutResource(R.layout.additional_subtype_dialog); setPersistent(false); @@ -185,7 +186,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { return mSubtype; } - public void setSubtype(InputMethodSubtype subtype) { + public void setSubtype(final InputMethodSubtype subtype) { mPreviousSubtype = mSubtype; mSubtype = subtype; if (isIncomplete()) { @@ -221,7 +222,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) { final Context context = builder.getContext(); builder.setCancelable(true).setOnCancelListener(this); if (isIncomplete()) { @@ -239,7 +240,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } } - private static void setSpinnerPosition(Spinner spinner, Object itemToSelect) { + private static void setSpinnerPosition(final Spinner spinner, final Object itemToSelect) { final SpinnerAdapter adapter = spinner.getAdapter(); final int count = adapter.getCount(); for (int i = 0; i < count; i++) { @@ -252,14 +253,14 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onCancel(DialogInterface dialog) { + public void onCancel(final DialogInterface dialog) { if (isIncomplete()) { mProxy.onRemovePressed(this); } } @Override - public void onClick(DialogInterface dialog, int which) { + public void onClick(final DialogInterface dialog, final int which) { super.onClick(dialog, which); switch (which) { case DialogInterface.BUTTON_POSITIVE: @@ -287,12 +288,12 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } } - private static int getSpinnerPosition(Spinner spinner) { + private static int getSpinnerPosition(final Spinner spinner) { if (spinner == null) return -1; return spinner.getSelectedItemPosition(); } - private static void setSpinnerPosition(Spinner spinner, int position) { + private static void setSpinnerPosition(final Spinner spinner, final int position) { if (spinner == null || position < 0) return; spinner.setSelection(position); } @@ -313,7 +314,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - protected void onRestoreInstanceState(Parcelable state) { + protected void onRestoreInstanceState(final Parcelable state) { if (!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; @@ -326,24 +327,24 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { setSubtype(myState.mSubtype); } - static class SavedState extends Preference.BaseSavedState { + static final class SavedState extends Preference.BaseSavedState { InputMethodSubtype mSubtype; int mSubtypeLocaleSelectedPos; int mKeyboardLayoutSetSelectedPos; - public SavedState(Parcelable superState) { + public SavedState(final Parcelable superState) { super(superState); } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(final Parcel dest, final int flags) { super.writeToParcel(dest, flags); dest.writeInt(mSubtypeLocaleSelectedPos); dest.writeInt(mKeyboardLayoutSetSelectedPos); dest.writeParcelable(mSubtype, 0); } - public SavedState(Parcel source) { + public SavedState(final Parcel source) { super(source); mSubtypeLocaleSelectedPos = source.readInt(); mKeyboardLayoutSetSelectedPos = source.readInt(); @@ -354,12 +355,12 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { @Override - public SavedState createFromParcel(Parcel source) { + public SavedState createFromParcel(final Parcel source) { return new SavedState(source); } @Override - public SavedState[] newArray(int size) { + public SavedState[] newArray(final int size) { return new SavedState[size]; } }; @@ -371,7 +372,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.additional_subtype_settings); @@ -381,7 +382,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onActivityCreated(Bundle savedInstanceState) { + public void onActivityCreated(final Bundle savedInstanceState) { final Context context = getActivity(); mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context); mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context); @@ -411,7 +412,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onSaveInstanceState(Bundle outState) { + public void onSaveInstanceState(final Bundle outState) { super.onSaveInstanceState(outState); if (mIsAddingNewSubtype) { outState.putBoolean(KEY_IS_ADDING_NEW_SUBTYPE, true); @@ -426,7 +427,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { private final SubtypeDialogProxy mSubtypeProxy = new SubtypeDialogProxy() { @Override - public void onRemovePressed(SubtypePreference subtypePref) { + public void onRemovePressed(final SubtypePreference subtypePref) { mIsAddingNewSubtype = false; final PreferenceGroup group = getPreferenceScreen(); group.removePreference(subtypePref); @@ -434,7 +435,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onSavePressed(SubtypePreference subtypePref) { + public void onSavePressed(final SubtypePreference subtypePref) { final InputMethodSubtype subtype = subtypePref.getSubtype(); if (!subtypePref.hasBeenModified()) { return; @@ -453,7 +454,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onAddPressed(SubtypePreference subtypePref) { + public void onAddPressed(final SubtypePreference subtypePref) { mIsAddingNewSubtype = false; final InputMethodSubtype subtype = subtypePref.getSubtype(); if (findDuplicatedSubtype(subtype) == null) { @@ -481,7 +482,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } }; - private void showSubtypeAlreadyExistsToast(InputMethodSubtype subtype) { + private void showSubtypeAlreadyExistsToast(final InputMethodSubtype subtype) { final Context context = getActivity(); final Resources res = context.getResources(); final String message = res.getString(R.string.custom_input_style_already_exists, @@ -489,14 +490,15 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } - private InputMethodSubtype findDuplicatedSubtype(InputMethodSubtype subtype) { + private InputMethodSubtype findDuplicatedSubtype(final InputMethodSubtype subtype) { final String localeString = subtype.getLocale(); final String keyboardLayoutSetName = SubtypeLocale.getKeyboardLayoutSetName(subtype); return ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet( getActivity(), localeString, keyboardLayoutSetName); } - private AlertDialog createDialog(SubtypePreference subtypePref) { + private AlertDialog createDialog( + @SuppressWarnings("unused") final SubtypePreference subtypePref) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.custom_input_styles_title) .setMessage(R.string.custom_input_style_note_message) @@ -519,7 +521,7 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { return builder.create(); } - private void setPrefSubtypes(String prefSubtypes, Context context) { + private void setPrefSubtypes(final String prefSubtypes, final Context context) { final PreferenceGroup group = getPreferenceScreen(); group.removeAll(); final InputMethodSubtype[] subtypesArray = @@ -547,23 +549,12 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { return subtypes.toArray(new InputMethodSubtype[subtypes.size()]); } - private String getPrefSubtypes(InputMethodSubtype[] subtypes) { - final StringBuilder sb = new StringBuilder(); - for (final InputMethodSubtype subtype : subtypes) { - if (sb.length() > 0) { - sb.append(AdditionalSubtype.PREF_SUBTYPE_SEPARATOR); - } - sb.append(AdditionalSubtype.getPrefSubtype(subtype)); - } - return sb.toString(); - } - @Override public void onPause() { super.onPause(); final String oldSubtypes = SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources()); final InputMethodSubtype[] subtypes = getSubtypes(); - final String prefSubtypes = getPrefSubtypes(subtypes); + final String prefSubtypes = AdditionalSubtype.createPrefSubtypes(subtypes); if (prefSubtypes.equals(oldSubtypes)) { return; } @@ -578,13 +569,13 @@ public class AdditionalSubtypeSettings extends PreferenceFragment { } @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { final MenuItem addSubtypeMenu = menu.add(0, MENU_ADD_SUBTYPE, 0, R.string.add_style); addSubtypeMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean onOptionsItemSelected(final MenuItem item) { final int itemId = item.getItemId(); if (itemId == MENU_ADD_SUBTYPE) { final SubtypePreference newSubtype = diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 5e355a3b8..5e9c870d4 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -35,7 +35,7 @@ import java.util.HashMap; * When you call the constructor of this class, you may want to change the current system locale by * using {@link LocaleUtils.RunInLocale}. */ -public class SettingsValues { +public final class SettingsValues { private static final String TAG = SettingsValues.class.getSimpleName(); private static final int SUGGESTION_VISIBILITY_SHOW_VALUE @@ -246,64 +246,65 @@ public class SettingsValues { && orientation == Configuration.ORIENTATION_PORTRAIT); } - public boolean isWordSeparator(int code) { + public boolean isWordSeparator(final int code) { return mWordSeparators.contains(String.valueOf((char)code)); } - public boolean isSymbolExcludedFromWordSeparators(int code) { + public boolean isSymbolExcludedFromWordSeparators(final int code) { return mSymbolsExcludedFromWordSeparators.contains(String.valueOf((char)code)); } - public boolean isWeakSpaceStripper(int code) { + public boolean isWeakSpaceStripper(final int code) { // TODO: this does not work if the code does not fit in a char return mWeakSpaceStrippers.contains(String.valueOf((char)code)); } - public boolean isWeakSpaceSwapper(int code) { + public boolean isWeakSpaceSwapper(final int code) { // TODO: this does not work if the code does not fit in a char return mWeakSpaceSwappers.contains(String.valueOf((char)code)); } - public boolean isPhantomSpacePromotingSymbol(int code) { + public boolean isPhantomSpacePromotingSymbol(final int code) { // TODO: this does not work if the code does not fit in a char return mPhantomSpacePromotingSymbols.contains(String.valueOf((char)code)); } - private static boolean isAutoCorrectEnabled(final Resources resources, + private static boolean isAutoCorrectEnabled(final Resources res, final String currentAutoCorrectionSetting) { - final String autoCorrectionOff = resources.getString( + final String autoCorrectionOff = res.getString( R.string.auto_correction_threshold_mode_index_off); return !currentAutoCorrectionSetting.equals(autoCorrectionOff); } // Public to access from KeyboardSwitcher. Should it have access to some // process-global instance instead? - public static boolean isKeyPreviewPopupEnabled(SharedPreferences sp, Resources resources) { - final boolean showPopupOption = resources.getBoolean( + public static boolean isKeyPreviewPopupEnabled(final SharedPreferences prefs, + final Resources res) { + final boolean showPopupOption = res.getBoolean( R.bool.config_enable_show_popup_on_keypress_option); - if (!showPopupOption) return resources.getBoolean(R.bool.config_default_popup_preview); - return sp.getBoolean(Settings.PREF_POPUP_ON, - resources.getBoolean(R.bool.config_default_popup_preview)); + if (!showPopupOption) return res.getBoolean(R.bool.config_default_popup_preview); + return prefs.getBoolean(Settings.PREF_POPUP_ON, + res.getBoolean(R.bool.config_default_popup_preview)); } // Likewise - public static int getKeyPreviewPopupDismissDelay(SharedPreferences sp, - Resources resources) { + public static int getKeyPreviewPopupDismissDelay(final SharedPreferences prefs, + final Resources res) { // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here. - return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(resources.getInteger( + return Integer.parseInt(prefs.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, + Integer.toString(res.getInteger( R.integer.config_key_preview_linger_timeout)))); } - private static boolean isBigramPredictionEnabled(final SharedPreferences sp, - final Resources resources) { - return sp.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, resources.getBoolean( + private static boolean isBigramPredictionEnabled(final SharedPreferences prefs, + final Resources res) { + return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean( R.bool.config_default_next_word_prediction)); } - private static float getAutoCorrectionThreshold(final Resources resources, + private static float getAutoCorrectionThreshold(final Resources res, final String currentAutoCorrectionSetting) { - final String[] autoCorrectionThresholdValues = resources.getStringArray( + final String[] autoCorrectionThresholdValues = res.getStringArray( R.array.auto_correction_threshold_values); // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. float autoCorrectionThreshold = Float.MAX_VALUE; @@ -335,11 +336,11 @@ public class SettingsValues { return mVoiceKeyOnMain; } - public static boolean isLanguageSwitchKeySupressed(SharedPreferences sp) { - return sp.getBoolean(Settings.PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); + public static boolean isLanguageSwitchKeySupressed(final SharedPreferences prefs) { + return prefs.getBoolean(Settings.PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); } - public boolean isLanguageSwitchKeyEnabled(Context context) { + public boolean isLanguageSwitchKeyEnabled(final Context context) { if (mIsLanguageSwitchKeySuppressed) { return false; } @@ -352,7 +353,7 @@ public class SettingsValues { } } - public boolean isFullscreenModeAllowed(Resources res) { + public boolean isFullscreenModeAllowed(final Resources res) { return res.getBoolean(R.bool.config_use_fullscreen_mode); } @@ -362,15 +363,16 @@ public class SettingsValues { public static String getPrefAdditionalSubtypes(final SharedPreferences prefs, final Resources res) { - final String prefSubtypes = res.getString(R.string.predefined_subtypes, ""); - return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes); + final String predefinedPrefSubtypes = AdditionalSubtype.createPrefSubtypes( + res.getStringArray(R.array.predefined_subtypes)); + return prefs.getString(Settings.PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes); } // Accessed from the settings interface, hence public - public static float getCurrentKeypressSoundVolume(final SharedPreferences sp, - final Resources res) { + public static float getCurrentKeypressSoundVolume(final SharedPreferences prefs, + final Resources res) { // TODO: use mVibrationDurationSettingsRawValue instead of reading it again here - final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + final float volume = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); if (volume >= 0) { return volume; } @@ -380,10 +382,10 @@ public class SettingsValues { } // Likewise - public static int getCurrentVibrationDuration(final SharedPreferences sp, - final Resources res) { + public static int getCurrentVibrationDuration(final SharedPreferences prefs, + final Resources res) { // TODO: use mKeypressVibrationDuration instead of reading it again here - final int ms = sp.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); + final int ms = prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); if (ms >= 0) { return ms; } @@ -398,8 +400,8 @@ public class SettingsValues { return prefs.getBoolean(Settings.PREF_USABILITY_STUDY_MODE, true); } - public static long getLastUserHistoryWriteTime( - final SharedPreferences prefs, final String locale) { + public static long getLastUserHistoryWriteTime(final SharedPreferences prefs, + final String locale) { final String str = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(str); if (map.containsKey(locale)) { @@ -408,8 +410,8 @@ public class SettingsValues { return 0; } - public static void setLastUserHistoryWriteTime( - final SharedPreferences prefs, final String locale) { + public static void setLastUserHistoryWriteTime(final SharedPreferences prefs, + final String locale) { final String oldStr = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); final HashMap<String, Long> map = LocaleUtils.localeAndTimeStrToHashMap(oldStr); map.put(locale, System.currentTimeMillis()); diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 68ecfa0d7..d9f48c4a4 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -177,7 +177,7 @@ public class SuggestedWords { return; } int i = 1; - while(i < candidates.size()) { + while (i < candidates.size()) { final SuggestedWordInfo cur = candidates.get(i); for (int j = 0; j < i; ++j) { final SuggestedWordInfo previous = candidates.get(j); diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index f1abea9ec..61f7371b8 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -728,7 +728,7 @@ public class FusionDictionary implements Iterable<Word> { // StringBuilder s = new StringBuilder(); // for (CharGroup g : node.data) { // s.append(g.frequency); -// for (int ch : g.chars){ +// for (int ch : g.chars) { // s.append(Character.toChars(ch)); // } // } @@ -794,7 +794,7 @@ public class FusionDictionary implements Iterable<Word> { currentPos = mPositions.getLast(); mCurrentString.setLength(mCurrentString.length() - mPositions.getLast().length); } - } while(true); + } while (true); } @Override diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index a20958a88..dd2513f9f 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -68,9 +68,9 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, return 0; } int pagesize = getpagesize(); - adjust = dictOffset % pagesize; - int adjDictOffset = dictOffset - adjust; - int adjDictSize = dictSize + adjust; + adjust = static_cast<int>(dictOffset) % pagesize; + int adjDictOffset = static_cast<int>(dictOffset) - adjust; + int adjDictSize = static_cast<int>(dictSize) + adjust; dictBuf = mmap(0, sizeof(char) * adjDictSize, PROT_READ, MAP_PRIVATE, fd, adjDictOffset); if (dictBuf == MAP_FAILED) { AKLOGE("DICT: Can't mmap dictionary. errno=%d", errno); @@ -120,8 +120,8 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, releaseDictBuf(dictBuf, 0, 0); #endif // USE_MMAP_FOR_DICTIONARY } else { - dictionary = new Dictionary(dictBuf, dictSize, fd, adjust, typedLetterMultiplier, - fullWordMultiplier, maxWordLength, maxWords, maxPredictions); + dictionary = new Dictionary(dictBuf, static_cast<int>(dictSize), fd, adjust, + typedLetterMultiplier, fullWordMultiplier, maxWordLength, maxWords, maxPredictions); } PROF_END(66); PROF_CLOSE; diff --git a/native/jni/src/additional_proximity_chars.h b/native/jni/src/additional_proximity_chars.h index 1fe996d0d..d420c4664 100644 --- a/native/jni/src/additional_proximity_chars.h +++ b/native/jni/src/additional_proximity_chars.h @@ -50,7 +50,7 @@ class AdditionalProximityChars { if (!isEnLocale(localeStr)) { return 0; } - switch(c) { + switch (c) { case 'a': return EN_US_ADDITIONAL_A_SIZE; case 'e': @@ -70,7 +70,7 @@ class AdditionalProximityChars { if (!isEnLocale(localeStr)) { return 0; } - switch(c) { + switch (c) { case 'a': return EN_US_ADDITIONAL_A; case 'e': diff --git a/native/jni/src/basechars.cpp b/native/jni/src/basechars.cpp index c91e5f741..379cb6226 100644 --- a/native/jni/src/basechars.cpp +++ b/native/jni/src/basechars.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include <stdint.h> + #include "char_utils.h" namespace latinime { @@ -24,7 +26,7 @@ namespace latinime { * if c is not a combined character, or the base character if it * is combined. */ -const unsigned short BASE_CHARS[BASE_CHARS_SIZE] = { +const uint16_t BASE_CHARS[BASE_CHARS_SIZE] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp index f1d538095..3eea51a41 100644 --- a/native/jni/src/bigram_dictionary.cpp +++ b/native/jni/src/bigram_dictionary.cpp @@ -156,7 +156,7 @@ int BigramDictionary::getBigramListPositionForWord(const int32_t *prevWord, const int flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); if (0 == (flags & BinaryFormat::FLAG_HAS_BIGRAMS)) return 0; if (0 == (flags & BinaryFormat::FLAG_HAS_MULTIPLE_CHARS)) { - BinaryFormat::getCharCodeAndForwardPointer(root, &pos); + BinaryFormat::getCodePointAndForwardPointer(root, &pos); } else { pos = BinaryFormat::skipOtherCharacters(root, pos); } diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h index 25d504bfb..5d8b2a0f2 100644 --- a/native/jni/src/binary_format.h +++ b/native/jni/src/binary_format.h @@ -84,7 +84,7 @@ class BinaryFormat { static unsigned int getFlags(const uint8_t *const dict); static int getGroupCountAndForwardPointer(const uint8_t *const dict, int *pos); static uint8_t getFlagsAndForwardPointer(const uint8_t *const dict, int *pos); - static int32_t getCharCodeAndForwardPointer(const uint8_t *const dict, int *pos); + static int32_t getCodePointAndForwardPointer(const uint8_t *const dict, int *pos); static int readFrequencyWithoutMovingPointer(const uint8_t *const dict, const int pos); static int skipOtherCharacters(const uint8_t *const dict, const int pos); static int skipChildrenPosition(const uint8_t flags, const int pos); @@ -176,22 +176,22 @@ inline uint8_t BinaryFormat::getFlagsAndForwardPointer(const uint8_t *const dict return dict[(*pos)++]; } -inline int32_t BinaryFormat::getCharCodeAndForwardPointer(const uint8_t *const dict, int *pos) { +inline int32_t BinaryFormat::getCodePointAndForwardPointer(const uint8_t *const dict, int *pos) { const int origin = *pos; - const int32_t character = dict[origin]; - if (character < MINIMAL_ONE_BYTE_CHARACTER_VALUE) { - if (character == CHARACTER_ARRAY_TERMINATOR) { + const int32_t codePoint = dict[origin]; + if (codePoint < MINIMAL_ONE_BYTE_CHARACTER_VALUE) { + if (codePoint == CHARACTER_ARRAY_TERMINATOR) { *pos = origin + 1; - return NOT_A_CHARACTER; + return NOT_A_CODE_POINT; } else { *pos = origin + 3; - const int32_t char_1 = character << 16; + const int32_t char_1 = codePoint << 16; const int32_t char_2 = char_1 + (dict[origin + 1] << 8); return char_2 + dict[origin + 2]; } } else { *pos = origin + 1; - return character; + return codePoint; } } @@ -369,15 +369,15 @@ inline int BinaryFormat::getTerminalPosition(const uint8_t *const root, if (0 >= charGroupCount) return NOT_VALID_WORD; const int charGroupPos = pos; const uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); - int32_t character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); + int32_t character = BinaryFormat::getCodePointAndForwardPointer(root, &pos); if (character == wChar) { // This is the correct node. Only one character group may start with the same // char within a node, so either we found our match in this node, or there is // no match and we can return NOT_VALID_WORD. So we will check all the characters // in this character group indeed does match. if (FLAG_HAS_MULTIPLE_CHARS & flags) { - character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); - while (NOT_A_CHARACTER != character) { + character = BinaryFormat::getCodePointAndForwardPointer(root, &pos); + while (NOT_A_CODE_POINT != character) { ++wordPos; // If we shoot the length of the word we search for, or if we find a single // character that does not match, as explained above, it means the word is @@ -385,7 +385,7 @@ inline int BinaryFormat::getTerminalPosition(const uint8_t *const root, // match the word on the first character, but not matching the whole word). if (wordPos > length) return NOT_VALID_WORD; if (inWord[wordPos] != character) return NOT_VALID_WORD; - character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); + character = BinaryFormat::getCodePointAndForwardPointer(root, &pos); } } // If we come here we know that so far, we do match. Either we are on a terminal @@ -457,19 +457,19 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t *const root, const int a --charGroupCount) { const int startPos = pos; const uint8_t flags = getFlagsAndForwardPointer(root, &pos); - const int32_t character = getCharCodeAndForwardPointer(root, &pos); + const int32_t character = getCodePointAndForwardPointer(root, &pos); if (address == startPos) { // We found the address. Copy the rest of the word in the buffer and return // the length. outWord[wordPos] = character; if (FLAG_HAS_MULTIPLE_CHARS & flags) { - int32_t nextChar = getCharCodeAndForwardPointer(root, &pos); + int32_t nextChar = getCodePointAndForwardPointer(root, &pos); // We count chars in order to avoid infinite loops if the file is broken or // if there is some other bug int charCount = maxDepth; - while (NOT_A_CHARACTER != nextChar && --charCount > 0) { + while (NOT_A_CODE_POINT != nextChar && --charCount > 0) { outWord[++wordPos] = nextChar; - nextChar = getCharCodeAndForwardPointer(root, &pos); + nextChar = getCodePointAndForwardPointer(root, &pos); } } *outUnigramFrequency = readFrequencyWithoutMovingPointer(root, pos); @@ -523,16 +523,16 @@ inline int BinaryFormat::getWordAtAddress(const uint8_t *const root, const int a const uint8_t lastFlags = getFlagsAndForwardPointer(root, &lastCandidateGroupPos); const int32_t lastChar = - getCharCodeAndForwardPointer(root, &lastCandidateGroupPos); + getCodePointAndForwardPointer(root, &lastCandidateGroupPos); // We copy all the characters in this group to the buffer outWord[wordPos] = lastChar; if (FLAG_HAS_MULTIPLE_CHARS & lastFlags) { int32_t nextChar = - getCharCodeAndForwardPointer(root, &lastCandidateGroupPos); + getCodePointAndForwardPointer(root, &lastCandidateGroupPos); int charCount = maxDepth; while (-1 != nextChar && --charCount > 0) { outWord[++wordPos] = nextChar; - nextChar = getCharCodeAndForwardPointer(root, &lastCandidateGroupPos); + nextChar = getCodePointAndForwardPointer(root, &lastCandidateGroupPos); } } ++wordPos; @@ -582,8 +582,8 @@ inline int BinaryFormat::computeFrequencyForBigram(const int unigramFreq, const // 0 for the bigram frequency represents the middle of the 16th step from the top, // while a value of 15 represents the middle of the top step. // See makedict.BinaryDictInputOutput for details. - const float stepSize = (static_cast<float>(MAX_FREQ) - unigramFreq) / (1.5f + MAX_BIGRAM_FREQ); - return static_cast<int>(unigramFreq + (bigramFreq + 1) * stepSize); + const float stepSize = static_cast<float>(MAX_FREQ - unigramFreq) / (1.5f + MAX_BIGRAM_FREQ); + return unigramFreq + static_cast<int>(static_cast<float>(bigramFreq + 1) * stepSize); } // This returns a probability in log space. diff --git a/native/jni/src/bloom_filter.h b/native/jni/src/bloom_filter.h index 47177dcba..bcce1f7ea 100644 --- a/native/jni/src/bloom_filter.h +++ b/native/jni/src/bloom_filter.h @@ -23,14 +23,16 @@ namespace latinime { -static inline void setInFilter(uint8_t *filter, const int position) { - const unsigned int bucket = position % BIGRAM_FILTER_MODULO; - filter[bucket >> 3] |= (1 << (bucket & 0x7)); +// TODO: uint32_t position +static inline void setInFilter(uint8_t *filter, const int32_t position) { + const uint32_t bucket = static_cast<uint32_t>(position % BIGRAM_FILTER_MODULO); + filter[bucket >> 3] |= static_cast<uint8_t>(1 << (bucket & 0x7)); } -static inline bool isInFilter(const uint8_t *filter, const int position) { - const unsigned int bucket = position % BIGRAM_FILTER_MODULO; - return filter[bucket >> 3] & (1 << (bucket & 0x7)); +// TODO: uint32_t position +static inline bool isInFilter(const uint8_t *filter, const int32_t position) { + const uint32_t bucket = static_cast<uint32_t>(position % BIGRAM_FILTER_MODULO); + return filter[bucket >> 3] & static_cast<uint8_t>(1 << (bucket & 0x7)); } } // namespace latinime #endif // LATINIME_BLOOM_FILTER_H diff --git a/native/jni/src/char_utils.h b/native/jni/src/char_utils.h index b30677fa7..b17f262ec 100644 --- a/native/jni/src/char_utils.h +++ b/native/jni/src/char_utils.h @@ -18,6 +18,7 @@ #define LATINIME_CHAR_UTILS_H #include <cctype> +#include <stdint.h> namespace latinime { @@ -43,7 +44,7 @@ unsigned short latin_tolower(const unsigned short c); */ static const int BASE_CHARS_SIZE = 0x0500; -extern const unsigned short BASE_CHARS[BASE_CHARS_SIZE]; +extern const uint16_t BASE_CHARS[BASE_CHARS_SIZE]; inline static unsigned short toBaseChar(unsigned short c) { if (c < BASE_CHARS_SIZE) { diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp index 9ad65b09d..92cfd1a49 100644 --- a/native/jni/src/correction.cpp +++ b/native/jni/src/correction.cpp @@ -362,7 +362,8 @@ Correction::CorrectionType Correction::processCharAndCalcState( if (mSkipPos >= 0) { if (mSkippedCount == 0 && mSkipPos < mOutputIndex) { if (DEBUG_DICT) { - assert(mSkipPos == mOutputIndex - 1); + // TODO: Enable this assertion. + //assert(mSkipPos == mOutputIndex - 1); } mSkipPos = mOutputIndex; } @@ -630,7 +631,7 @@ Correction::CorrectionType Correction::processCharAndCalcState( inline static int getQuoteCount(const unsigned short *word, const int length) { int quoteCount = 0; for (int i = 0; i < length; ++i) { - if(word[i] == '\'') { + if (word[i] == '\'') { ++quoteCount; } } @@ -936,7 +937,7 @@ int Correction::RankingAlgorithm::calcFreqForSplitMultipleWords( int totalLength = 0; int totalFreq = 0; - for (int i = 0; i < wordCount; ++i){ + for (int i = 0; i < wordCount; ++i) { const int wordLength = wordLengthArray[i]; if (wordLength <= 0) { return 0; @@ -1126,15 +1127,16 @@ float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short *be return 0; } - const float maxScore = score >= S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE - * powf(static_cast<float>(TYPED_LETTER_MULTIPLIER), - static_cast<float>(min(beforeLength, afterLength - spaceCount))) - * FULL_WORD_MULTIPLIER; + const float maxScore = score >= S_INT_MAX ? static_cast<float>(S_INT_MAX) + : static_cast<float>(MAX_INITIAL_SCORE) + * powf(static_cast<float>(TYPED_LETTER_MULTIPLIER), + static_cast<float>(min(beforeLength, afterLength - spaceCount))) + * static_cast<float>(FULL_WORD_MULTIPLIER); // add a weight based on edit distance. // distance <= max(afterLength, beforeLength) == afterLength, // so, 0 <= distance / afterLength <= 1 const float weight = 1.0f - static_cast<float>(distance) / static_cast<float>(afterLength); - return (score / maxScore) * weight; + return (static_cast<float>(score) / maxScore) * weight; } } // namespace latinime diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index 28661ab20..0286365bc 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -17,6 +17,8 @@ #ifndef LATINIME_DEFINES_H #define LATINIME_DEFINES_H +#include <stdint.h> + #if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) #include <android/log.h> #ifndef LOG_TAG @@ -26,9 +28,9 @@ #define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__) #define DUMP_RESULT(words, frequencies, maxWordCount, maxWordLength) do { \ - dumpResult(words, frequencies, maxWordCount, maxWordLength); } while(0) -#define DUMP_WORD(word, length) do { dumpWord(word, length); } while(0) -#define DUMP_WORD_INT(word, length) do { dumpWordInt(word, length); } while(0) + dumpResult(words, frequencies, maxWordCount, maxWordLength); } while (0) +#define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0) +#define DUMP_WORD_INT(word, length) do { dumpWordInt(word, length); } while (0) static inline void dumpWordInfo(const unsigned short *word, const int length, const int rank, const int frequency) { @@ -39,7 +41,8 @@ static inline void dumpWordInfo(const unsigned short *word, const int length, if (c == 0) { break; } - charBuf[i] = c; + // static_cast only for debugging + charBuf[i] = static_cast<char>(c); } charBuf[i] = 0; if (i > 1) { @@ -65,7 +68,8 @@ static inline void dumpWord(const unsigned short *word, const int length) { if (c == 0) { break; } - charBuf[i] = c; + // static_cast only for debugging + charBuf[i] = static_cast<char>(c); } charBuf[i] = 0; if (i > 1) { @@ -84,7 +88,7 @@ static inline void dumpWordInt(const int *word, const int length) { } #ifndef __ANDROID__ -#define ASSERT(success) do { if(!success) { showStackTrace(); assert(success);};} while (0) +#define ASSERT(success) do { if (!success) { showStackTrace(); assert(success);};} while (0) #define SHOW_STACK_TRACE do { showStackTrace(); } while (0) #include <execinfo.h> @@ -128,14 +132,14 @@ static unsigned int profile_counter[PROF_BUF_SIZE]; #define PROF_RESET prof_reset() #define PROF_COUNT(prof_buf_id) ++profile_counter[prof_buf_id] -#define PROF_OPEN do { PROF_RESET; PROF_START(PROF_BUF_SIZE - 1); } while(0) +#define PROF_OPEN do { PROF_RESET; PROF_START(PROF_BUF_SIZE - 1); } while (0) #define PROF_START(prof_buf_id) do { \ - PROF_COUNT(prof_buf_id); profile_old[prof_buf_id] = (clock()); } while(0) -#define PROF_CLOSE do { PROF_END(PROF_BUF_SIZE - 1); PROF_OUTALL; } while(0) + PROF_COUNT(prof_buf_id); profile_old[prof_buf_id] = (clock()); } while (0) +#define PROF_CLOSE do { PROF_END(PROF_BUF_SIZE - 1); PROF_OUTALL; } while (0) #define PROF_END(prof_buf_id) profile_buf[prof_buf_id] += ((clock()) - profile_old[prof_buf_id]) #define PROF_CLOCKOUT(prof_buf_id) \ AKLOGI("%s : clock is %f", __FUNCTION__, (clock() - profile_old[prof_buf_id])) -#define PROF_OUTALL do { AKLOGI("--- %s ---", __FUNCTION__); prof_out(); } while(0) +#define PROF_OUTALL do { AKLOGI("--- %s ---", __FUNCTION__); prof_out(); } while (0) static inline void prof_reset(void) { for (int i = 0; i < PROF_BUF_SIZE; ++i) { @@ -236,15 +240,15 @@ static inline void prof_out(void) { #define FLAG_BIGRAM_FREQ 0x7F #define DICTIONARY_VERSION_MIN 200 -#define NOT_VALID_WORD -99 -#define NOT_A_CHARACTER -1 -#define NOT_A_DISTANCE -1 -#define NOT_A_COORDINATE -1 -#define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO -2 -#define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO -3 -#define ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO -4 -#define NOT_AN_INDEX -1 -#define NOT_A_PROBABILITY -1 +#define NOT_VALID_WORD (-99) +#define NOT_A_CODE_POINT (-1) +#define NOT_A_DISTANCE (-1) +#define NOT_A_COORDINATE (-1) +#define EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO (-2) +#define PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO (-3) +#define ADDITIONAL_PROXIMITY_CHAR_DISTANCE_INFO (-4) +#define NOT_AN_INDEX (-1) +#define NOT_A_PROBABILITY (-1) #define KEYCODE_SPACE ' ' @@ -323,6 +327,9 @@ static inline void prof_out(void) { // Max Distance between point to key #define MAX_POINT_TO_KEY_LENGTH 10000000 +// The max number of the keys in one keyboard layout +#define MAX_KEY_COUNT_IN_A_KEYBOARD 64 + // TODO: Reduce this constant if possible; check the maximum number of digraphs in the same // word in the dictionary for languages with digraphs, like German and French #define DEFAULT_MAX_DIGRAPH_SEARCH_DEPTH 5 @@ -355,8 +362,8 @@ template<typename T> inline T max(T a, T b) { return a > b ? a : b; } #define NEUTRAL_AREA_RADIUS_RATIO 1.3f // DEBUG -#define INPUTLENGTH_FOR_DEBUG -1 -#define MIN_OUTPUT_INDEX_FOR_DEBUG -1 +#define INPUTLENGTH_FOR_DEBUG (-1) +#define MIN_OUTPUT_INDEX_FOR_DEBUG (-1) #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index e9a03ce55..a1358890d 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -90,11 +90,12 @@ class Dictionary { // static inline methods should be defined in the header file inline int Dictionary::wideStrLen(unsigned short *str) { if (!str) return 0; - unsigned short *end = str; - while (*end) { - end++; + int length = 0; + while (*str) { + str++; + length++; } - return end - str; + return length; } } // namespace latinime #endif // LATINIME_DICTIONARY_H diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp index 765632e46..a8c04300f 100644 --- a/native/jni/src/proximity_info.cpp +++ b/native/jni/src/proximity_info.cpp @@ -29,7 +29,6 @@ namespace latinime { -/* static */ const int ProximityInfo::NOT_A_CODE = -1; /* static */ const float ProximityInfo::NOT_A_DISTANCE_FLOAT = -1.0f; static inline void safeGetOrFillZeroIntArrayRegion(JNIEnv *env, jintArray jArray, jsize len, @@ -63,6 +62,7 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int ma CELL_WIDTH((keyboardWidth + gridWidth - 1) / gridWidth), CELL_HEIGHT((keyboardHeight + gridHeight - 1) / gridHeight), KEY_COUNT(min(keyCount, MAX_KEY_COUNT_IN_A_KEYBOARD)), + KEYBOARD_WIDTH(keyboardWidth), KEYBOARD_HEIGHT(keyboardHeight), HAS_TOUCH_POSITION_CORRECTION_DATA(keyCount > 0 && keyXCoordinates && keyYCoordinates && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs && sweetSpotCenterYs && sweetSpotRadii), @@ -84,22 +84,22 @@ ProximityInfo::ProximityInfo(JNIEnv *env, const jstring localeJStr, const int ma safeGetOrFillZeroIntArrayRegion(env, keyYCoordinates, KEY_COUNT, mKeyYCoordinates); safeGetOrFillZeroIntArrayRegion(env, keyWidths, KEY_COUNT, mKeyWidths); safeGetOrFillZeroIntArrayRegion(env, keyHeights, KEY_COUNT, mKeyHeights); - safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCharCodes); + safeGetOrFillZeroIntArrayRegion(env, keyCharCodes, KEY_COUNT, mKeyCodePoints); safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterXs, KEY_COUNT, mSweetSpotCenterXs); safeGetOrFillZeroFloatArrayRegion(env, sweetSpotCenterYs, KEY_COUNT, mSweetSpotCenterYs); safeGetOrFillZeroFloatArrayRegion(env, sweetSpotRadii, KEY_COUNT, mSweetSpotRadii); - initializeCodeToKeyIndex(); + initializeCodePointToKeyIndex(); initializeG(); } // Build the reversed look up table from the char code to the index in mKeyXCoordinates, // mKeyYCoordinates, mKeyWidths, mKeyHeights, mKeyCharCodes. -void ProximityInfo::initializeCodeToKeyIndex() { - memset(mCodeToKeyIndex, -1, (MAX_CHAR_CODE + 1) * sizeof(mCodeToKeyIndex[0])); +void ProximityInfo::initializeCodePointToKeyIndex() { + memset(mCodePointToKeyIndex, -1, sizeof(mCodePointToKeyIndex)); for (int i = 0; i < KEY_COUNT; ++i) { - const int code = mKeyCharCodes[i]; + const int code = mKeyCodePoints[i]; if (0 <= code && code <= MAX_CHAR_CODE) { - mCodeToKeyIndex[code] = i; + mCodePointToKeyIndex[code] = i; } } } @@ -117,7 +117,8 @@ bool ProximityInfo::hasSpaceProximity(const int x, const int y) const { if (x < 0 || y < 0) { if (DEBUG_DICT) { AKLOGI("HasSpaceProximity: Illegal coordinates (%d, %d)", x, y); - assert(false); + // TODO: Enable this assertion. + //assert(false); } return false; } @@ -145,8 +146,8 @@ static inline float getNormalizedSquaredDistanceFloat(float x1, float y1, float float ProximityInfo::getNormalizedSquaredDistanceFromCenterFloat( const int keyId, const int x, const int y) const { - const float centerX = static_cast<float>(getKeyCenterXOfIdG(keyId)); - const float centerY = static_cast<float>(getKeyCenterYOfIdG(keyId)); + const float centerX = static_cast<float>(getKeyCenterXOfKeyIdG(keyId)); + const float centerY = static_cast<float>(getKeyCenterYOfKeyIdG(keyId)); const float touchX = static_cast<float>(x); const float touchY = static_cast<float>(y); const float keyWidth = static_cast<float>(getMostCommonKeyWidth()); @@ -178,7 +179,7 @@ void ProximityInfo::calculateNearbyKeyCodes( if (c < KEYCODE_SPACE || c == primaryKey) { continue; } - const int keyIndex = getKeyIndex(c); + const int keyIndex = getKeyIndexOf(c); const bool onKey = isOnKey(keyIndex, x, y); const int distance = squaredDistanceToEdge(keyIndex, x, y); if (onKey || distance < MOST_COMMON_KEY_WIDTH_SQUARE) { @@ -208,7 +209,7 @@ void ProximityInfo::calculateNearbyKeyCodes( const int32_t ac = additionalProximityChars[j]; int k = 0; for (; k < insertPos; ++k) { - if ((int)ac == inputCodes[k]) { + if (static_cast<int>(ac) == inputCodes[k]) { break; } } @@ -227,11 +228,11 @@ void ProximityInfo::calculateNearbyKeyCodes( } // Add a delimiter for the proximity characters for (int i = insertPos; i < MAX_PROXIMITY_CHARS_SIZE; ++i) { - inputCodes[i] = NOT_A_CODE; + inputCodes[i] = NOT_A_CODE_POINT; } } -int ProximityInfo::getKeyIndex(const int c) const { +int ProximityInfo::getKeyIndexOf(const int c) const { if (KEY_COUNT == 0) { // We do not have the coordinate data return NOT_AN_INDEX; @@ -240,28 +241,28 @@ int ProximityInfo::getKeyIndex(const int c) const { if (baseLowerC > MAX_CHAR_CODE) { return NOT_AN_INDEX; } - return mCodeToKeyIndex[baseLowerC]; + return mCodePointToKeyIndex[baseLowerC]; } -int ProximityInfo::getKeyCode(const int keyIndex) const { +int ProximityInfo::getCodePointOf(const int keyIndex) const { if (keyIndex < 0 || keyIndex >= KEY_COUNT) { - return NOT_AN_INDEX; + return NOT_A_CODE_POINT; } - return mKeyToCodeIndexG[keyIndex]; + return mKeyIndexToCodePointG[keyIndex]; } void ProximityInfo::initializeG() { // TODO: Optimize for (int i = 0; i < KEY_COUNT; ++i) { - const int code = mKeyCharCodes[i]; + const int code = mKeyCodePoints[i]; const int lowerCode = toBaseLowerCase(code); mCenterXsG[i] = mKeyXCoordinates[i] + mKeyWidths[i] / 2; mCenterYsG[i] = mKeyYCoordinates[i] + mKeyHeights[i] / 2; if (code != lowerCode && lowerCode >= 0 && lowerCode <= MAX_CHAR_CODE) { - mCodeToKeyIndex[lowerCode] = i; - mKeyToCodeIndexG[i] = lowerCode; + mCodePointToKeyIndex[lowerCode] = i; + mKeyIndexToCodePointG[i] = lowerCode; } else { - mKeyToCodeIndexG[i] = code; + mKeyIndexToCodePointG[i] = code; } } for (int i = 0; i < KEY_COUNT; i++) { @@ -274,22 +275,22 @@ void ProximityInfo::initializeG() { } } -float ProximityInfo::getKeyCenterXOfCharG(int charCode) const { - return getKeyCenterXOfIdG(getKeyIndex(charCode)); +float ProximityInfo::getKeyCenterXOfCodePointG(int charCode) const { + return getKeyCenterXOfKeyIdG(getKeyIndexOf(charCode)); } -float ProximityInfo::getKeyCenterYOfCharG(int charCode) const { - return getKeyCenterYOfIdG(getKeyIndex(charCode)); +float ProximityInfo::getKeyCenterYOfCodePointG(int charCode) const { + return getKeyCenterYOfKeyIdG(getKeyIndexOf(charCode)); } -float ProximityInfo::getKeyCenterXOfIdG(int keyId) const { +float ProximityInfo::getKeyCenterXOfKeyIdG(int keyId) const { if (keyId >= 0) { return mCenterXsG[keyId]; } return 0; } -float ProximityInfo::getKeyCenterYOfIdG(int keyId) const { +float ProximityInfo::getKeyCenterYOfKeyIdG(int keyId) const { if (keyId >= 0) { return mCenterYsG[keyId]; } @@ -297,8 +298,8 @@ float ProximityInfo::getKeyCenterYOfIdG(int keyId) const { } int ProximityInfo::getKeyKeyDistanceG(int key0, int key1) const { - const int keyId0 = getKeyIndex(key0); - const int keyId1 = getKeyIndex(key1); + const int keyId0 = getKeyIndexOf(key0); + const int keyId1 = getKeyIndexOf(key1); if (keyId0 >= 0 && keyId1 >= 0) { return mKeyKeyDistancesG[keyId0][keyId1]; } diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h index 822909b7a..7c22e108b 100644 --- a/native/jni/src/proximity_info.h +++ b/native/jni/src/proximity_info.h @@ -41,8 +41,8 @@ class ProximityInfo { float getNormalizedSquaredDistanceFromCenterFloat( const int keyId, const int x, const int y) const; bool sameAsTyped(const unsigned short *word, int length) const; - int getKeyIndex(const int c) const; - int getKeyCode(const int keyIndex) const; + int getKeyIndexOf(const int c) const; + int getCodePointOf(const int keyIndex) const; bool hasSweetSpotData(const int keyIndex) const { // When there are no calibration data for a key, // the radius of the key is assigned to zero. @@ -96,23 +96,29 @@ class ProximityInfo { return GRID_HEIGHT; } - float getKeyCenterXOfCharG(int charCode) const; - float getKeyCenterYOfCharG(int charCode) const; - float getKeyCenterXOfIdG(int keyId) const; - float getKeyCenterYOfIdG(int keyId) const; + int getKeyboardWidth() const { + return KEYBOARD_WIDTH; + } + + int getKeyboardHeight() const { + return KEYBOARD_HEIGHT; + } + + // TODO: These should return int. + float getKeyCenterXOfCodePointG(int charCode) const; + float getKeyCenterYOfCodePointG(int charCode) const; + float getKeyCenterXOfKeyIdG(int keyId) const; + float getKeyCenterYOfKeyIdG(int keyId) const; int getKeyKeyDistanceG(int key0, int key1) const; private: DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfo); - // The max number of the keys in one keyboard layout - static const int MAX_KEY_COUNT_IN_A_KEYBOARD = 64; - // The upper limit of the char code in mCodeToKeyIndex + // The upper limit of the char code in mCodePointToKeyIndex static const int MAX_CHAR_CODE = 127; - static const int NOT_A_CODE; static const float NOT_A_DISTANCE_FLOAT; int getStartIndexFromCoordinates(const int x, const int y) const; - void initializeCodeToKeyIndex(); + void initializeCodePointToKeyIndex(); void initializeG(); float calculateNormalizedSquaredDistance(const int keyIndex, const int inputIndex) const; float calculateSquaredDistanceFromSweetSpotCenter( @@ -136,6 +142,8 @@ class ProximityInfo { const int CELL_WIDTH; const int CELL_HEIGHT; const int KEY_COUNT; + const int KEYBOARD_WIDTH; + const int KEYBOARD_HEIGHT; const bool HAS_TOUCH_POSITION_CORRECTION_DATA; char mLocaleStr[MAX_LOCALE_STRING_LENGTH]; int32_t *mProximityCharsArray; @@ -143,13 +151,13 @@ class ProximityInfo { int32_t mKeyYCoordinates[MAX_KEY_COUNT_IN_A_KEYBOARD]; int32_t mKeyWidths[MAX_KEY_COUNT_IN_A_KEYBOARD]; int32_t mKeyHeights[MAX_KEY_COUNT_IN_A_KEYBOARD]; - int32_t mKeyCharCodes[MAX_KEY_COUNT_IN_A_KEYBOARD]; + int32_t mKeyCodePoints[MAX_KEY_COUNT_IN_A_KEYBOARD]; float mSweetSpotCenterXs[MAX_KEY_COUNT_IN_A_KEYBOARD]; float mSweetSpotCenterYs[MAX_KEY_COUNT_IN_A_KEYBOARD]; float mSweetSpotRadii[MAX_KEY_COUNT_IN_A_KEYBOARD]; - int mCodeToKeyIndex[MAX_CHAR_CODE + 1]; + int mCodePointToKeyIndex[MAX_CHAR_CODE + 1]; - int mKeyToCodeIndexG[MAX_KEY_COUNT_IN_A_KEYBOARD]; + int mKeyIndexToCodePointG[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mCenterXsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mCenterYsG[MAX_KEY_COUNT_IN_A_KEYBOARD]; int mKeyKeyDistancesG[MAX_KEY_COUNT_IN_A_KEYBOARD][MAX_KEY_COUNT_IN_A_KEYBOARD]; diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp index e13d4e664..c9a1ed0c0 100644 --- a/native/jni/src/proximity_info_state.cpp +++ b/native/jni/src/proximity_info_state.cpp @@ -76,6 +76,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi mTimes.clear(); mLengthCache.clear(); mDistanceCache.clear(); + mNearKeysVector.clear(); mInputSize = 0; if (xCoordinates && yCoordinates) { @@ -122,14 +123,34 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi if (mInputSize > 0) { const int keyCount = mProximityInfo->getKeyCount(); + mNearKeysVector.resize(mInputSize); mDistanceCache.resize(mInputSize * keyCount); for (int i = 0; i < mInputSize; ++i) { + mNearKeysVector[i].reset(); + static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f; for (int k = 0; k < keyCount; ++k) { const int index = i * keyCount + k; const int x = mInputXs[i]; const int y = mInputYs[i]; - mDistanceCache[index] = + const float normalizedSquaredDistance = mProximityInfo->getNormalizedSquaredDistanceFromCenterFloat(k, x, y); + mDistanceCache[index] = normalizedSquaredDistance; + if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) { + mNearKeysVector[i].set(k, 1); + } + } + } + + static const float READ_FORWORD_LENGTH_SCALE = 0.95f; + const int readForwordLength = static_cast<int>( + hypotf(mProximityInfo->getKeyboardWidth(), mProximityInfo->getKeyboardHeight()) + * READ_FORWORD_LENGTH_SCALE); + for (int i = 0; i < mInputSize; ++i) { + for (int j = i + 1; j < mInputSize; ++j) { + if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) { + break; + } + mNearKeysVector[i] |= mNearKeysVector[j]; } } } @@ -160,7 +181,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi const int currentChar = proximityChars[j]; const float squaredDistance = hasInputCoordinates() ? calculateNormalizedSquaredDistance( - mProximityInfo->getKeyIndex(currentChar), i) : + mProximityInfo->getKeyIndexOf(currentChar), i) : NOT_A_DISTANCE_FLOAT; if (squaredDistance >= 0.0f) { mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE_INTERNAL + j] = @@ -182,7 +203,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi // the given point and the nearest key position. float ProximityInfoState::updateNearKeysDistances(const int x, const int y, NearKeysDistanceMap *const currentNearKeysDistances) { - static const float NEAR_KEY_THRESHOLD = 10.0f; + static const float NEAR_KEY_THRESHOLD = 4.0f; currentNearKeysDistances->clear(); const int keyCount = mProximityInfo->getKeyCount(); @@ -282,7 +303,7 @@ bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const const NearKeysDistanceMap *const prevPrevNearKeysDistances) { static const float LAST_POINT_SKIP_DISTANCE_SCALE = 0.25f; - uint32_t size = mInputXs.size(); + size_t size = mInputXs.size(); bool popped = false; if (nodeChar < 0 && sample) { const float nearest = updateNearKeysDistances(x, y, currentNearKeysDistances); @@ -309,7 +330,7 @@ bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const float minDist = mMaxPointToKeyLength; for (NearKeysDistanceMap::const_iterator it = currentNearKeysDistances->begin(); it != currentNearKeysDistances->end(); ++it) { - if(minDist > it->second){ + if (minDist > it->second) { minChar = it->first; minDist = it->second; } @@ -324,10 +345,10 @@ bool ProximityInfoState::pushTouchPoint(const int nodeChar, int x, int y, const } if (nodeChar >= 0 && (x < 0 || y < 0)) { - const int keyId = mProximityInfo->getKeyIndex(nodeChar); + const int keyId = mProximityInfo->getKeyIndexOf(nodeChar); if (keyId >= 0) { - x = mProximityInfo->getKeyCenterXOfIdG(keyId); - y = mProximityInfo->getKeyCenterYOfIdG(keyId); + x = mProximityInfo->getKeyCenterXOfKeyIdG(keyId); + y = mProximityInfo->getKeyCenterYOfKeyIdG(keyId); } } @@ -368,8 +389,8 @@ int ProximityInfoState::getDuration(const int index) const { return 0; } -float ProximityInfoState::getPointToKeyLength(int inputIndex, int charCode, float scale) { - const int keyId = mProximityInfo->getKeyIndex(charCode); +float ProximityInfoState::getPointToKeyLength(int inputIndex, int codePoint, float scale) { + const int keyId = mProximityInfo->getKeyIndexOf(codePoint); if (keyId >= 0) { const int index = inputIndex * mProximityInfo->getKeyCount() + keyId; return min(mDistanceCache[index] * scale, mMaxPointToKeyLength); @@ -382,8 +403,8 @@ int ProximityInfoState::getKeyKeyDistance(int key0, int key1) { } int ProximityInfoState::getSpaceY() { - const int keyId = mProximityInfo->getKeyIndex(' '); - return mProximityInfo->getKeyCenterYOfIdG(keyId); + const int keyId = mProximityInfo->getKeyIndexOf(' '); + return mProximityInfo->getKeyCenterYOfKeyIdG(keyId); } float ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter( @@ -394,4 +415,30 @@ float ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter( const float inputY = static_cast<float>(mInputYs[inputIndex]); return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY); } + +// Puts possible characters into filter and returns new filter size. +int32_t ProximityInfoState::getAllPossibleChars( + const size_t index, int32_t *const filter, const int32_t filterSize) const { + if (index >= mInputXs.size()) { + return filterSize; + } + int i = filterSize; + for (int j = 0; j < mProximityInfo->getKeyCount(); ++j) { + if (mNearKeysVector[index].test(j)) { + const int32_t keyCodePoint = mProximityInfo->getCodePointOf(j); + bool insert = true; + // TODO: Avoid linear search + for (int k = 0; k < filterSize; ++k) { + if (filter[k] == keyCodePoint) { + insert = false; + break; + } + } + if (insert) { + filter[i++] = keyCodePoint; + } + } + } + return i; +} } // namespace latinime diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h index 746b9c968..80b84e962 100644 --- a/native/jni/src/proximity_info_state.h +++ b/native/jni/src/proximity_info_state.h @@ -17,6 +17,7 @@ #ifndef LATINIME_PROXIMITY_INFO_STATE_H #define LATINIME_PROXIMITY_INFO_STATE_H +#include <bitset> #include <cstring> // for memset() #include <stdint.h> #include <string> @@ -32,6 +33,7 @@ class ProximityInfo; class ProximityInfoState { public: + typedef std::bitset<MAX_KEY_COUNT_IN_A_KEYBOARD> NearKeycodesSet; static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10; static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR = 1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; @@ -56,7 +58,8 @@ class ProximityInfoState { mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0), mLocaleStr(), mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0), mInputXs(), mInputYs(), mTimes(), mDistanceCache(), mLengthCache(), - mTouchPositionCorrectionEnabled(false), mInputSize(0) { + mNearKeysVector(), mTouchPositionCorrectionEnabled(false), + mInputSize(0) { memset(mInputCodes, 0, sizeof(mInputCodes)); memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances)); memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord)); @@ -215,6 +218,9 @@ class ProximityInfoState { int getSpaceY(); + int32_t getAllPossibleChars( + const size_t startIndex, int32_t *const filter, int32_t filterSize) const; + private: DISALLOW_COPY_AND_ASSIGN(ProximityInfoState); typedef hash_map_compat<int, float> NearKeysDistanceMap; @@ -272,6 +278,7 @@ class ProximityInfoState { std::vector<int> mTimes; std::vector<float> mDistanceCache; std::vector<int> mLengthCache; + std::vector<NearKeycodesSet> mNearKeysVector; bool mTouchPositionCorrectionEnabled; int32_t mInputCodes[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH_INTERNAL]; int mNormalizedSquaredDistances[MAX_PROXIMITY_CHARS_SIZE_INTERNAL * MAX_WORD_LENGTH_INTERNAL]; diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h index 9ff2772b1..53ae385ea 100644 --- a/native/jni/src/terminal_attributes.h +++ b/native/jni/src/terminal_attributes.h @@ -52,9 +52,9 @@ class TerminalAttributes { 0 != (shortcutFlags & BinaryFormat::FLAG_ATTRIBUTE_HAS_NEXT); unsigned int i; for (i = 0; i < MAX_WORD_LENGTH_INTERNAL; ++i) { - const int charCode = BinaryFormat::getCharCodeAndForwardPointer(mDict, &mPos); - if (NOT_A_CHARACTER == charCode) break; - outWord[i] = (uint16_t)charCode; + const int codePoint = BinaryFormat::getCodePointAndForwardPointer(mDict, &mPos); + if (NOT_A_CODE_POINT == codePoint) break; + outWord[i] = (uint16_t)codePoint; } *outFreq = BinaryFormat::getAttributeFrequencyFromFlags(shortcutFlags); mPos += BinaryFormat::CHARACTER_ARRAY_TERMINATOR_SIZE; @@ -62,8 +62,8 @@ class TerminalAttributes { } }; - TerminalAttributes(const uint8_t *const dict, const uint8_t flags, const int pos) : - mDict(dict), mFlags(flags), mStartPos(pos) { + TerminalAttributes(const uint8_t *const dict, const uint8_t flags, const int pos) + : mDict(dict), mFlags(flags), mStartPos(pos) { } inline ShortcutIterator getShortcutIterator() const { diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp index d4c51df63..b7e245a6c 100644 --- a/native/jni/src/unigram_dictionary.cpp +++ b/native/jni/src/unigram_dictionary.cpp @@ -58,12 +58,12 @@ UnigramDictionary::~UnigramDictionary() { } static inline unsigned int getCodesBufferSize(const int *codes, const int codesSize) { - return sizeof(*codes) * codesSize; + return static_cast<unsigned int>(sizeof(*codes)) * codesSize; } // TODO: This needs to take a const unsigned short* and not tinker with its contents -static inline void addWord( - unsigned short *word, int length, int frequency, WordsPriorityQueue *queue, int type) { +static inline void addWord(unsigned short *word, int length, int frequency, + WordsPriorityQueue *queue, int type) { queue->push(frequency, word, length, type); } @@ -106,7 +106,7 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit WordsPriorityQueuePool *queuePool, const digraph_t *const digraphs, const unsigned int digraphsSize) const { - const int startIndex = codesDest - codesBuffer; + const int startIndex = static_cast<int>(codesDest - codesBuffer); if (currentDepth < MAX_DIGRAPH_SEARCH_DEPTH) { for (int i = 0; i < codesRemain; ++i) { xCoordinatesBuffer[startIndex + i] = xcoordinates[codesBufferSize - codesRemain + i]; @@ -170,8 +170,7 @@ void UnigramDictionary::getWordWithDigraphSuggestionsRec(ProximityInfo *proximit // bigramMap contains the association <bigram address> -> <bigram frequency> // bigramFilter is a bloom filter for fast rejection: see functions setInFilter and isInFilter // in bigram_dictionary.cpp -int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, - const int *xcoordinates, +int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, const int codesSize, const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, const bool useFullEditDistance, unsigned short *outWords, int *frequencies, @@ -597,11 +596,10 @@ int UnigramDictionary::getSubStringSuggestion( void UnigramDictionary::getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, const int *codes, - const bool useFullEditDistance, const int inputSize, - Correction *correction, WordsPriorityQueuePool *queuePool, - const bool hasAutoCorrectionCandidate, const int startInputPos, const int startWordIndex, - const int outputWordLength, int *freqArray, int *wordLengthArray, - unsigned short *outputWord) const { + const bool useFullEditDistance, const int inputSize, Correction *correction, + WordsPriorityQueuePool *queuePool, const bool hasAutoCorrectionCandidate, + const int startInputPos, const int startWordIndex, const int outputWordLength, + int *freqArray, int *wordLengthArray, unsigned short *outputWord) const { if (startWordIndex >= (MULTIPLE_WORDS_SUGGESTION_MAX_WORDS - 1)) { // Return if the last word index return; @@ -641,7 +639,7 @@ void UnigramDictionary::getMultiWordsSuggestionRec(ProximityInfo *proximityInfo, // Missing space inputWordStartPos = i; inputWordLength = inputSize - i; - if(getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes, + if (getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes, useFullEditDistance, correction, queuePool, inputSize, hasAutoCorrectionCandidate, startWordIndex + 1, inputWordStartPos, inputWordLength, tempOutputWordLength, false /* missing space */, freqArray, wordLengthArray, outputWord, 0) @@ -724,13 +722,13 @@ inline int UnigramDictionary::getMostFrequentWordLike(const int startInputIndex, // In and out parameters may point to the same location. This function takes care // not to use any input parameters after it wrote into its outputs. static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, - const uint8_t *const root, const int startPos, - const uint16_t *const inWord, const int startInputIndex, - int32_t *outNewWord, int *outInputIndex, int *outPos) { + const uint8_t *const root, const int startPos, const uint16_t *const inWord, + const int startInputIndex, const int inputSize, int32_t *outNewWord, int *outInputIndex, + int *outPos) { const bool hasMultipleChars = (0 != (BinaryFormat::FLAG_HAS_MULTIPLE_CHARS & flags)); int pos = startPos; - int32_t character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); - int32_t baseChar = toBaseLowerCase(character); + int32_t codePoint = BinaryFormat::getCodePointAndForwardPointer(root, &pos); + int32_t baseChar = toBaseLowerCase(codePoint); const uint16_t wChar = toBaseLowerCase(inWord[startInputIndex]); if (baseChar != wChar) { @@ -739,18 +737,18 @@ static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, return false; } int inputIndex = startInputIndex; - outNewWord[inputIndex] = character; + outNewWord[inputIndex] = codePoint; if (hasMultipleChars) { - character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); - while (NOT_A_CHARACTER != character) { - baseChar = toBaseLowerCase(character); - if (toBaseLowerCase(inWord[++inputIndex]) != baseChar) { + codePoint = BinaryFormat::getCodePointAndForwardPointer(root, &pos); + while (NOT_A_CODE_POINT != codePoint) { + baseChar = toBaseLowerCase(codePoint); + if (inputIndex + 1 >= inputSize || toBaseLowerCase(inWord[++inputIndex]) != baseChar) { *outPos = BinaryFormat::skipOtherCharacters(root, pos); *outInputIndex = startInputIndex; return false; } - outNewWord[inputIndex] = character; - character = BinaryFormat::getCharCodeAndForwardPointer(root, &pos); + outNewWord[inputIndex] = codePoint; + codePoint = BinaryFormat::getCodePointAndForwardPointer(root, &pos); } } *outInputIndex = inputIndex + 1; @@ -765,8 +763,9 @@ static inline bool testCharGroupForContinuedLikeness(const uint8_t flags, static inline void onTerminalWordLike(const int freq, int32_t *newWord, const int length, short unsigned int *outWord, int *maxFreq) { if (freq > *maxFreq) { - for (int q = 0; q < length; ++q) + for (int q = 0; q < length; ++q) { outWord[q] = newWord[q]; + } outWord[length] = 0; *maxFreq = freq; } @@ -775,7 +774,7 @@ static inline void onTerminalWordLike(const int freq, int32_t *newWord, const in // Will find the highest frequency of the words like the one passed as an argument, // that is, everything that only differs by case/accents. int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t *const inWord, - const int length, short unsigned int *outWord) const { + const int inputSize, short unsigned int *outWord) const { int32_t newWord[MAX_WORD_LENGTH_INTERNAL]; int depth = 0; int maxFreq = -1; @@ -795,12 +794,12 @@ int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t *const inWord int inputIndex = stackInputIndex[depth]; const uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos); // Test whether all chars in this group match with the word we are searching for. If so, - // we want to traverse its children (or if the length match, evaluate its frequency). + // we want to traverse its children (or if the inputSize match, evaluate its frequency). // Note that this function will output the position regardless, but will only write // into inputIndex if there is a match. const bool isAlike = testCharGroupForContinuedLikeness(flags, root, pos, inWord, - inputIndex, newWord, &inputIndex, &pos); - if (isAlike && (BinaryFormat::FLAG_IS_TERMINAL & flags) && (inputIndex == length)) { + inputIndex, inputSize, newWord, &inputIndex, &pos); + if (isAlike && (BinaryFormat::FLAG_IS_TERMINAL & flags) && (inputIndex == inputSize)) { const int frequency = BinaryFormat::readFrequencyWithoutMovingPointer(root, pos); onTerminalWordLike(frequency, newWord, inputIndex, outWord, &maxFreq); } @@ -809,8 +808,8 @@ int UnigramDictionary::getMostFrequentWordLikeInner(const uint16_t *const inWord const int childrenNodePos = BinaryFormat::readChildrenPosition(root, flags, pos); // If we had a match and the word has children, we want to traverse them. We don't have // to traverse words longer than the one we are searching for, since they will not match - // anyway, so don't traverse unless inputIndex < length. - if (isAlike && (-1 != childrenNodePos) && (inputIndex < length)) { + // anyway, so don't traverse unless inputIndex < inputSize. + if (isAlike && (-1 != childrenNodePos) && (inputIndex < inputSize)) { // Save position for this depth, to get back to this once children are done stackChildCount[depth] = charGroupIndex; stackSiblingPos[depth] = siblingPos; @@ -853,7 +852,7 @@ int UnigramDictionary::getFrequency(const int32_t *const inWord, const int lengt if (hasMultipleChars) { pos = BinaryFormat::skipOtherCharacters(root, pos); } else { - BinaryFormat::getCharCodeAndForwardPointer(DICT_ROOT, &pos); + BinaryFormat::getCodePointAndForwardPointer(DICT_ROOT, &pos); } const int unigramFreq = BinaryFormat::readFrequencyWithoutMovingPointer(root, pos); return unigramFreq; @@ -907,23 +906,23 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, // else if FLAG_IS_TERMINAL: the frequency // else if MASK_GROUP_ADDRESS_TYPE is not NONE: the children address // Note that you can't have a node that both is not a terminal and has no children. - int32_t c = BinaryFormat::getCharCodeAndForwardPointer(DICT_ROOT, &pos); - assert(NOT_A_CHARACTER != c); + int32_t c = BinaryFormat::getCodePointAndForwardPointer(DICT_ROOT, &pos); + assert(NOT_A_CODE_POINT != c); // We are going to loop through each character and make it look like it's a different // node each time. To do that, we will process characters in this node in order until - // we find the character terminator. This is signalled by getCharCode* returning - // NOT_A_CHARACTER. + // we find the character terminator. This is signalled by getCodePoint* returning + // NOT_A_CODE_POINT. // As a special case, if there is only one character in this node, we must not read the - // next bytes so we will simulate the NOT_A_CHARACTER return by testing the flags. + // next bytes so we will simulate the NOT_A_CODE_POINT return by testing the flags. // This way, each loop run will look like a "virtual node". do { // We prefetch the next char. If 'c' is the last char of this node, we will have - // NOT_A_CHARACTER in the next char. From this we can decide whether this virtual node + // NOT_A_CODE_POINT in the next char. From this we can decide whether this virtual node // should behave as a terminal or not and whether we have children. const int32_t nextc = hasMultipleChars - ? BinaryFormat::getCharCodeAndForwardPointer(DICT_ROOT, &pos) : NOT_A_CHARACTER; - const bool isLastChar = (NOT_A_CHARACTER == nextc); + ? BinaryFormat::getCodePointAndForwardPointer(DICT_ROOT, &pos) : NOT_A_CODE_POINT; + const bool isLastChar = (NOT_A_CODE_POINT == nextc); // If there are more chars in this nodes, then this virtual node is not a terminal. // If we are on the last char, this virtual node is a terminal if this node is. const bool isTerminal = isLastChar && isTerminalNode; @@ -952,9 +951,9 @@ inline bool UnigramDictionary::processCurrentNode(const int initialPos, // Prepare for the next character. Promote the prefetched char to current char - the loop // will take care of prefetching the next. If we finally found our last char, nextc will - // contain NOT_A_CHARACTER. + // contain NOT_A_CODE_POINT. c = nextc; - } while (NOT_A_CHARACTER != c); + } while (NOT_A_CODE_POINT != c); if (isTerminalNode) { // The frequency should be here, because we come here only if this is actually diff --git a/native/jni/src/unigram_dictionary.h b/native/jni/src/unigram_dictionary.h index 2c6622210..57129bb07 100644 --- a/native/jni/src/unigram_dictionary.h +++ b/native/jni/src/unigram_dictionary.h @@ -43,11 +43,11 @@ class UnigramDictionary { int fullWordMultiplier, int maxWordLength, int maxWords, const unsigned int flags); int getFrequency(const int32_t *const inWord, const int length) const; int getBigramPosition(int pos, unsigned short *word, int offset, int length) const; - int getSuggestions( - ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, - const int *codes, const int codesSize, const std::map<int, int> *bigramMap, - const uint8_t *bigramFilter, const bool useFullEditDistance, unsigned short *outWords, - int *frequencies, int *outputTypes) const; + int getSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates, + const int *ycoordinates, const int *codes, const int codesSize, + const std::map<int, int> *bigramMap, const uint8_t *bigramFilter, + const bool useFullEditDistance, unsigned short *outWords, int *frequencies, + int *outputTypes) const; virtual ~UnigramDictionary(); private: @@ -94,7 +94,7 @@ class UnigramDictionary { const int currentWordIndex) const; int getMostFrequentWordLike(const int startInputIndex, const int inputSize, Correction *correction, unsigned short *word) const; - int getMostFrequentWordLikeInner(const uint16_t *const inWord, const int length, + int getMostFrequentWordLikeInner(const uint16_t *const inWord, const int inputSize, short unsigned int *outWord) const; int getSubStringSuggestion( ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates, diff --git a/native/jni/src/words_priority_queue_pool.h b/native/jni/src/words_priority_queue_pool.h index c5de9797f..2d52903e0 100644 --- a/native/jni/src/words_priority_queue_pool.h +++ b/native/jni/src/words_priority_queue_pool.h @@ -30,7 +30,7 @@ class WordsPriorityQueuePool { mainQueueMaxWords, maxWordLength)) { for (int i = 0, subQueueBufOffset = 0; i < MULTIPLE_WORDS_SUGGESTION_MAX_WORDS * SUB_QUEUE_MAX_COUNT; - ++i, subQueueBufOffset += sizeof(WordsPriorityQueue)) { + ++i, subQueueBufOffset += static_cast<int>(sizeof(WordsPriorityQueue))) { mSubQueues[i] = new(mSubQueueBuf + subQueueBufOffset) WordsPriorityQueue(subQueueMaxWords, maxWordLength); } diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java index ffd95f57a..fe58cb84e 100644 --- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java +++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java @@ -41,6 +41,7 @@ import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import java.util.HashMap; +import java.util.Locale; public class InputTestsBase extends ServiceTestCase<LatinIME> { @@ -51,7 +52,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { protected LatinIME mLatinIME; protected Keyboard mKeyboard; - protected TextView mTextView; + protected MyTextView mTextView; protected InputConnection mInputConnection; private final HashMap<String, InputMethodSubtype> mSubtypeMap = new HashMap<String, InputMethodSubtype>(); @@ -86,6 +87,27 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { return (mSpan instanceof SuggestionSpan) && 0 != (SuggestionSpan.FLAG_AUTO_CORRECTION & ((SuggestionSpan)mSpan).getFlags()); } + public String[] getSuggestions() { + return ((SuggestionSpan)mSpan).getSuggestions(); + } + } + + // A helper class to increase control over the TextView + public static class MyTextView extends TextView { + public Locale mCurrentLocale; + public MyTextView(final Context c) { + super(c); + } + public void onAttachedToWindow() { + super.onAttachedToWindow(); + } + public Locale getTextServicesLocale() { + // This method is necessary because TextView is asking this method for the language + // to check the spell in. If we don't override this, the spell checker will run in + // whatever language the keyboard is currently set on the test device, ignoring any + // settings we do inside the tests. + return mCurrentLocale; + } } public InputTestsBase() { @@ -112,7 +134,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { @Override protected void setUp() throws Exception { super.setUp(); - mTextView = new TextView(getContext()); + mTextView = new MyTextView(getContext()); mTextView.setInputType(InputType.TYPE_CLASS_TEXT); mTextView.setEnabled(true); setupService(); @@ -248,6 +270,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIME> { protected void changeLanguage(final String locale) { final InputMethodSubtype subtype = mSubtypeMap.get(locale); + mTextView.mCurrentLocale = LocaleUtils.constructLocaleFromString(locale); if (subtype == null) { fail("InputMethodSubtype for locale " + locale + " is not enabled"); } diff --git a/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java b/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java new file mode 100644 index 000000000..21406d370 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin.spellcheck; + +import android.text.SpannableStringBuilder; +import android.text.style.CharacterStyle; +import android.text.style.SuggestionSpan; + +import com.android.inputmethod.latin.InputTestsBase; + +public class AndroidSpellCheckerServiceTest extends InputTestsBase { + public void testSpellchecker() { + mTextView.onAttachedToWindow(); + mTextView.setText("tgis"); + type(" "); + sleep(1000); + runMessages(); + sleep(1000); + + final SpanGetter span = new SpanGetter(mTextView.getText(), SuggestionSpan.class); + // If no span, the following will crash + final String[] suggestions = span.getSuggestions(); + // For this test we consider "tgis" should yield at least 2 suggestions (at this moment + // it yields 5). + assertTrue(suggestions.length >= 2); + // We also assume the top suggestion should be "this". + assertEquals("", "this", suggestions[0]); + } + + public void testRussianSpellchecker() { + changeLanguage("ru"); + mTextView.onAttachedToWindow(); + mTextView.setText("годп"); + type(" "); + sleep(1000); + runMessages(); + sleep(1000); + + final SpanGetter span = new SpanGetter(mTextView.getText(), SuggestionSpan.class); + // If no span, the following will crash + final String[] suggestions = span.getSuggestions(); + // For this test we consider "годп" should yield at least 2 suggestions (at this moment + // it yields 5). + assertTrue(suggestions.length >= 2); + // We also assume the top suggestion should be "года", which is the top word in the + // Russian dictionary. + assertEquals("", "года", suggestions[0]); + } +} |