aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java319
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java106
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java80
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java4
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java24
6 files changed, 430 insertions, 113 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
index 9996a6d6a..d28b5088c 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
@@ -19,14 +19,18 @@ package com.android.inputmethod.keyboard;
import static com.android.inputmethod.latin.Constants.NOT_A_COORDINATE;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.os.Build;
+import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -43,11 +47,15 @@ import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
+import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* View class to implement Emoji keyboards.
@@ -75,16 +83,25 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
+ private static final int CATEGORY_ID_UNSPECIFIED = -1;
+ public static final int CATEGORY_ID_RECENTS = 0;
+ public static final int CATEGORY_ID_PEOPLE = 1;
+ public static final int CATEGORY_ID_OBJECTS = 2;
+ public static final int CATEGORY_ID_NATURE = 3;
+ public static final int CATEGORY_ID_PLACES = 4;
+ public static final int CATEGORY_ID_SYMBOLS = 5;
+ public static final int CATEGORY_ID_EMOTICONS = 6;
+
+ private static class CategoryProperties {
+ public int mCategoryId;
+ public int mPageCount;
+ public CategoryProperties(final int categoryId, final int pageCount) {
+ mCategoryId = categoryId;
+ mPageCount = pageCount;
+ }
+ }
+
private static class EmojiCategory {
- private int mCurrentCategory = CATEGORY_UNSPECIFIED;
- private static final int CATEGORY_UNSPECIFIED = -1;
- private static final int CATEGORY_RECENTS = 0;
- private static final int CATEGORY_PEOPLE = 1;
- private static final int CATEGORY_OBJECTS = 2;
- private static final int CATEGORY_NATURE = 3;
- private static final int CATEGORY_PLACES = 4;
- private static final int CATEGORY_SYMBOLS = 5;
- private static final int CATEGORY_EMOTICONS = 6;
private static final String[] sCategoryName = {
"recents",
"people",
@@ -110,87 +127,231 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
KeyboardId.ELEMENT_EMOJI_CATEGORY3,
KeyboardId.ELEMENT_EMOJI_CATEGORY4,
KeyboardId.ELEMENT_EMOJI_CATEGORY5,
- KeyboardId.ELEMENT_EMOJI_CATEGORY6, };
+ KeyboardId.ELEMENT_EMOJI_CATEGORY6 };
+ private final SharedPreferences mPrefs;
+ private final int mMaxPageKeyCount;
+ private final KeyboardLayoutSet mLayoutSet;
private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
- private final ArrayList<Integer> mShownCategories = new ArrayList<Integer>();
-
- public EmojiCategory() {
+ private final ArrayList<CategoryProperties> mShownCategories =
+ CollectionUtils.newArrayList();
+ private final ConcurrentHashMap<Long, DynamicGridKeyboard>
+ mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>();
+
+ private int mCurrentCategoryId = CATEGORY_ID_UNSPECIFIED;
+ private int mCurrentCategoryPageId = 0;
+
+ public EmojiCategory(final SharedPreferences prefs, final Resources res,
+ final KeyboardLayoutSet layoutSet) {
+ mPrefs = prefs;
+ mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count);
+ mLayoutSet = layoutSet;
for (int i = 0; i < sCategoryName.length; ++i) {
mCategoryNameToIdMap.put(sCategoryName[i], i);
}
- mShownCategories.add(CATEGORY_RECENTS);
+ addShownCategoryId(CATEGORY_ID_RECENTS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- mShownCategories.add(CATEGORY_PEOPLE);
- mShownCategories.add(CATEGORY_OBJECTS);
- mShownCategories.add(CATEGORY_NATURE);
- mShownCategories.add(CATEGORY_PLACES);
- // TODO: Restore last saved category
- mCurrentCategory = CATEGORY_PEOPLE;
+ addShownCategoryId(CATEGORY_ID_PEOPLE);
+ addShownCategoryId(CATEGORY_ID_OBJECTS);
+ addShownCategoryId(CATEGORY_ID_NATURE);
+ addShownCategoryId(CATEGORY_ID_PLACES);
+ mCurrentCategoryId = CATEGORY_ID_PEOPLE;
} else {
- // TODO: Restore last saved category
- mCurrentCategory = CATEGORY_SYMBOLS;
+ mCurrentCategoryId = CATEGORY_ID_SYMBOLS;
}
- mShownCategories.add(CATEGORY_SYMBOLS);
- mShownCategories.add(CATEGORY_EMOTICONS);
+ addShownCategoryId(CATEGORY_ID_SYMBOLS);
+ addShownCategoryId(CATEGORY_ID_EMOTICONS);
+ getKeyboard(CATEGORY_ID_RECENTS, 0 /* cagetoryPageId */)
+ .loadRecentKeys(mCategoryKeyboardMap.values());
+ }
+
+ private void addShownCategoryId(int categoryId) {
+ // Load a keyboard of categoryId
+ getKeyboard(categoryId, 0 /* cagetoryPageId */);
+ final CategoryProperties properties =
+ new CategoryProperties(categoryId, getCategoryPageCount(categoryId));
+ mShownCategories.add(properties);
}
- public String getCategoryName(int category) {
- return sCategoryName[category];
+ public String getCategoryName(int categoryId, int categoryPageId) {
+ return sCategoryName[categoryId] + "-" + categoryPageId;
}
public int getCategoryId(String name) {
- return mCategoryNameToIdMap.get(name);
+ final String[] strings = name.split("-");
+ return mCategoryNameToIdMap.get(strings[0]);
}
- public int getCategoryIcon(int category) {
- return sCategoryIcon[category];
+ public int getCategoryIcon(int categoryId) {
+ return sCategoryIcon[categoryId];
}
- public String getCategoryLabel(int category) {
- return sCategoryLabel[category];
+ public String getCategoryLabel(int categoryId) {
+ return sCategoryLabel[categoryId];
}
- public ArrayList<Integer> getShownCategories() {
+ public ArrayList<CategoryProperties> getShownCategories() {
return mShownCategories;
}
- public int getCurrentCategory() {
- // TODO: Record current category.
- return mCurrentCategory;
+ public int getCurrentCategoryId() {
+ return mCurrentCategoryId;
+ }
+
+ public void setCurrentCategoryId(int categoryId) {
+ mCurrentCategoryId = categoryId;
}
- public void setCurrentCategory(int category) {
- mCurrentCategory = category;
+ public void setCurrentCategoryPageId(int id) {
+ mCurrentCategoryPageId = id;
+ }
+
+ public void saveLastTypedCategoryPage() {
+ Settings.writeEmojiCategoryLastTypedId(
+ mPrefs, mCurrentCategoryId, mCurrentCategoryPageId);
}
public boolean isInRecentTab() {
- return mCurrentCategory == CATEGORY_RECENTS;
+ return mCurrentCategoryId == CATEGORY_ID_RECENTS;
}
- public int getTabIdFromCategory(int category) {
+ public int getTabIdFromCategoryId(int categoryId) {
for (int i = 0; i < mShownCategories.size(); ++i) {
- if (mShownCategories.get(i) == category) {
+ if (mShownCategories.get(i).mCategoryId == categoryId) {
return i;
}
}
- Log.w(TAG, "category not found: " + category);
+ Log.w(TAG, "categoryId not found: " + categoryId);
+ return 0;
+ }
+
+ // Returns the view pager's page position for the categoryId
+ public int getPageIdFromCategoryId(int categoryId) {
+ final int lastSavedCategoryPageId =
+ Settings.readEmojiCategoryLastTypedId(mPrefs, categoryId);
+ int sum = 0;
+ for (int i = 0; i < mShownCategories.size(); ++i) {
+ final CategoryProperties props = mShownCategories.get(i);
+ if (props.mCategoryId == categoryId) {
+ return sum + lastSavedCategoryPageId;
+ }
+ sum += props.mPageCount;
+ }
+ Log.w(TAG, "categoryId not found: " + categoryId);
return 0;
}
public int getRecentTabId() {
- return getTabIdFromCategory(CATEGORY_RECENTS);
+ return getTabIdFromCategoryId(CATEGORY_ID_RECENTS);
}
- public int getCategoryFromTabId(int tabId) {
- return mShownCategories.get(tabId);
+ private int getCategoryPageCount(int categoryId) {
+ final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
+ return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
}
- public int getElementIdFromTabId(int tabId) {
- return sCategoryElementId[getCategoryFromTabId(tabId)];
+ // Returns a pair of the category id and the category page id from the view pager's page
+ // position. The category page id is numbered in each category. And the view page position
+ // is the position of the current shown page in the view pager which contains all pages of
+ // all categories.
+ public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(int position) {
+ int sum = 0;
+ for (CategoryProperties properties : mShownCategories) {
+ final int temp = sum;
+ sum += properties.mPageCount;
+ if (sum > position) {
+ return new Pair<Integer, Integer>(properties.mCategoryId, position - temp);
+ }
+ }
+ return null;
+ }
+
+ // Returns a keyboard from the view pager's page position.
+ public DynamicGridKeyboard getKeyboardFromPagePosition(int position) {
+ final Pair<Integer, Integer> categoryAndId =
+ getCategoryIdAndPageIdFromPagePosition(position);
+ if (categoryAndId != null) {
+ return getKeyboard(categoryAndId.first, categoryAndId.second);
+ }
+ return null;
+ }
+
+ public DynamicGridKeyboard getKeyboard(int categoryId, int id) {
+ synchronized(mCategoryKeyboardMap) {
+ final long key = (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id;
+ final DynamicGridKeyboard kbd;
+ if (!mCategoryKeyboardMap.containsKey(key)) {
+ if (categoryId != CATEGORY_ID_RECENTS) {
+ final Keyboard keyboard =
+ mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
+ final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), mMaxPageKeyCount);
+ for (int i = 0; i < sortedKeys.length; ++i) {
+ final DynamicGridKeyboard tempKbd = new DynamicGridKeyboard(mPrefs,
+ mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
+ mMaxPageKeyCount, categoryId, i /* categoryPageId */);
+ for (Key emojiKey : sortedKeys[i]) {
+ if (emojiKey == null) {
+ break;
+ }
+ tempKbd.addKeyLast(emojiKey);
+ }
+ mCategoryKeyboardMap.put((((long) categoryId)
+ << Constants.MAX_INT_BIT_COUNT) | i, tempKbd);
+ }
+ kbd = mCategoryKeyboardMap.get(key);
+ } else {
+ kbd = new DynamicGridKeyboard(mPrefs,
+ mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
+ mMaxPageKeyCount, categoryId, 0 /* categoryPageId */);
+ mCategoryKeyboardMap.put(key, kbd);
+ }
+ } else {
+ kbd = mCategoryKeyboardMap.get(key);
+ }
+ return kbd;
+ }
+ }
+
+ public int getTotalPageCountOfAllCategories() {
+ int sum = 0;
+ for (CategoryProperties properties : mShownCategories) {
+ sum += properties.mPageCount;
+ }
+ return sum;
+ }
+
+ private Key[][] sortKeys(Key[] inKeys, int maxPageCount) {
+ Key[] keys = Arrays.copyOf(inKeys, inKeys.length);
+ Arrays.sort(keys, 0, keys.length, new Comparator<Key>() {
+ @Override
+ public int compare(Key lhs, Key rhs) {
+ final Rect lHitBox = lhs.getHitBox();
+ final Rect rHitBox = rhs.getHitBox();
+ if (lHitBox.top < rHitBox.top) {
+ return -1;
+ } else if (lHitBox.top > rHitBox.top) {
+ return 1;
+ }
+ if (lHitBox.left < rHitBox.left) {
+ return -1;
+ } else if (lHitBox.left > rHitBox.left) {
+ return 1;
+ }
+ if (lhs.getCode() == rhs.getCode()) {
+ return 0;
+ }
+ return lhs.getCode() < rhs.getCode() ? -1 : 1;
+ }
+ });
+ final int pageCount = (keys.length - 1) / maxPageCount + 1;
+ final Key[][] retval = new Key[pageCount][maxPageCount];
+ for (int i = 0; i < keys.length; ++i) {
+ retval[i / maxPageCount][i % maxPageCount] = keys[i];
+ }
+ return retval;
}
}
- private final EmojiCategory mEmojiCategory = new EmojiCategory();
+ private final EmojiCategory mEmojiCategory;
public EmojiKeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.emojiKeyboardViewStyle);
@@ -213,13 +374,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
context, null /* editorInfo */);
final Resources res = context.getResources();
+ final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
builder.setSubtype(SubtypeSwitcher.getInstance().getEmojiSubtype());
builder.setKeyboardGeometry(ResourceUtils.getDefaultKeyboardWidth(res),
- (int)ResourceUtils.getDefaultKeyboardHeight(res)
- + res.getDimensionPixelSize(R.dimen.suggestions_strip_height));
+ emojiLp.mEmojiKeyboardHeight);
builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */);
mLayoutSet = builder.build();
- // TODO: Save/restore recent keys from/to preferences.
+ mEmojiCategory = new EmojiCategory(PreferenceManager.getDefaultSharedPreferences(context),
+ context.getResources(), builder.build());
}
@Override
@@ -235,20 +397,20 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
setMeasuredDimension(width, height);
}
- private void addTab(final TabHost host, final int category) {
- final String tabId = mEmojiCategory.getCategoryName(category);
+ private void addTab(final TabHost host, final int categoryId) {
+ final String tabId = mEmojiCategory.getCategoryName(categoryId, 0 /* categoryPageId */);
final TabHost.TabSpec tspec = host.newTabSpec(tabId);
tspec.setContent(R.id.emoji_keyboard_dummy);
- if (mEmojiCategory.getCategoryIcon(category) != 0) {
+ if (mEmojiCategory.getCategoryIcon(categoryId) != 0) {
final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_icon, null);
- iconView.setImageResource(mEmojiCategory.getCategoryIcon(category));
+ iconView.setImageResource(mEmojiCategory.getCategoryIcon(categoryId));
tspec.setIndicator(iconView);
}
- if (mEmojiCategory.getCategoryLabel(category) != null) {
+ if (mEmojiCategory.getCategoryLabel(categoryId) != null) {
final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_label, null);
- textView.setText(mEmojiCategory.getCategoryLabel(category));
+ textView.setText(mEmojiCategory.getCategoryLabel(categoryId));
textView.setTextColor(mTabLabelColor);
tspec.setIndicator(textView);
}
@@ -259,8 +421,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
protected void onFinishInflate() {
mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost);
mTabHost.setup();
- for (final int i : mEmojiCategory.getShownCategories()) {
- addTab(mTabHost, i);
+ for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) {
+ addTab(mTabHost, properties.mCategoryId);
}
mTabHost.setOnTabChangedListener(this);
mTabHost.getTabWidget().setStripEnabled(true);
@@ -275,7 +437,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
emojiLp.setPagerProps(mEmojiPager);
- setCurrentCategory(mEmojiCategory.getCurrentCategory(), true /* force */);
+ setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true /* force */);
final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar);
emojiLp.setActionBarProps(actionBar);
@@ -302,14 +464,17 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public void onTabChanged(final String tabId) {
- final int category = mEmojiCategory.getCategoryId(tabId);
- setCurrentCategory(category, false /* force */);
+ final int categoryId = mEmojiCategory.getCategoryId(tabId);
+ setCurrentCategoryId(categoryId, false /* force */);
}
@Override
public void onPageSelected(final int position) {
- setCurrentCategory(mEmojiCategory.getCategoryFromTabId(position), false /* force */);
+ final Pair<Integer, Integer> newPos =
+ mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position);
+ setCurrentCategoryId(newPos.first /* categoryId */, false /* force */);
+ mEmojiCategory.setCurrentCategoryPageId(newPos.second /* categoryPageId */);
}
@Override
@@ -341,6 +506,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public void onKeyClick(final Key key) {
mEmojiKeyboardAdapter.addRecentKey(key);
+ mEmojiCategory.saveLastTypedCategoryPage();
final int code = key.getCode();
if (code == Constants.CODE_OUTPUT_TEXT) {
mKeyboardActionListener.onTextInput(key.getOutputText());
@@ -357,25 +523,25 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
mKeyboardActionListener = listener;
}
- private void setCurrentCategory(final int category, final boolean force) {
- if (mEmojiCategory.getCurrentCategory() == category && !force) {
+ private void setCurrentCategoryId(final int categoryId, final boolean force) {
+ if (mEmojiCategory.getCurrentCategoryId() == categoryId && !force) {
return;
}
- mEmojiCategory.setCurrentCategory(category);
- final int newTabId = mEmojiCategory.getTabIdFromCategory(category);
- if (force || mEmojiPager.getCurrentItem() != newTabId) {
- mEmojiPager.setCurrentItem(newTabId, true /* smoothScroll */);
+ mEmojiCategory.setCurrentCategoryId(categoryId);
+ final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId);
+ final int newCategoryPageId = mEmojiCategory.getPageIdFromCategoryId(categoryId);
+ if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(
+ mEmojiPager.getCurrentItem()).first != categoryId) {
+ mEmojiPager.setCurrentItem(newCategoryPageId, true /* smoothScroll */);
}
if (force || mTabHost.getCurrentTab() != newTabId) {
mTabHost.setCurrentTab(newTabId);
}
- // TODO: Record current category
}
private static class EmojiKeyboardAdapter extends PagerAdapter {
private final ScrollKeyboardView.OnKeyClickListener mListener;
- private final KeyboardLayoutSet mLayoutSet;
private final DynamicGridKeyboard mRecentsKeyboard;
private final SparseArray<ScrollKeyboardView> mActiveKeyboardView =
CollectionUtils.newSparseArray();
@@ -387,16 +553,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final ScrollKeyboardView.OnKeyClickListener listener) {
mEmojiCategory = emojiCategory;
mListener = listener;
- mLayoutSet = layoutSet;
- mRecentsKeyboard = new DynamicGridKeyboard(
- layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS));
+ mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0);
}
public void addRecentKey(final Key key) {
if (mEmojiCategory.isInRecentTab()) {
return;
}
- mRecentsKeyboard.addRecentKey(key);
+ mRecentsKeyboard.addKeyFirst(key);
final KeyboardView recentKeyboardView =
mActiveKeyboardView.get(mEmojiCategory.getRecentTabId());
if (recentKeyboardView != null) {
@@ -406,7 +570,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public int getCount() {
- return mEmojiCategory.getShownCategories().size();
+ return mEmojiCategory.getTotalPageCountOfAllCategories();
}
@Override
@@ -424,9 +588,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public Object instantiateItem(final ViewGroup container, final int position) {
- final int elementId = mEmojiCategory.getElementIdFromTabId(position);
- final Keyboard keyboard = (elementId == KeyboardId.ELEMENT_EMOJI_RECENTS)
- ? mRecentsKeyboard : mLayoutSet.getKeyboard(elementId);
+ final Keyboard keyboard =
+ mEmojiCategory.getKeyboardFromPagePosition(position);
final LayoutInflater inflater = LayoutInflater.from(container.getContext());
final View view = inflater.inflate(
R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
index 6486fc9db..5570d594d 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
@@ -27,6 +27,8 @@ import android.widget.LinearLayout;
public class EmojiLayoutParams {
private static final int DEFAULT_KEYBOARD_ROWS = 4;
+ public final int mEmojiPagerHeight;
+ private final int mEmojiPagerBottomMargin;
public final int mEmojiKeyboardHeight;
public final int mEmojiActionBarHeight;
public final int mKeyVerticalGap;
@@ -49,13 +51,15 @@ public class EmojiLayoutParams {
+ mKeyVerticalGap;
mEmojiActionBarHeight = ((int) baseheight) / DEFAULT_KEYBOARD_ROWS
- (mKeyVerticalGap - mBottomPadding) / 2;
- mEmojiKeyboardHeight = defaultKeyboardHeight - mEmojiActionBarHeight;
+ mEmojiPagerHeight = defaultKeyboardHeight - mEmojiActionBarHeight;
+ mEmojiPagerBottomMargin = mKeyVerticalGap / 2;
+ mEmojiKeyboardHeight = mEmojiPagerHeight - mEmojiPagerBottomMargin - 1;
}
public void setPagerProps(ViewPager vp) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vp.getLayoutParams();
- lp.height = mEmojiKeyboardHeight - mKeyVerticalGap / 2;
- lp.bottomMargin = mKeyVerticalGap / 2;
+ lp.height = mEmojiPagerHeight - mEmojiPagerBottomMargin;
+ lp.bottomMargin = mEmojiPagerBottomMargin;
vp.setLayoutParams(lp);
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index a226891b4..f203eb7d7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -16,33 +16,41 @@
package com.android.inputmethod.keyboard.internal;
+import android.content.SharedPreferences;
import android.text.TextUtils;
+import com.android.inputmethod.keyboard.EmojiKeyboardView;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.util.ArrayDeque;
-import java.util.Random;
+import java.util.Collection;
/**
* This is a Keyboard class where you can add keys dynamically shown in a grid layout
*/
-// TODO: Save/restore recent keys from/to preferences.
public class DynamicGridKeyboard extends Keyboard {
private static final int TEMPLATE_KEY_CODE_0 = 0x30;
private static final int TEMPLATE_KEY_CODE_1 = 0x31;
+ // Recent codes are saved as an integer array, so we use comma as a separater.
+ private static final String RECENT_KEY_SEPARATOR = Constants.STRING_COMMA;
+ private final SharedPreferences mPrefs;
private final int mLeftPadding;
private final int mHorizontalStep;
private final int mVerticalStep;
private final int mColumnsNum;
- private final int mMaxRecentKeyCount;
- private final ArrayDeque<RecentKey> mRecentKeys = CollectionUtils.newArrayDeque();
+ private final int mMaxKeyCount;
+ private final boolean mIsRecents;
+ private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
- private Key[] mCachedRecentKeys;
+ private Key[] mCachedGridKeys;
- public DynamicGridKeyboard(final Keyboard templateKeyboard) {
+ public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard,
+ final int maxKeyCount, final int categoryId, final int categoryPageId) {
super(templateKeyboard);
final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
@@ -50,8 +58,9 @@ public class DynamicGridKeyboard extends Keyboard {
mHorizontalStep = Math.abs(key1.getX() - key0.getX());
mVerticalStep = key0.getHeight() + mVerticalGap;
mColumnsNum = mBaseWidth / mHorizontalStep;
- final int rowsNum = mBaseHeight / mVerticalStep;
- mMaxRecentKeyCount = mColumnsNum * rowsNum;
+ mMaxKeyCount = maxKeyCount;
+ mIsRecents = categoryId == EmojiKeyboardView.CATEGORY_ID_RECENTS;
+ mPrefs = prefs;
}
private Key getTemplateKey(final int code) {
@@ -63,32 +72,67 @@ public class DynamicGridKeyboard extends Keyboard {
throw new RuntimeException("Can't find template key: code=" + code);
}
- private final Random random = new Random();
+ public void addKeyFirst(final Key usedKey) {
+ addKey(usedKey, true);
+ if (mIsRecents) {
+ saveRecentKeys();
+ }
+ }
+
+ public void addKeyLast(final Key usedKey) {
+ addKey(usedKey, false);
+ }
- public void addRecentKey(final Key usedKey) {
- synchronized (mRecentKeys) {
- mCachedRecentKeys = null;
- final RecentKey key = (usedKey instanceof RecentKey)
- ? (RecentKey)usedKey : new RecentKey(usedKey);
- while (mRecentKeys.remove(key)) {
+ private void addKey(final Key usedKey, final boolean addFirst) {
+ synchronized (mGridKeys) {
+ mCachedGridKeys = null;
+ final GridKey key = new GridKey(usedKey);
+ while (mGridKeys.remove(key)) {
// Remove duplicate keys.
}
- mRecentKeys.addFirst(key);
- while (mRecentKeys.size() > mMaxRecentKeyCount) {
- mRecentKeys.removeLast();
+ if (addFirst) {
+ mGridKeys.addFirst(key);
+ } else {
+ mGridKeys.addLast(key);
+ }
+ while (mGridKeys.size() > mMaxKeyCount) {
+ mGridKeys.removeLast();
}
int index = 0;
- for (final RecentKey recentKey : mRecentKeys) {
+ for (final GridKey gridKey : mGridKeys) {
final int keyX = getKeyX(index);
final int keyY = getKeyY(index);
- final int x = keyX+random.nextInt(recentKey.getWidth());
- final int y = keyY+random.nextInt(recentKey.getHeight());
- recentKey.updateCorrdinates(keyX, keyY);
+ gridKey.updateCorrdinates(keyX, keyY);
index++;
}
}
}
+ private void saveRecentKeys() {
+ final StringBuilder sb = new StringBuilder();
+ for (final Key key : mGridKeys) {
+ sb.append(key.getCode()).append(RECENT_KEY_SEPARATOR);
+ }
+ Settings.writeEmojiRecentKeys(mPrefs, sb.toString());
+ }
+
+ public void loadRecentKeys(Collection<DynamicGridKeyboard> keyboards) {
+ final String str = Settings.readEmojiRecentKeys(mPrefs);
+ for (String s : str.split(RECENT_KEY_SEPARATOR)) {
+ if (TextUtils.isEmpty(s)) {
+ continue;
+ }
+ final int code = Integer.valueOf(s);
+ for (DynamicGridKeyboard kbd : keyboards) {
+ final Key key = kbd.getKey(code);
+ if (key != null) {
+ addKeyLast(key);
+ break;
+ }
+ }
+ }
+ }
+
private int getKeyX(final int index) {
final int column = index % mColumnsNum;
return column * mHorizontalStep + mLeftPadding;
@@ -101,26 +145,26 @@ public class DynamicGridKeyboard extends Keyboard {
@Override
public Key[] getKeys() {
- synchronized (mRecentKeys) {
- if (mCachedRecentKeys != null) {
- return mCachedRecentKeys;
+ synchronized (mGridKeys) {
+ if (mCachedGridKeys != null) {
+ return mCachedGridKeys;
}
- mCachedRecentKeys = mRecentKeys.toArray(new Key[mRecentKeys.size()]);
- return mCachedRecentKeys;
+ mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]);
+ return mCachedGridKeys;
}
}
@Override
public Key[] getNearestKeys(final int x, final int y) {
- // TODO: Calculate the nearest key index in mRecentKeys from x and y.
+ // TODO: Calculate the nearest key index in mGridKeys from x and y.
return getKeys();
}
- static final class RecentKey extends Key {
+ static final class GridKey extends Key {
private int mCurrentX;
private int mCurrentY;
- public RecentKey(final Key originalKey) {
+ public GridKey(final Key originalKey) {
super(originalKey);
}
@@ -151,7 +195,7 @@ public class DynamicGridKeyboard extends Keyboard {
@Override
public String toString() {
- return "RecentKey: " + super.toString();
+ return "GridKey: " + super.toString();
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 7008b0619..a72595f7c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -383,7 +383,7 @@ public final class KeyboardTextsSet {
// Label for "switch to more symbol" modifier key. Must be short to fit on key!
/* 124 */ "= \\ <",
// Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key!
- /* 125 */ "~ [ {",
+ /* 125 */ "~ [ <",
// Label for "Tab" key. Must be short to fit on key!
/* 126 */ "Tab",
// Label for "switch to phone numeric" key. Must be short to fit on key!
@@ -2056,6 +2056,25 @@ public final class KeyboardTextsSet {
/* 45 */ "\u0410\u0411\u0412",
};
+ /* Language lo: Lao */
+ private static final String[] LANGUAGE_lo = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
+ // Label for "switch to alphabetic" key.
+ // U+0E81: "ກ" LAO LETTER KO
+ // U+0E82: "ຂ" LAO LETTER KHO SUNG
+ // U+0E84: "ຄ" LAO LETTER KHO TAM
+ /* 45 */ "\u0E81\u0E82\u0E84",
+ /* 46~ */
+ null, null, null, null, null,
+ /* ~50 */
+ // U+20AD: "₭" KIP SIGN
+ /* 51 */ "\u20AD",
+ };
+
/* Language lt: Lithuanian */
private static final String[] LANGUAGE_lt = {
// U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
@@ -2347,6 +2366,63 @@ public final class KeyboardTextsSet {
/* 47 */ "!text/double_9qm_rqm",
};
+ /* Language ne: Nepali */
+ private static final String[] LANGUAGE_ne = {
+ /* 0~ */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
+ // Label for "switch to alphabetic" key.
+ // U+0915: "क" DEVANAGARI LETTER KA
+ // U+0916: "ख" DEVANAGARI LETTER KHA
+ // U+0917: "ग" DEVANAGARI LETTER GA
+ /* 45 */ "\u0915\u0916\u0917",
+ /* 46~ */
+ null, null, null, null, null,
+ /* ~50 */
+ // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
+ /* 51 */ "\u0930\u0941.",
+ /* 52~ */
+ null, null, null, null, null, null, null, null, null, null, null,
+ /* ~62 */
+ // U+0967: "१" DEVANAGARI DIGIT ONE
+ /* 63 */ "\u0967",
+ // U+0968: "२" DEVANAGARI DIGIT TWO
+ /* 64 */ "\u0968",
+ // U+0969: "३" DEVANAGARI DIGIT THREE
+ /* 65 */ "\u0969",
+ // U+096A: "४" DEVANAGARI DIGIT FOUR
+ /* 66 */ "\u096A",
+ // U+096B: "५" DEVANAGARI DIGIT FIVE
+ /* 67 */ "\u096B",
+ // U+096C: "६" DEVANAGARI DIGIT SIX
+ /* 68 */ "\u096C",
+ // U+096D: "७" DEVANAGARI DIGIT SEVEN
+ /* 69 */ "\u096D",
+ // U+096E: "८" DEVANAGARI DIGIT EIGHT
+ /* 70 */ "\u096E",
+ // U+096F: "९" DEVANAGARI DIGIT NINE
+ /* 71 */ "\u096F",
+ // U+0966: "०" DEVANAGARI DIGIT ZERO
+ /* 72 */ "\u0966",
+ // Label for "switch to symbols" key.
+ /* 73 */ "?\u0967\u0968\u0969",
+ // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ // part because it'll be appended by the code.
+ /* 74 */ "\u0967\u0968\u0969",
+ /* 75 */ "1",
+ /* 76 */ "2",
+ /* 77 */ "3",
+ /* 78 */ "4",
+ /* 79 */ "5",
+ /* 80 */ "6",
+ /* 81 */ "7",
+ /* 82 */ "8",
+ /* 83 */ "9",
+ /* 84 */ "0",
+ };
+
/* Language nl: Dutch */
private static final String[] LANGUAGE_nl = {
// U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
@@ -3332,11 +3408,13 @@ public final class KeyboardTextsSet {
"ka", LANGUAGE_ka, /* Georgian */
"kk", LANGUAGE_kk, /* Kazakh */
"ky", LANGUAGE_ky, /* Kirghiz */
+ "lo", LANGUAGE_lo, /* Lao */
"lt", LANGUAGE_lt, /* Lithuanian */
"lv", LANGUAGE_lv, /* Latvian */
"mk", LANGUAGE_mk, /* Macedonian */
"mn", LANGUAGE_mn, /* Mongolian */
"nb", LANGUAGE_nb, /* Norwegian Bokmål */
+ "ne", LANGUAGE_ne, /* Nepali */
"nl", LANGUAGE_nl, /* Dutch */
"pl", LANGUAGE_pl, /* Polish */
"pt", LANGUAGE_pt, /* Portuguese */
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 8aec03f71..029ba02ed 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -220,7 +220,11 @@ public final class Constants {
}
}
+ public static final int MAX_INT_BIT_COUNT = 32;
+ public static final String STRING_COMMA = ",";
+
private Constants() {
// This utility class is not publicly instantiable.
}
+
}
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 686c8d5f5..1a0fecc62 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -98,6 +98,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SEND_FEEDBACK = "send_feedback";
public static final String PREF_ABOUT_KEYBOARD = "about_keyboard";
+ // Emoji
+ public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
+ public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";
+
private Resources mRes;
private SharedPreferences mPrefs;
private SettingsValues mSettingsValues;
@@ -370,4 +374,24 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
final String tokenStr = mPrefs.getString(PREF_LAST_USED_PERSONALIZATION_TOKEN, null);
return StringUtils.hexStringToByteArray(tokenStr);
}
+
+ public static void writeEmojiRecentKeys(final SharedPreferences prefs, String str) {
+ prefs.edit().putString(PREF_EMOJI_RECENT_KEYS, str).apply();
+ }
+
+ public static String readEmojiRecentKeys(final SharedPreferences prefs) {
+ return prefs.getString(PREF_EMOJI_RECENT_KEYS, "");
+ }
+
+ public static void writeEmojiCategoryLastTypedId(
+ final SharedPreferences prefs, final int category, final int id) {
+ final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+ prefs.edit().putInt(key, id).apply();
+ }
+
+ public static int readEmojiCategoryLastTypedId(
+ final SharedPreferences prefs, final int category) {
+ final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+ return prefs.getInt(key, 0);
+ }
}