aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod')
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java22
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java22
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java123
-rw-r--r--java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java149
-rw-r--r--java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java142
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java27
6 files changed, 369 insertions, 116 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index a02203d31..0517bc814 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -32,6 +32,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -956,14 +957,23 @@ public final class UpdateHandler {
WordListMetadata metadata = WordListMetadata.createFromContentValues(installCandidate);
actions.add(new ActionBatch.StartDownloadAction(clientId, metadata));
final String localeString = installCandidate.getAsString(MetadataDbHelper.LOCALE_COLUMN);
+
// We are in a content provider: we can't do any UI at all. We have to defer the displaying
// itself to the service. Also, we only display this when the user does not have a
- // dictionary for this language already.
- final Intent intent = new Intent();
- intent.setClass(context, DictionaryService.class);
- intent.setAction(DictionaryService.SHOW_DOWNLOAD_TOAST_INTENT_ACTION);
- intent.putExtra(DictionaryService.LOCALE_INTENT_ARGUMENT, localeString);
- context.startService(intent);
+ // dictionary for this language already. During setup wizard, however, this UI is
+ // suppressed.
+ final boolean deviceProvisioned = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+ if (deviceProvisioned) {
+ final Intent intent = new Intent();
+ intent.setClass(context, DictionaryService.class);
+ intent.setAction(DictionaryService.SHOW_DOWNLOAD_TOAST_INTENT_ACTION);
+ intent.putExtra(DictionaryService.LOCALE_INTENT_ARGUMENT, localeString);
+ context.startService(intent);
+ } else {
+ Log.i(TAG, "installIfNeverRequested() : Don't show download toast");
+ }
+
Log.i(TAG, "installIfNeverRequested() : StartDownloadAction for " + metadata);
actions.execute(context, new LogProblemReporter(TAG));
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index a1f7bf0e1..7352f911b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -60,6 +60,16 @@ public final class KeyboardId {
public static final int ELEMENT_EMOJI_CATEGORY4 = 14;
public static final int ELEMENT_EMOJI_CATEGORY5 = 15;
public static final int ELEMENT_EMOJI_CATEGORY6 = 16;
+ public static final int ELEMENT_EMOJI_CATEGORY7 = 17;
+ public static final int ELEMENT_EMOJI_CATEGORY8 = 18;
+ public static final int ELEMENT_EMOJI_CATEGORY9 = 19;
+ public static final int ELEMENT_EMOJI_CATEGORY10 = 20;
+ public static final int ELEMENT_EMOJI_CATEGORY11 = 21;
+ public static final int ELEMENT_EMOJI_CATEGORY12 = 22;
+ public static final int ELEMENT_EMOJI_CATEGORY13 = 23;
+ public static final int ELEMENT_EMOJI_CATEGORY14 = 24;
+ public static final int ELEMENT_EMOJI_CATEGORY15 = 25;
+ public static final int ELEMENT_EMOJI_CATEGORY16 = 26;
public final RichInputMethodSubtype mSubtype;
public final int mWidth;
@@ -225,6 +235,16 @@ public final class KeyboardId {
case ELEMENT_EMOJI_CATEGORY4: return "emojiCategory4";
case ELEMENT_EMOJI_CATEGORY5: return "emojiCategory5";
case ELEMENT_EMOJI_CATEGORY6: return "emojiCategory6";
+ case ELEMENT_EMOJI_CATEGORY7: return "emojiCategory7";
+ case ELEMENT_EMOJI_CATEGORY8: return "emojiCategory8";
+ case ELEMENT_EMOJI_CATEGORY9: return "emojiCategory9";
+ case ELEMENT_EMOJI_CATEGORY10: return "emojiCategory10";
+ case ELEMENT_EMOJI_CATEGORY11: return "emojiCategory11";
+ case ELEMENT_EMOJI_CATEGORY12: return "emojiCategory12";
+ case ELEMENT_EMOJI_CATEGORY13: return "emojiCategory13";
+ case ELEMENT_EMOJI_CATEGORY14: return "emojiCategory14";
+ case ELEMENT_EMOJI_CATEGORY15: return "emojiCategory15";
+ case ELEMENT_EMOJI_CATEGORY16: return "emojiCategory16";
default: return null;
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 92e5dfceb..4d337b6f3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -44,6 +44,8 @@ import com.android.inputmethod.latin.utils.RecapitalizeStatus;
import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.ScriptUtils;
+import javax.annotation.Nonnull;
+
public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
@@ -139,15 +141,18 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
}
- private void setKeyboard(final Keyboard keyboard) {
+ private void setKeyboard(
+ @Nonnull final int keyboardId,
+ @Nonnull final KeyboardSwitchState toggleState) {
// Make {@link MainKeyboardView} visible and hide {@link EmojiPalettesView}.
final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent();
- setMainKeyboardFrame(currentSettingsValues);
+ setMainKeyboardFrame(currentSettingsValues, toggleState);
// TODO: pass this object to setKeyboard instead of getting the current values.
final MainKeyboardView keyboardView = mKeyboardView;
final Keyboard oldKeyboard = keyboardView.getKeyboard();
- keyboardView.setKeyboard(keyboard);
- mCurrentInputView.setKeyboardTopPadding(keyboard.mTopPadding);
+ final Keyboard newKeyboard = mKeyboardLayoutSet.getKeyboard(keyboardId);
+ keyboardView.setKeyboard(newKeyboard);
+ mCurrentInputView.setKeyboardTopPadding(newKeyboard.mTopPadding);
keyboardView.setKeyPreviewPopupEnabled(
currentSettingsValues.mKeyPreviewPopupOn,
currentSettingsValues.mKeyPreviewPopupDismissDelay);
@@ -161,9 +166,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
currentSettingsValues.mKeyPreviewDismissDuration);
keyboardView.updateShortcutKey(mRichImm.isShortcutImeReady());
final boolean subtypeChanged = (oldKeyboard == null)
- || !keyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype);
+ || !newKeyboard.mId.mSubtype.equals(oldKeyboard.mId.mSubtype);
final int languageOnSpacebarFormatType = LanguageOnSpacebarUtils
- .getLanguageOnSpacebarFormatType(keyboard.mId.mSubtype);
+ .getLanguageOnSpacebarFormatType(newKeyboard.mId.mSubtype);
final boolean hasMultipleEnabledIMEsOrSubtypes = mRichImm
.hasMultipleEnabledIMEsOrSubtypes(true /* shouldIncludeAuxiliarySubtypes */);
keyboardView.startDisplayLanguageOnSpacebar(subtypeChanged, languageOnSpacebarFormatType,
@@ -205,7 +210,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setAlphabetKeyboard");
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET));
+ setKeyboard(KeyboardId.ELEMENT_ALPHABET, KeyboardSwitchState.OTHER);
}
// Implements {@link KeyboardState.SwitchActions}.
@@ -214,7 +219,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setAlphabetManualShiftedKeyboard");
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED));
+ setKeyboard(KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED, KeyboardSwitchState.OTHER);
}
// Implements {@link KeyboardState.SwitchActions}.
@@ -223,7 +228,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setAlphabetAutomaticShiftedKeyboard");
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED));
+ setKeyboard(KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED, KeyboardSwitchState.OTHER);
}
// Implements {@link KeyboardState.SwitchActions}.
@@ -232,7 +237,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setAlphabetShiftLockedKeyboard");
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED));
+ setKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED, KeyboardSwitchState.OTHER);
}
// Implements {@link KeyboardState.SwitchActions}.
@@ -241,7 +246,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setAlphabetShiftLockShiftedKeyboard");
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED));
+ setKeyboard(KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED, KeyboardSwitchState.OTHER);
}
// Implements {@link KeyboardState.SwitchActions}.
@@ -250,11 +255,29 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (DEBUG_ACTION) {
Log.d(TAG, "setSymbolsKeyboard");
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS));
+ setKeyboard(KeyboardId.ELEMENT_SYMBOLS, KeyboardSwitchState.OTHER);
+ }
+
+ // Implements {@link KeyboardState.SwitchActions}.
+ @Override
+ public void setSymbolsShiftedKeyboard() {
+ if (DEBUG_ACTION) {
+ Log.d(TAG, "setSymbolsShiftedKeyboard");
+ }
+ setKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED, KeyboardSwitchState.SYMBOLS_SHIFTED);
}
- private void setMainKeyboardFrame(final SettingsValues settingsValues) {
- final int visibility = settingsValues.mHasHardwareKeyboard ? View.GONE : View.VISIBLE;
+ public boolean isImeSuppressedByHardwareKeyboard(
+ @Nonnull final SettingsValues settingsValues,
+ @Nonnull final KeyboardSwitchState toggleState) {
+ return settingsValues.mHasHardwareKeyboard && toggleState == KeyboardSwitchState.HIDDEN;
+ }
+
+ private void setMainKeyboardFrame(
+ @Nonnull final SettingsValues settingsValues,
+ @Nonnull final KeyboardSwitchState toggleState) {
+ final int visibility = isImeSuppressedByHardwareKeyboard(settingsValues, toggleState)
+ ? View.GONE : View.VISIBLE;
mKeyboardView.setVisibility(visibility);
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
// @see #getVisibleKeyboardView() and
@@ -282,24 +305,55 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mEmojiPalettesView.setVisibility(View.VISIBLE);
}
- public void onToggleEmojiKeyboard() {
- final boolean needsToLoadKeyboard = (mKeyboardLayoutSet == null);
- if (needsToLoadKeyboard || !isShowingEmojiPalettes()) {
- mLatinIME.startShowingInputView(needsToLoadKeyboard);
- setEmojiKeyboard();
- } else {
- mLatinIME.stopShowingInputView();
- setAlphabetKeyboard();
+ public enum KeyboardSwitchState {
+ HIDDEN(-1),
+ SYMBOLS_SHIFTED(KeyboardId.ELEMENT_SYMBOLS_SHIFTED),
+ EMOJI(KeyboardId.ELEMENT_EMOJI_RECENTS),
+ OTHER(-1);
+
+ final int mKeyboardId;
+
+ KeyboardSwitchState(int keyboardId) {
+ mKeyboardId = keyboardId;
}
}
- // Implements {@link KeyboardState.SwitchActions}.
- @Override
- public void setSymbolsShiftedKeyboard() {
- if (DEBUG_ACTION) {
- Log.d(TAG, "setSymbolsShiftedKeyboard");
+ public KeyboardSwitchState getKeyboardSwitchState() {
+ boolean hidden = !isShowingEmojiPalettes()
+ && (mKeyboardLayoutSet == null
+ || mKeyboardView == null
+ || !mKeyboardView.isShown());
+ KeyboardSwitchState state;
+ if (hidden) {
+ return KeyboardSwitchState.HIDDEN;
+ } else if (isShowingEmojiPalettes()) {
+ return KeyboardSwitchState.EMOJI;
+ } else if (isShowingKeyboardId(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)) {
+ return KeyboardSwitchState.SYMBOLS_SHIFTED;
+ }
+ return KeyboardSwitchState.OTHER;
+ }
+
+ public void onToggleKeyboard(@Nonnull final KeyboardSwitchState toggleState) {
+ KeyboardSwitchState currentState = getKeyboardSwitchState();
+ Log.w(TAG, "onToggleKeyboard() : Current = " + currentState + " : Toggle = " + toggleState);
+ if (currentState == toggleState) {
+ mLatinIME.stopShowingInputView();
+ mLatinIME.hideWindow();
+ setAlphabetKeyboard();
+ } else {
+ mLatinIME.startShowingInputView(true);
+ if (toggleState == KeyboardSwitchState.EMOJI) {
+ setEmojiKeyboard();
+ } else {
+ mEmojiPalettesView.stopEmojiPalettes();
+ mEmojiPalettesView.setVisibility(View.GONE);
+
+ mMainKeyboardFrame.setVisibility(View.VISIBLE);
+ mKeyboardView.setVisibility(View.VISIBLE);
+ setKeyboard(toggleState.mKeyboardId, toggleState);
+ }
}
- setKeyboard(mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_SYMBOLS_SHIFTED));
}
// Future method for requesting an updating to the shift state.
@@ -355,6 +409,19 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mState.onEvent(event, currentAutoCapsState, currentRecapitalizeState);
}
+ public boolean isShowingKeyboardId(@Nonnull int... keyboardIds) {
+ if (mKeyboardView == null || !mKeyboardView.isShown()) {
+ return false;
+ }
+ int activeKeyboardId = mKeyboardView.getKeyboard().mId.mElementId;
+ for (int keyboardId : keyboardIds) {
+ if (activeKeyboardId == keyboardId) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public boolean isShowingEmojiPalettes() {
return mEmojiPalettesView != null && mEmojiPalettesView.isShown();
}
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java
index a9711aed2..75b7962cb 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -19,6 +19,7 @@ package com.android.inputmethod.keyboard.emoji;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
@@ -50,6 +51,16 @@ final class EmojiCategory {
private static final int ID_PLACES = 4;
private static final int ID_SYMBOLS = 5;
private static final int ID_EMOTICONS = 6;
+ private static final int ID_FLAGS = 7;
+ private static final int ID_EIGHT_SMILEY_PEOPLE = 8;
+ private static final int ID_EIGHT_ANIMALS_NATURE = 9;
+ private static final int ID_EIGHT_FOOD_DRINK = 10;
+ private static final int ID_EIGHT_TRAVEL_PLACES = 11;
+ private static final int ID_EIGHT_ACTIVITY = 12;
+ private static final int ID_EIGHT_OBJECTS = 13;
+ private static final int ID_EIGHT_SYMBOLS = 14;
+ private static final int ID_EIGHT_FLAGS = 15;
+ private static final int ID_EIGHT_SMILEY_PEOPLE_BORING = 16;
public final class CategoryProperties {
public final int mCategoryId;
@@ -67,7 +78,17 @@ final class EmojiCategory {
"nature",
"places",
"symbols",
- "emoticons" };
+ "emoticons",
+ "flags",
+ "smiley & people",
+ "animals & nature",
+ "food & drink",
+ "travel & places",
+ "activity",
+ "objects2",
+ "symbols2",
+ "flags2",
+ "smiley & people2" };
private static final int[] sCategoryTabIconAttr = {
R.styleable.EmojiPalettesView_iconEmojiRecentsTab,
@@ -76,7 +97,17 @@ final class EmojiCategory {
R.styleable.EmojiPalettesView_iconEmojiCategory3Tab,
R.styleable.EmojiPalettesView_iconEmojiCategory4Tab,
R.styleable.EmojiPalettesView_iconEmojiCategory5Tab,
- R.styleable.EmojiPalettesView_iconEmojiCategory6Tab };
+ R.styleable.EmojiPalettesView_iconEmojiCategory6Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory7Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory8Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory9Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory10Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory11Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory12Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory13Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory14Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory15Tab,
+ R.styleable.EmojiPalettesView_iconEmojiCategory16Tab };
private static final int[] sAccessibilityDescriptionResourceIdsForCategories = {
R.string.spoken_descrption_emoji_category_recents,
@@ -85,7 +116,17 @@ final class EmojiCategory {
R.string.spoken_descrption_emoji_category_nature,
R.string.spoken_descrption_emoji_category_places,
R.string.spoken_descrption_emoji_category_symbols,
- R.string.spoken_descrption_emoji_category_emoticons };
+ R.string.spoken_descrption_emoji_category_emoticons,
+ R.string.spoken_descrption_emoji_category_flags,
+ R.string.spoken_descrption_emoji_category_eight_smiley_people,
+ R.string.spoken_descrption_emoji_category_eight_animals_nature,
+ R.string.spoken_descrption_emoji_category_eight_food_drink,
+ R.string.spoken_descrption_emoji_category_eight_travel_places,
+ R.string.spoken_descrption_emoji_category_eight_activity,
+ R.string.spoken_descrption_emoji_category_objects,
+ R.string.spoken_descrption_emoji_category_symbols,
+ R.string.spoken_descrption_emoji_category_flags,
+ R.string.spoken_descrption_emoji_category_eight_smiley_people };
private static final int[] sCategoryElementId = {
KeyboardId.ELEMENT_EMOJI_RECENTS,
@@ -94,7 +135,17 @@ final class EmojiCategory {
KeyboardId.ELEMENT_EMOJI_CATEGORY3,
KeyboardId.ELEMENT_EMOJI_CATEGORY4,
KeyboardId.ELEMENT_EMOJI_CATEGORY5,
- KeyboardId.ELEMENT_EMOJI_CATEGORY6 };
+ KeyboardId.ELEMENT_EMOJI_CATEGORY6,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY7,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY8,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY9,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY10,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY11,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY12,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY13,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY14,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY15,
+ KeyboardId.ELEMENT_EMOJI_CATEGORY16 };
private final SharedPreferences mPrefs;
private final Resources mRes;
@@ -120,27 +171,49 @@ final class EmojiCategory {
mCategoryTabIconId[i] = emojiPaletteViewAttr.getResourceId(
sCategoryTabIconAttr[i], 0);
}
+
+ int defaultCategoryId = EmojiCategory.ID_SYMBOLS;
addShownCategoryId(EmojiCategory.ID_RECENTS);
if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.KITKAT) {
- addShownCategoryId(EmojiCategory.ID_PEOPLE);
- addShownCategoryId(EmojiCategory.ID_OBJECTS);
- addShownCategoryId(EmojiCategory.ID_NATURE);
- addShownCategoryId(EmojiCategory.ID_PLACES);
- mCurrentCategoryId =
- Settings.readLastShownEmojiCategoryId(mPrefs, EmojiCategory.ID_PEOPLE);
- } else {
- mCurrentCategoryId =
- Settings.readLastShownEmojiCategoryId(mPrefs, EmojiCategory.ID_SYMBOLS);
+ if (canShowUnicodeEightEmoji()) {
+ defaultCategoryId = EmojiCategory.ID_EIGHT_SMILEY_PEOPLE;
+ addShownCategoryId(EmojiCategory.ID_EIGHT_SMILEY_PEOPLE);
+ addShownCategoryId(EmojiCategory.ID_EIGHT_ANIMALS_NATURE);
+ addShownCategoryId(EmojiCategory.ID_EIGHT_FOOD_DRINK);
+ addShownCategoryId(EmojiCategory.ID_EIGHT_TRAVEL_PLACES);
+ addShownCategoryId(EmojiCategory.ID_EIGHT_ACTIVITY);
+ addShownCategoryId(EmojiCategory.ID_EIGHT_OBJECTS);
+ addShownCategoryId(EmojiCategory.ID_EIGHT_SYMBOLS);
+ addShownCategoryId(EmojiCategory.ID_FLAGS); // Exclude combinations without glyphs.
+ } else {
+ defaultCategoryId = EmojiCategory.ID_PEOPLE;
+ addShownCategoryId(EmojiCategory.ID_PEOPLE);
+ addShownCategoryId(EmojiCategory.ID_OBJECTS);
+ addShownCategoryId(EmojiCategory.ID_NATURE);
+ addShownCategoryId(EmojiCategory.ID_PLACES);
+ addShownCategoryId(EmojiCategory.ID_SYMBOLS);
+ if (canShowFlagEmoji()) {
+ addShownCategoryId(EmojiCategory.ID_FLAGS);
+ }
+ }
}
- addShownCategoryId(EmojiCategory.ID_SYMBOLS);
addShownCategoryId(EmojiCategory.ID_EMOTICONS);
- getKeyboard(EmojiCategory.ID_RECENTS, 0 /* cagetoryPageId */)
- .loadRecentKeys(mCategoryKeyboardMap.values());
+
+ DynamicGridKeyboard recentsKbd =
+ getKeyboard(EmojiCategory.ID_RECENTS, 0 /* categoryPageId */);
+ recentsKbd.loadRecentKeys(mCategoryKeyboardMap.values());
+
+ mCurrentCategoryId = Settings.readLastShownEmojiCategoryId(mPrefs, defaultCategoryId);
+ if (mCurrentCategoryId == EmojiCategory.ID_RECENTS &&
+ recentsKbd.getSortedKeys().isEmpty()) {
+ Log.i(TAG, "No recent emojis found, starting in category " + mCurrentCategoryId);
+ mCurrentCategoryId = defaultCategoryId;
+ }
}
private void addShownCategoryId(final int categoryId) {
// Load a keyboard of categoryId
- getKeyboard(categoryId, 0 /* cagetoryPageId */);
+ getKeyboard(categoryId, 0 /* categoryPageId */);
final CategoryProperties properties =
new CategoryProperties(categoryId, getCategoryPageCount(categoryId));
mShownCategories.add(properties);
@@ -275,16 +348,16 @@ final class EmojiCategory {
public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) {
synchronized (mCategoryKeyboardMap) {
- final Long categotyKeyboardMapKey = getCategoryKeyboardMapKey(categoryId, id);
- if (mCategoryKeyboardMap.containsKey(categotyKeyboardMapKey)) {
- return mCategoryKeyboardMap.get(categotyKeyboardMapKey);
+ final Long categoryKeyboardMapKey = getCategoryKeyboardMapKey(categoryId, id);
+ if (mCategoryKeyboardMap.containsKey(categoryKeyboardMapKey)) {
+ return mCategoryKeyboardMap.get(categoryKeyboardMapKey);
}
if (categoryId == EmojiCategory.ID_RECENTS) {
final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs,
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
mMaxPageKeyCount, categoryId);
- mCategoryKeyboardMap.put(categotyKeyboardMapKey, kbd);
+ mCategoryKeyboardMap.put(categoryKeyboardMapKey, kbd);
return kbd;
}
@@ -304,7 +377,7 @@ final class EmojiCategory {
mCategoryKeyboardMap.put(
getCategoryKeyboardMapKey(categoryId, pageId), tempKeyboard);
}
- return mCategoryKeyboardMap.get(categotyKeyboardMapKey);
+ return mCategoryKeyboardMap.get(categoryKeyboardMapKey);
}
}
@@ -348,4 +421,34 @@ final class EmojiCategory {
}
return retval;
}
+
+ private static boolean canShowFlagEmoji() {
+ Paint paint = new Paint();
+ String switzerland = "\uD83C\uDDE8\uD83C\uDDED"; // U+1F1E8 U+1F1ED Flag for Switzerland
+ try {
+ return paint.hasGlyph(switzerland);
+ } catch (NoSuchMethodError e) {
+ // Compare display width of single-codepoint emoji to width of flag emoji to determine
+ // whether flag is rendered as single glyph or two adjacent regional indicator symbols.
+ float flagWidth = paint.measureText(switzerland);
+ float standardWidth = paint.measureText("\uD83D\uDC27"); // U+1F427 Penguin
+ return flagWidth < standardWidth * 1.25;
+ // This assumes that a valid glyph for the flag emoji must be less than 1.25 times
+ // the width of the penguin.
+ }
+ }
+
+ private static boolean canShowUnicodeEightEmoji() {
+ Paint paint = new Paint();
+ String cheese = "\uD83E\uDDC0"; // U+1F9C0 Cheese wedge
+ try {
+ return paint.hasGlyph(cheese);
+ } catch (NoSuchMethodError e) {
+ float cheeseWidth = paint.measureText(cheese);
+ float tofuWidth = paint.measureText("\uFFFE");
+ return cheeseWidth > tofuWidth;
+ // This assumes that a valid glyph for the cheese wedge must be greater than the width
+ // of the noncharacter.
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
index 9b271116d..2529424c0 100644
--- a/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
+++ b/java/src/com/android/inputmethod/latin/EmojiAltPhysicalKeyDetector.java
@@ -16,92 +16,140 @@
package com.android.inputmethod.latin;
+import android.content.res.Resources;
import android.util.Log;
import android.view.KeyEvent;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.latin.settings.Settings;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
/**
* A class for detecting Emoji-Alt physical key.
*/
final class EmojiAltPhysicalKeyDetector {
private static final String TAG = "EmojiAltPhysicalKeyDetector";
- private final RichInputConnection mRichInputConnection;
+ private final Map<Integer, Integer> mEmojiSwitcherMap;
+ private final Map<Integer, Integer> mSymbolsShiftedSwitcherMap;
+ private final Map<Integer, Integer> mCombinedSwitcherMap;
- // True if the Alt key has been used as a modifier. In this case the Alt key up isn't
- // recognized as an emoji key.
- private boolean mAltHasBeenUsedAsAModifier;
+ // Set of keys codes that have been used as modifiers.
+ private Set<Integer> mActiveModifiers;
- public EmojiAltPhysicalKeyDetector(final RichInputConnection richInputConnection) {
- mRichInputConnection = richInputConnection;
+ public EmojiAltPhysicalKeyDetector(@Nonnull final Resources resources) {
+ mEmojiSwitcherMap = parseSwitchDefinition(resources, R.array.keyboard_switcher_emoji);
+ mSymbolsShiftedSwitcherMap = parseSwitchDefinition(
+ resources, R.array.keyboard_switcher_symbols_shifted);
+ mCombinedSwitcherMap = new HashMap<>();
+ mCombinedSwitcherMap.putAll(mEmojiSwitcherMap);
+ mCombinedSwitcherMap.putAll(mSymbolsShiftedSwitcherMap);
+ mActiveModifiers = new HashSet<>();
}
- /**
- * Record a down key event.
- * @param keyEvent a down key event.
- */
- public void onKeyDown(final KeyEvent keyEvent) {
- if (isAltKey(keyEvent)) {
- mAltHasBeenUsedAsAModifier = false;
- }
- if (containsAltModifier(keyEvent)) {
- mAltHasBeenUsedAsAModifier = true;
+ private static Map<Integer, Integer> parseSwitchDefinition(
+ @Nonnull final Resources resources,
+ final int resourceId) {
+ final Map<Integer, Integer> definition = new HashMap<>();
+ final String name = resources.getResourceEntryName(resourceId);
+ final String[] values = resources.getStringArray(resourceId);
+ for (int i = 0; values != null && i < values.length; i++) {
+ String[] valuePair = values[i].split(",");
+ if (valuePair.length != 2) {
+ Log.w(TAG, "Expected 2 integers in " + name + "[" + i + "] : " + values[i]);
+ }
+ try {
+ definition.put(Integer.parseInt(valuePair[0]), Integer.parseInt(valuePair[1]));
+ } catch (NumberFormatException e) {
+ Log.w(TAG, "Failed to parse " + name + "[" + i + "] : " + values[i], e);
+ }
}
+ return definition;
}
/**
- * Determine whether an up key event is a special key up or not.
+ * Determine whether an up key event came from a mapped modifier key.
+ *
* @param keyEvent an up key event.
*/
- public void onKeyUp(final KeyEvent keyEvent) {
- if (keyEvent.isCanceled()) {
- // This key up event was a part of key combinations and should be ignored.
+ public void onKeyUp(@Nonnull final KeyEvent keyEvent) {
+ Log.d(TAG, "onKeyUp() : " + keyEvent);
+ if (!Settings.getInstance().getCurrent().mEnableEmojiAltPhysicalKey) {
+ // The feature is disabled.
+ Log.d(TAG, "onKeyUp() : Disabled");
return;
}
- if (!isAltKey(keyEvent)) {
- mAltHasBeenUsedAsAModifier |= containsAltModifier(keyEvent);
+ if (keyEvent.isCanceled()) {
+ // This key up event was a part of key combinations and should be ignored.
+ Log.d(TAG, "onKeyUp() : Canceled");
return;
}
- if (containsAltModifier(keyEvent)) {
- mAltHasBeenUsedAsAModifier = true;
+ final Integer mappedModifier = getMappedModifier(keyEvent);
+ if (mappedModifier != null) {
+ // If the key was modified by a mapped key, then ignore the next time
+ // the same modifier key comes up.
+ Log.d(TAG, "onKeyUp() : Using Modifier: " + mappedModifier);
+ mActiveModifiers.add(mappedModifier);
return;
}
- if (!Settings.getInstance().getCurrent().mEnableEmojiAltPhysicalKey) {
+ final int keyCode = keyEvent.getKeyCode();
+ if (mActiveModifiers.contains(keyCode)) {
+ // Used as a modifier, not a standalone key press.
+ Log.d(TAG, "onKeyUp() : Used as Modifier: " + keyCode);
+ mActiveModifiers.remove(keyCode);
return;
}
- if (mAltHasBeenUsedAsAModifier) {
+ if (!isMappedKeyCode(keyEvent)) {
+ // Nothing special about this key.
+ Log.d(TAG, "onKeyUp() : Not Mapped: " + keyCode);
return;
}
- if (!mRichInputConnection.isConnected()) {
- Log.w(TAG, "onKeyUp() : No connection to text view");
- return;
+ final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
+ if (mEmojiSwitcherMap.keySet().contains(keyCode)) {
+ switcher.onToggleKeyboard(KeyboardSwitcher.KeyboardSwitchState.EMOJI);
+ } else if (mSymbolsShiftedSwitcherMap.keySet().contains(keyCode)) {
+ switcher.onToggleKeyboard(KeyboardSwitcher.KeyboardSwitchState.SYMBOLS_SHIFTED);
+ } else {
+ Log.w(TAG, "Cannot toggle on keyCode: " + keyCode);
}
- onEmojiAltKeyDetected();
}
- private static void onEmojiAltKeyDetected() {
- KeyboardSwitcher.getInstance().onToggleEmojiKeyboard();
+ /**
+ * @param keyEvent pressed key event
+ * @return true iff the user pressed a mapped modifier key.
+ */
+ private boolean isMappedKeyCode(@Nonnull final KeyEvent keyEvent) {
+ return mCombinedSwitcherMap.get(keyEvent.getKeyCode()) != null;
}
- private static boolean isAltKey(final KeyEvent keyEvent) {
+ /**
+ * @param keyEvent pressed key event
+ * @return the mapped modifier used with this key opress, if any.
+ */
+ private Integer getMappedModifier(@Nonnull final KeyEvent keyEvent) {
final int keyCode = keyEvent.getKeyCode();
- return keyCode == KeyEvent.KEYCODE_ALT_LEFT || keyCode == KeyEvent.KEYCODE_ALT_RIGHT;
- }
-
- private static boolean containsAltModifier(final KeyEvent keyEvent) {
final int metaState = keyEvent.getMetaState();
- // TODO: Support multiple keyboards. Take device id into account.
- switch (keyEvent.getKeyCode()) {
- case KeyEvent.KEYCODE_ALT_LEFT:
- // Return true if Left-Alt is pressed with Right-Alt pressed.
- return (metaState & KeyEvent.META_ALT_RIGHT_ON) != 0;
- case KeyEvent.KEYCODE_ALT_RIGHT:
- // Return true if Right-Alt is pressed with Left-Alt pressed.
- return (metaState & KeyEvent.META_ALT_LEFT_ON) != 0;
- default:
- return (metaState & (KeyEvent.META_ALT_LEFT_ON | KeyEvent.META_ALT_RIGHT_ON)) != 0;
+ for (int mappedKeyCode : mCombinedSwitcherMap.keySet()) {
+ if (keyCode == mappedKeyCode) {
+ Log.d(TAG, "getMappedModifier() : KeyCode = MappedKeyCode = " + mappedKeyCode);
+ continue;
+ }
+ final Integer mappedMeta = mCombinedSwitcherMap.get(mappedKeyCode);
+ if (mappedMeta == null || mappedMeta.intValue() == -1) {
+ continue;
+ }
+ if ((metaState & mappedMeta) != 0) {
+ Log.d(TAG, "getMappedModifier() : MetaState(" + metaState
+ + ") contains MappedMeta(" + mappedMeta + ")");
+ return mappedKeyCode;
+ }
}
+ return null;
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 1f2b6f25d..25a5de250 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -142,8 +142,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private RichInputMethodManager mRichImm;
@UsedForTesting final KeyboardSwitcher mKeyboardSwitcher;
private final SubtypeState mSubtypeState = new SubtypeState();
- private final EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector =
- new EmojiAltPhysicalKeyDetector(mInputLogic.mConnection);
+ private EmojiAltPhysicalKeyDetector mEmojiAltPhysicalKeyDetector;
private StatsUtilsManager mStatsUtilsManager;
// Working variable for {@link #startShowingInputView()} and
// {@link #onEvaluateInputViewShown()}.
@@ -702,6 +701,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mInputLogic.recycle();
}
+ private boolean isImeSuppressedByHardwareKeyboard() {
+ final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
+ return switcher.isImeSuppressedByHardwareKeyboard(
+ mSettings.getCurrent(), switcher.getKeyboardSwitchState());
+ }
+
@Override
public void onConfigurationChanged(final Configuration conf) {
SettingsValues settingsValues = mSettings.getCurrent();
@@ -716,7 +721,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// have a change in hardware keyboard configuration.
loadSettings();
settingsValues = mSettings.getCurrent();
- if (settingsValues.mHasHardwareKeyboard) {
+ if (isImeSuppressedByHardwareKeyboard()) {
// We call cleanupInternalStateForFinishInput() because it's the right thing to do;
// however, it seems at the moment the framework is passing us a seemingly valid
// but actually non-functional InputConnection object. So if this bug ever gets
@@ -874,7 +879,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// can go into the correct mode, so we need to do some housekeeping here.
final boolean needToCallLoadKeyboardLater;
final Suggest suggest = mInputLogic.mSuggest;
- if (!currentSettingsValues.mHasHardwareKeyboard) {
+ if (!isImeSuppressedByHardwareKeyboard()) {
// The app calling setText() has the effect of clearing the composing
// span, so we should reset our state unconditionally, even if restarting is true.
// We also tell the input logic about the combining rules for the current subtype, so
@@ -1118,8 +1123,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return;
}
final int inputHeight = mInputView.getHeight();
- final boolean hasHardwareKeyboard = settingsValues.mHasHardwareKeyboard;
- if (hasHardwareKeyboard && visibleKeyboardView.getVisibility() == View.GONE) {
+ if (isImeSuppressedByHardwareKeyboard() && !visibleKeyboardView.isShown()) {
// If there is a hardware keyboard and a visible software keyboard view has been hidden,
// no visual element will be shown on the screen.
outInsets.contentTopInsets = inputHeight;
@@ -1165,7 +1169,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public boolean onShowInputRequested(final int flags, final boolean configChange) {
- if (Settings.getInstance().getCurrent().mHasHardwareKeyboard) {
+ if (isImeSuppressedByHardwareKeyboard()) {
return true;
}
return super.onShowInputRequested(flags, configChange);
@@ -1182,7 +1186,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public boolean onEvaluateFullscreenMode() {
final SettingsValues settingsValues = mSettings.getCurrent();
- if (settingsValues.mHasHardwareKeyboard) {
+ if (isImeSuppressedByHardwareKeyboard()) {
// If there is a hardware keyboard, disable full screen mode.
return false;
}
@@ -1646,8 +1650,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// Hooks for hardware keyboard
@Override
public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
- // TODO: This should be processed in {@link InputLogic}.
- mEmojiAltPhysicalKeyDetector.onKeyDown(keyEvent);
if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) {
return super.onKeyDown(keyCode, keyEvent);
}
@@ -1668,7 +1670,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override
public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) {
- // TODO: This should be processed in {@link InputLogic}.
+ if (mEmojiAltPhysicalKeyDetector == null) {
+ mEmojiAltPhysicalKeyDetector = new EmojiAltPhysicalKeyDetector(
+ getApplicationContext().getResources());
+ }
mEmojiAltPhysicalKeyDetector.onKeyUp(keyEvent);
if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) {
return super.onKeyUp(keyCode, keyEvent);