am f3f00006: Save & restore emoji keyboard state

* commit 'f3f00006cbe2046abbad3a901b436d67497a40f9':
  Save & restore emoji keyboard state
main
Satoshi Kataoka 2013-09-16 07:14:15 -07:00 committed by Android Git Automerger
commit 4e3d778211
4 changed files with 173 additions and 93 deletions

View File

@ -19,11 +19,13 @@ package com.android.inputmethod.keyboard;
import static com.android.inputmethod.latin.Constants.NOT_A_COORDINATE; import static com.android.inputmethod.latin.Constants.NOT_A_COORDINATE;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -45,6 +47,7 @@ import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier;
import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher; 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.CollectionUtils;
import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.ResourceUtils;
@ -80,27 +83,25 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
private static final int CATEGORY_UNSPECIFIED = -1; private static final int CATEGORY_ID_UNSPECIFIED = -1;
private static final int CATEGORY_RECENTS = 0; public static final int CATEGORY_ID_RECENTS = 0;
private static final int CATEGORY_PEOPLE = 1; public static final int CATEGORY_ID_PEOPLE = 1;
private static final int CATEGORY_OBJECTS = 2; public static final int CATEGORY_ID_OBJECTS = 2;
private static final int CATEGORY_NATURE = 3; public static final int CATEGORY_ID_NATURE = 3;
private static final int CATEGORY_PLACES = 4; public static final int CATEGORY_ID_PLACES = 4;
private static final int CATEGORY_SYMBOLS = 5; public static final int CATEGORY_ID_SYMBOLS = 5;
private static final int CATEGORY_EMOTICONS = 6; public static final int CATEGORY_ID_EMOTICONS = 6;
private static class CategoryProperties { private static class CategoryProperties {
public int mCategory; public int mCategoryId;
public int mPageCount; public int mPageCount;
public CategoryProperties(final int category, final int pageCount) { public CategoryProperties(final int categoryId, final int pageCount) {
mCategory = category; mCategoryId = categoryId;
mPageCount = pageCount; mPageCount = pageCount;
} }
} }
private static class EmojiCategory { private static class EmojiCategory {
private static final int DEFAULT_PAGE_KEY_COUNT = 21;
private static final int DEFAULT_MAX_ROW_SIZE = 3;
private static final String[] sCategoryName = { private static final String[] sCategoryName = {
"recents", "recents",
"people", "people",
@ -126,8 +127,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
KeyboardId.ELEMENT_EMOJI_CATEGORY3, KeyboardId.ELEMENT_EMOJI_CATEGORY3,
KeyboardId.ELEMENT_EMOJI_CATEGORY4, KeyboardId.ELEMENT_EMOJI_CATEGORY4,
KeyboardId.ELEMENT_EMOJI_CATEGORY5, KeyboardId.ELEMENT_EMOJI_CATEGORY5,
KeyboardId.ELEMENT_EMOJI_CATEGORY6, }; KeyboardId.ELEMENT_EMOJI_CATEGORY6 };
private final Resources mRes; private final SharedPreferences mPrefs;
private final int mMaxPageKeyCount; private final int mMaxPageKeyCount;
private final KeyboardLayoutSet mLayoutSet; private final KeyboardLayoutSet mLayoutSet;
private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap(); private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
@ -136,41 +137,43 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
private final ConcurrentHashMap<Long, DynamicGridKeyboard> private final ConcurrentHashMap<Long, DynamicGridKeyboard>
mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>(); mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>();
private int mCurrentCategory = CATEGORY_UNSPECIFIED; private int mCurrentCategoryId = CATEGORY_ID_UNSPECIFIED;
private int mCurrentCategoryPageId = 0;
public EmojiCategory(final Resources res, final KeyboardLayoutSet layoutSet) { public EmojiCategory(final SharedPreferences prefs, final Resources res,
mRes = res; final KeyboardLayoutSet layoutSet) {
mPrefs = prefs;
mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count); mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count);
mLayoutSet = layoutSet; mLayoutSet = layoutSet;
for (int i = 0; i < sCategoryName.length; ++i) { for (int i = 0; i < sCategoryName.length; ++i) {
mCategoryNameToIdMap.put(sCategoryName[i], i); mCategoryNameToIdMap.put(sCategoryName[i], i);
} }
addShownCategory(CATEGORY_RECENTS); addShownCategoryId(CATEGORY_ID_RECENTS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
addShownCategory(CATEGORY_PEOPLE); addShownCategoryId(CATEGORY_ID_PEOPLE);
addShownCategory(CATEGORY_OBJECTS); addShownCategoryId(CATEGORY_ID_OBJECTS);
addShownCategory(CATEGORY_NATURE); addShownCategoryId(CATEGORY_ID_NATURE);
addShownCategory(CATEGORY_PLACES); addShownCategoryId(CATEGORY_ID_PLACES);
// TODO: Restore last saved category mCurrentCategoryId = CATEGORY_ID_PEOPLE;
mCurrentCategory = CATEGORY_PEOPLE;
} else { } else {
// TODO: Restore last saved category mCurrentCategoryId = CATEGORY_ID_SYMBOLS;
mCurrentCategory = CATEGORY_SYMBOLS;
} }
addShownCategory(CATEGORY_SYMBOLS); addShownCategoryId(CATEGORY_ID_SYMBOLS);
addShownCategory(CATEGORY_EMOTICONS); addShownCategoryId(CATEGORY_ID_EMOTICONS);
getKeyboard(CATEGORY_ID_RECENTS, 0 /* cagetoryPageId */)
.loadRecentKeys(mCategoryKeyboardMap.values());
} }
private void addShownCategory(int category) { private void addShownCategoryId(int categoryId) {
// Load a keyboard of category // Load a keyboard of categoryId
getKeyboard(category, 0); getKeyboard(categoryId, 0 /* cagetoryPageId */);
final CategoryProperties properties = final CategoryProperties properties =
new CategoryProperties(category, getCategoryPageCount(category)); new CategoryProperties(categoryId, getCategoryPageCount(categoryId));
mShownCategories.add(properties); mShownCategories.add(properties);
} }
public String getCategoryName(int category, int categoryPageId) { public String getCategoryName(int categoryId, int categoryPageId) {
return sCategoryName[category] + "-" + categoryPageId; return sCategoryName[categoryId] + "-" + categoryPageId;
} }
public int getCategoryId(String name) { public int getCategoryId(String name) {
@ -178,61 +181,71 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
return mCategoryNameToIdMap.get(strings[0]); return mCategoryNameToIdMap.get(strings[0]);
} }
public int getCategoryIcon(int category) { public int getCategoryIcon(int categoryId) {
return sCategoryIcon[category]; return sCategoryIcon[categoryId];
} }
public String getCategoryLabel(int category) { public String getCategoryLabel(int categoryId) {
return sCategoryLabel[category]; return sCategoryLabel[categoryId];
} }
public ArrayList<CategoryProperties> getShownCategories() { public ArrayList<CategoryProperties> getShownCategories() {
return mShownCategories; return mShownCategories;
} }
public int getCurrentCategory() { public int getCurrentCategoryId() {
// TODO: Record current category. return mCurrentCategoryId;
return mCurrentCategory;
} }
public void setCurrentCategory(int category) { public void setCurrentCategoryId(int categoryId) {
mCurrentCategory = category; mCurrentCategoryId = categoryId;
}
public void setCurrentCategoryPageId(int id) {
mCurrentCategoryPageId = id;
}
public void saveLastTypedCategoryPage() {
Settings.writeEmojiCategoryLastTypedId(
mPrefs, mCurrentCategoryId, mCurrentCategoryPageId);
} }
public boolean isInRecentTab() { 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) { for (int i = 0; i < mShownCategories.size(); ++i) {
if (mShownCategories.get(i).mCategory == category) { if (mShownCategories.get(i).mCategoryId == categoryId) {
return i; return i;
} }
} }
Log.w(TAG, "category not found: " + category); Log.w(TAG, "categoryId not found: " + categoryId);
return 0; return 0;
} }
// Returns the view pager's page position for the category // Returns the view pager's page position for the categoryId
public int getPageIdFromCategory(int category) { public int getPageIdFromCategoryId(int categoryId) {
final int lastSavedCategoryPageId =
Settings.readEmojiCategoryLastTypedId(mPrefs, categoryId);
int sum = 0; int sum = 0;
for (int i = 0; i < mShownCategories.size(); ++i) { for (int i = 0; i < mShownCategories.size(); ++i) {
final CategoryProperties props = mShownCategories.get(i); final CategoryProperties props = mShownCategories.get(i);
if (props.mCategory == category) { if (props.mCategoryId == categoryId) {
return sum; return sum + lastSavedCategoryPageId;
} }
sum += props.mPageCount; sum += props.mPageCount;
} }
Log.w(TAG, "category not found: " + category); Log.w(TAG, "categoryId not found: " + categoryId);
return 0; return 0;
} }
public int getRecentTabId() { public int getRecentTabId() {
return getTabIdFromCategory(CATEGORY_RECENTS); return getTabIdFromCategoryId(CATEGORY_ID_RECENTS);
} }
private int getCategoryPageCount(int category) { private int getCategoryPageCount(int categoryId) {
final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[category]); final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1; return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
} }
@ -246,7 +259,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final int temp = sum; final int temp = sum;
sum += properties.mPageCount; sum += properties.mPageCount;
if (sum > position) { if (sum > position) {
return new Pair<Integer, Integer>(properties.mCategory, position - temp); return new Pair<Integer, Integer>(properties.mCategoryId, position - temp);
} }
} }
return null; return null;
@ -262,33 +275,33 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
return null; return null;
} }
public DynamicGridKeyboard getKeyboard(int category, int id) { public DynamicGridKeyboard getKeyboard(int categoryId, int id) {
synchronized(mCategoryKeyboardMap) { synchronized(mCategoryKeyboardMap) {
final long key = (((long) category) << 32) | id; final long key = (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id;
final DynamicGridKeyboard kbd; final DynamicGridKeyboard kbd;
if (!mCategoryKeyboardMap.containsKey(key)) { if (!mCategoryKeyboardMap.containsKey(key)) {
if (category != CATEGORY_RECENTS) { if (categoryId != CATEGORY_ID_RECENTS) {
final Keyboard keyboard = final Keyboard keyboard =
mLayoutSet.getKeyboard(sCategoryElementId[category]); mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
// TODO: Calculate maxPageCount dynamically
final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), mMaxPageKeyCount); final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), mMaxPageKeyCount);
for (int i = 0; i < sortedKeys.length; ++i) { for (int i = 0; i < sortedKeys.length; ++i) {
final DynamicGridKeyboard tempKbd = new DynamicGridKeyboard( final DynamicGridKeyboard tempKbd = new DynamicGridKeyboard(mPrefs,
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
mMaxPageKeyCount); mMaxPageKeyCount, categoryId, i /* categoryPageId */);
for (Key emojiKey : sortedKeys[i]) { for (Key emojiKey : sortedKeys[i]) {
if (emojiKey == null) { if (emojiKey == null) {
break; break;
} }
tempKbd.addKeyLast(emojiKey); tempKbd.addKeyLast(emojiKey);
} }
mCategoryKeyboardMap.put((((long) category) << 32) | i, tempKbd); mCategoryKeyboardMap.put((((long) categoryId)
<< Constants.MAX_INT_BIT_COUNT) | i, tempKbd);
} }
kbd = mCategoryKeyboardMap.get(key); kbd = mCategoryKeyboardMap.get(key);
} else { } else {
kbd = new DynamicGridKeyboard( kbd = new DynamicGridKeyboard(mPrefs,
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
mMaxPageKeyCount); mMaxPageKeyCount, categoryId, 0 /* categoryPageId */);
mCategoryKeyboardMap.put(key, kbd); mCategoryKeyboardMap.put(key, kbd);
} }
} else { } else {
@ -367,8 +380,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
emojiLp.mEmojiKeyboardHeight); emojiLp.mEmojiKeyboardHeight);
builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */); builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */);
mLayoutSet = builder.build(); mLayoutSet = builder.build();
mEmojiCategory = new EmojiCategory(context.getResources(), builder.build()); mEmojiCategory = new EmojiCategory(PreferenceManager.getDefaultSharedPreferences(context),
// TODO: Save/restore recent keys from/to preferences. context.getResources(), builder.build());
} }
@Override @Override
@ -384,20 +397,20 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
setMeasuredDimension(width, height); setMeasuredDimension(width, height);
} }
private void addTab(final TabHost host, final int category) { private void addTab(final TabHost host, final int categoryId) {
final String tabId = mEmojiCategory.getCategoryName(category, 0 /* categoryPageId */); final String tabId = mEmojiCategory.getCategoryName(categoryId, 0 /* categoryPageId */);
final TabHost.TabSpec tspec = host.newTabSpec(tabId); final TabHost.TabSpec tspec = host.newTabSpec(tabId);
tspec.setContent(R.id.emoji_keyboard_dummy); 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( final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_icon, null); R.layout.emoji_keyboard_tab_icon, null);
iconView.setImageResource(mEmojiCategory.getCategoryIcon(category)); iconView.setImageResource(mEmojiCategory.getCategoryIcon(categoryId));
tspec.setIndicator(iconView); tspec.setIndicator(iconView);
} }
if (mEmojiCategory.getCategoryLabel(category) != null) { if (mEmojiCategory.getCategoryLabel(categoryId) != null) {
final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate( final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_label, null); R.layout.emoji_keyboard_tab_label, null);
textView.setText(mEmojiCategory.getCategoryLabel(category)); textView.setText(mEmojiCategory.getCategoryLabel(categoryId));
textView.setTextColor(mTabLabelColor); textView.setTextColor(mTabLabelColor);
tspec.setIndicator(textView); tspec.setIndicator(textView);
} }
@ -409,7 +422,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost); mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost);
mTabHost.setup(); mTabHost.setup();
for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) { for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) {
addTab(mTabHost, properties.mCategory); addTab(mTabHost, properties.mCategoryId);
} }
mTabHost.setOnTabChangedListener(this); mTabHost.setOnTabChangedListener(this);
mTabHost.getTabWidget().setStripEnabled(true); mTabHost.getTabWidget().setStripEnabled(true);
@ -424,7 +437,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res); final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
emojiLp.setPagerProps(mEmojiPager); emojiLp.setPagerProps(mEmojiPager);
setCurrentCategory(mEmojiCategory.getCurrentCategory(), true /* force */); setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true /* force */);
final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar); final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar);
emojiLp.setActionBarProps(actionBar); emojiLp.setActionBarProps(actionBar);
@ -451,15 +464,17 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override @Override
public void onTabChanged(final String tabId) { public void onTabChanged(final String tabId) {
final int category = mEmojiCategory.getCategoryId(tabId); final int categoryId = mEmojiCategory.getCategoryId(tabId);
setCurrentCategory(category, false /* force */); setCurrentCategoryId(categoryId, false /* force */);
} }
@Override @Override
public void onPageSelected(final int position) { public void onPageSelected(final int position) {
setCurrentCategory(mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position).first, final Pair<Integer, Integer> newPos =
false /* force */); mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position);
setCurrentCategoryId(newPos.first /* categoryId */, false /* force */);
mEmojiCategory.setCurrentCategoryPageId(newPos.second /* categoryPageId */);
} }
@Override @Override
@ -491,6 +506,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override @Override
public void onKeyClick(final Key key) { public void onKeyClick(final Key key) {
mEmojiKeyboardAdapter.addRecentKey(key); mEmojiKeyboardAdapter.addRecentKey(key);
mEmojiCategory.saveLastTypedCategoryPage();
final int code = key.getCode(); final int code = key.getCode();
if (code == Constants.CODE_OUTPUT_TEXT) { if (code == Constants.CODE_OUTPUT_TEXT) {
mKeyboardActionListener.onTextInput(key.getOutputText()); mKeyboardActionListener.onTextInput(key.getOutputText());
@ -507,27 +523,25 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
mKeyboardActionListener = listener; mKeyboardActionListener = listener;
} }
private void setCurrentCategory(final int category, final boolean force) { private void setCurrentCategoryId(final int categoryId, final boolean force) {
if (mEmojiCategory.getCurrentCategory() == category && !force) { if (mEmojiCategory.getCurrentCategoryId() == categoryId && !force) {
return; return;
} }
mEmojiCategory.setCurrentCategory(category); mEmojiCategory.setCurrentCategoryId(categoryId);
final int newTabId = mEmojiCategory.getTabIdFromCategory(category); final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId);
final int newCategoryPageId = mEmojiCategory.getPageIdFromCategory(category); final int newCategoryPageId = mEmojiCategory.getPageIdFromCategoryId(categoryId);
if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition( if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(
mEmojiPager.getCurrentItem()).first != category) { mEmojiPager.getCurrentItem()).first != categoryId) {
mEmojiPager.setCurrentItem(newCategoryPageId, true /* smoothScroll */); mEmojiPager.setCurrentItem(newCategoryPageId, true /* smoothScroll */);
} }
if (force || mTabHost.getCurrentTab() != newTabId) { if (force || mTabHost.getCurrentTab() != newTabId) {
mTabHost.setCurrentTab(newTabId); mTabHost.setCurrentTab(newTabId);
} }
// TODO: Record current category
} }
private static class EmojiKeyboardAdapter extends PagerAdapter { private static class EmojiKeyboardAdapter extends PagerAdapter {
private final ScrollKeyboardView.OnKeyClickListener mListener; private final ScrollKeyboardView.OnKeyClickListener mListener;
private final KeyboardLayoutSet mLayoutSet;
private final DynamicGridKeyboard mRecentsKeyboard; private final DynamicGridKeyboard mRecentsKeyboard;
private final SparseArray<ScrollKeyboardView> mActiveKeyboardView = private final SparseArray<ScrollKeyboardView> mActiveKeyboardView =
CollectionUtils.newSparseArray(); CollectionUtils.newSparseArray();
@ -539,8 +553,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final ScrollKeyboardView.OnKeyClickListener listener) { final ScrollKeyboardView.OnKeyClickListener listener) {
mEmojiCategory = emojiCategory; mEmojiCategory = emojiCategory;
mListener = listener; mListener = listener;
mLayoutSet = layoutSet; mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0);
mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_RECENTS, 0);
} }
public void addRecentKey(final Key key) { public void addRecentKey(final Key key) {

View File

@ -16,32 +16,41 @@
package com.android.inputmethod.keyboard.internal; package com.android.inputmethod.keyboard.internal;
import android.content.SharedPreferences;
import android.text.TextUtils; import android.text.TextUtils;
import com.android.inputmethod.keyboard.EmojiKeyboardView;
import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard; 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 com.android.inputmethod.latin.utils.CollectionUtils;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Collection;
/** /**
* This is a Keyboard class where you can add keys dynamically shown in a grid layout * 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 { public class DynamicGridKeyboard extends Keyboard {
private static final int TEMPLATE_KEY_CODE_0 = 0x30; private static final int TEMPLATE_KEY_CODE_0 = 0x30;
private static final int TEMPLATE_KEY_CODE_1 = 0x31; 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 mLeftPadding;
private final int mHorizontalStep; private final int mHorizontalStep;
private final int mVerticalStep; private final int mVerticalStep;
private final int mColumnsNum; private final int mColumnsNum;
private final int mMaxKeyCount; private final int mMaxKeyCount;
private final boolean mIsRecents;
private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque(); private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
private Key[] mCachedGridKeys; private Key[] mCachedGridKeys;
public DynamicGridKeyboard(final Keyboard templateKeyboard, final int maxKeyCount) { public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard,
final int maxKeyCount, final int categoryId, final int categoryPageId) {
super(templateKeyboard); super(templateKeyboard);
final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0); final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1); final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
@ -50,6 +59,8 @@ public class DynamicGridKeyboard extends Keyboard {
mVerticalStep = key0.getHeight() + mVerticalGap; mVerticalStep = key0.getHeight() + mVerticalGap;
mColumnsNum = mBaseWidth / mHorizontalStep; mColumnsNum = mBaseWidth / mHorizontalStep;
mMaxKeyCount = maxKeyCount; mMaxKeyCount = maxKeyCount;
mIsRecents = categoryId == EmojiKeyboardView.CATEGORY_ID_RECENTS;
mPrefs = prefs;
} }
private Key getTemplateKey(final int code) { private Key getTemplateKey(final int code) {
@ -63,6 +74,9 @@ public class DynamicGridKeyboard extends Keyboard {
public void addKeyFirst(final Key usedKey) { public void addKeyFirst(final Key usedKey) {
addKey(usedKey, true); addKey(usedKey, true);
if (mIsRecents) {
saveRecentKeys();
}
} }
public void addKeyLast(final Key usedKey) { public void addKeyLast(final Key usedKey) {
@ -94,6 +108,31 @@ public class DynamicGridKeyboard extends Keyboard {
} }
} }
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) { private int getKeyX(final int index) {
final int column = index % mColumnsNum; final int column = index % mColumnsNum;
return column * mHorizontalStep + mLeftPadding; return column * mHorizontalStep + mLeftPadding;

View File

@ -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() { private Constants() {
// This utility class is not publicly instantiable. // This utility class is not publicly instantiable.
} }
} }

View File

@ -97,6 +97,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SEND_FEEDBACK = "send_feedback"; public static final String PREF_SEND_FEEDBACK = "send_feedback";
public static final String PREF_ABOUT_KEYBOARD = "about_keyboard"; 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 Resources mRes;
private SharedPreferences mPrefs; private SharedPreferences mPrefs;
private SettingsValues mSettingsValues; private SettingsValues mSettingsValues;
@ -363,4 +367,24 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
final String tokenStr = mPrefs.getString(PREF_LAST_USED_PERSONALIZATION_TOKEN, null); final String tokenStr = mPrefs.getString(PREF_LAST_USED_PERSONALIZATION_TOKEN, null);
return StringUtils.hexStringToByteArray(tokenStr); 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);
}
} }