Merge "Use DynamicGridKeyboard for EmojiPager"
commit
cdc2ce8c89
|
@ -22,6 +22,7 @@ import android.content.Context;
|
||||||
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.os.Build;
|
import android.os.Build;
|
||||||
import android.support.v4.view.PagerAdapter;
|
import android.support.v4.view.PagerAdapter;
|
||||||
import android.support.v4.view.ViewPager;
|
import android.support.v4.view.ViewPager;
|
||||||
|
@ -37,7 +38,9 @@ import android.widget.TabHost;
|
||||||
import android.widget.TabHost.OnTabChangeListener;
|
import android.widget.TabHost.OnTabChangeListener;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.inputmethod.keyboard.internal.CodesArrayParser;
|
||||||
import com.android.inputmethod.keyboard.internal.DynamicGridKeyboard;
|
import com.android.inputmethod.keyboard.internal.DynamicGridKeyboard;
|
||||||
|
import com.android.inputmethod.keyboard.internal.KeyboardParams;
|
||||||
import com.android.inputmethod.keyboard.internal.ScrollKeyboardView;
|
import com.android.inputmethod.keyboard.internal.ScrollKeyboardView;
|
||||||
import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier;
|
import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier;
|
||||||
import com.android.inputmethod.latin.Constants;
|
import com.android.inputmethod.latin.Constants;
|
||||||
|
@ -47,7 +50,10 @@ import com.android.inputmethod.latin.utils.CollectionUtils;
|
||||||
import com.android.inputmethod.latin.utils.ResourceUtils;
|
import com.android.inputmethod.latin.utils.ResourceUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View class to implement Emoji keyboards.
|
* View class to implement Emoji keyboards.
|
||||||
|
@ -75,8 +81,6 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
|
|
||||||
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
|
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
|
||||||
|
|
||||||
private static class EmojiCategory {
|
|
||||||
private int mCurrentCategory = CATEGORY_UNSPECIFIED;
|
|
||||||
private static final int CATEGORY_UNSPECIFIED = -1;
|
private static final int CATEGORY_UNSPECIFIED = -1;
|
||||||
private static final int CATEGORY_RECENTS = 0;
|
private static final int CATEGORY_RECENTS = 0;
|
||||||
private static final int CATEGORY_PEOPLE = 1;
|
private static final int CATEGORY_PEOPLE = 1;
|
||||||
|
@ -85,6 +89,9 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
private static final int CATEGORY_PLACES = 4;
|
private static final int CATEGORY_PLACES = 4;
|
||||||
private static final int CATEGORY_SYMBOLS = 5;
|
private static final int CATEGORY_SYMBOLS = 5;
|
||||||
private static final int CATEGORY_EMOTICONS = 6;
|
private static final int CATEGORY_EMOTICONS = 6;
|
||||||
|
|
||||||
|
private static class EmojiCategory {
|
||||||
|
private static final int DEFAULT_MAX_ROW_SIZE = 3;
|
||||||
private static final String[] sCategoryName = {
|
private static final String[] sCategoryName = {
|
||||||
"recents",
|
"recents",
|
||||||
"people",
|
"people",
|
||||||
|
@ -111,10 +118,18 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
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 Resources mRes;
|
||||||
|
private final KeyboardLayoutSet mLayoutSet;
|
||||||
private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
|
private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
|
||||||
private final ArrayList<Integer> mShownCategories = new ArrayList<Integer>();
|
private final ArrayList<Integer> mShownCategories = new ArrayList<Integer>();
|
||||||
|
private final ConcurrentHashMap<Long, DynamicGridKeyboard>
|
||||||
|
mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>();
|
||||||
|
|
||||||
public EmojiCategory() {
|
private int mCurrentCategory = CATEGORY_UNSPECIFIED;
|
||||||
|
|
||||||
|
public EmojiCategory(final Resources res, final KeyboardLayoutSet layoutSet) {
|
||||||
|
mRes = res;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
@ -185,12 +200,71 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
return mShownCategories.get(tabId);
|
return mShownCategories.get(tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getElementIdFromTabId(int tabId) {
|
public DynamicGridKeyboard getKeyboard(int category, int id) {
|
||||||
return sCategoryElementId[getCategoryFromTabId(tabId)];
|
synchronized(mCategoryKeyboardMap) {
|
||||||
|
final long key = (((long) category) << 32) | id;
|
||||||
|
final DynamicGridKeyboard kbd;
|
||||||
|
if (!mCategoryKeyboardMap.containsKey(key)) {
|
||||||
|
if (category != CATEGORY_RECENTS) {
|
||||||
|
kbd = new DynamicGridKeyboard(
|
||||||
|
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
|
||||||
|
DEFAULT_MAX_ROW_SIZE);
|
||||||
|
final Keyboard keyboard =
|
||||||
|
mLayoutSet.getKeyboard(sCategoryElementId[category]);
|
||||||
|
// TODO: Calculate maxPageCount dynamically
|
||||||
|
final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), 21);
|
||||||
|
for (Key emojiKey : sortedKeys[0]) {
|
||||||
|
if (emojiKey == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kbd.addKeyLast(emojiKey);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
kbd = new DynamicGridKeyboard(
|
||||||
|
mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
|
||||||
|
DEFAULT_MAX_ROW_SIZE);
|
||||||
|
}
|
||||||
|
mCategoryKeyboardMap.put(key, kbd);
|
||||||
|
} else {
|
||||||
|
kbd = mCategoryKeyboardMap.get(key);
|
||||||
|
}
|
||||||
|
return kbd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final EmojiCategory mEmojiCategory = new EmojiCategory();
|
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;
|
||||||
|
|
||||||
public EmojiKeyboardView(final Context context, final AttributeSet attrs) {
|
public EmojiKeyboardView(final Context context, final AttributeSet attrs) {
|
||||||
this(context, attrs, R.attr.emojiKeyboardViewStyle);
|
this(context, attrs, R.attr.emojiKeyboardViewStyle);
|
||||||
|
@ -219,6 +293,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
+ res.getDimensionPixelSize(R.dimen.suggestions_strip_height));
|
+ res.getDimensionPixelSize(R.dimen.suggestions_strip_height));
|
||||||
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());
|
||||||
// TODO: Save/restore recent keys from/to preferences.
|
// TODO: Save/restore recent keys from/to preferences.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,15 +463,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
mEmojiCategory = emojiCategory;
|
mEmojiCategory = emojiCategory;
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
mLayoutSet = layoutSet;
|
mLayoutSet = layoutSet;
|
||||||
mRecentsKeyboard = new DynamicGridKeyboard(
|
mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_RECENTS, 0);
|
||||||
layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addRecentKey(final Key key) {
|
public void addRecentKey(final Key key) {
|
||||||
if (mEmojiCategory.isInRecentTab()) {
|
if (mEmojiCategory.isInRecentTab()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mRecentsKeyboard.addRecentKey(key);
|
mRecentsKeyboard.addKeyFirst(key);
|
||||||
final KeyboardView recentKeyboardView =
|
final KeyboardView recentKeyboardView =
|
||||||
mActiveKeyboardView.get(mEmojiCategory.getRecentTabId());
|
mActiveKeyboardView.get(mEmojiCategory.getRecentTabId());
|
||||||
if (recentKeyboardView != null) {
|
if (recentKeyboardView != null) {
|
||||||
|
@ -424,9 +498,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object instantiateItem(final ViewGroup container, final int position) {
|
public Object instantiateItem(final ViewGroup container, final int position) {
|
||||||
final int elementId = mEmojiCategory.getElementIdFromTabId(position);
|
final Keyboard keyboard =
|
||||||
final Keyboard keyboard = (elementId == KeyboardId.ELEMENT_EMOJI_RECENTS)
|
mEmojiCategory.getKeyboard(mEmojiCategory.getCategoryFromTabId(position), 0);
|
||||||
? mRecentsKeyboard : mLayoutSet.getKeyboard(elementId);
|
|
||||||
final LayoutInflater inflater = LayoutInflater.from(container.getContext());
|
final LayoutInflater inflater = LayoutInflater.from(container.getContext());
|
||||||
final View view = inflater.inflate(
|
final View view = inflater.inflate(
|
||||||
R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
|
R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
|
||||||
|
|
|
@ -23,7 +23,6 @@ import com.android.inputmethod.keyboard.Keyboard;
|
||||||
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.Random;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -37,12 +36,12 @@ public class DynamicGridKeyboard extends Keyboard {
|
||||||
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 mMaxRecentKeyCount;
|
private final int mMaxKeyCount;
|
||||||
private final ArrayDeque<RecentKey> mRecentKeys = CollectionUtils.newArrayDeque();
|
private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
|
||||||
|
|
||||||
private Key[] mCachedRecentKeys;
|
private Key[] mCachedGridKeys;
|
||||||
|
|
||||||
public DynamicGridKeyboard(final Keyboard templateKeyboard) {
|
public DynamicGridKeyboard(final Keyboard templateKeyboard, final int maxRows) {
|
||||||
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,8 +49,7 @@ public class DynamicGridKeyboard extends Keyboard {
|
||||||
mHorizontalStep = Math.abs(key1.getX() - key0.getX());
|
mHorizontalStep = Math.abs(key1.getX() - key0.getX());
|
||||||
mVerticalStep = key0.getHeight() + mVerticalGap;
|
mVerticalStep = key0.getHeight() + mVerticalGap;
|
||||||
mColumnsNum = mBaseWidth / mHorizontalStep;
|
mColumnsNum = mBaseWidth / mHorizontalStep;
|
||||||
final int rowsNum = mBaseHeight / mVerticalStep;
|
mMaxKeyCount = mColumnsNum * maxRows;
|
||||||
mMaxRecentKeyCount = mColumnsNum * rowsNum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Key getTemplateKey(final int code) {
|
private Key getTemplateKey(final int code) {
|
||||||
|
@ -63,27 +61,34 @@ public class DynamicGridKeyboard extends Keyboard {
|
||||||
throw new RuntimeException("Can't find template key: code=" + code);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
public void addRecentKey(final Key usedKey) {
|
public void addKeyLast(final Key usedKey) {
|
||||||
synchronized (mRecentKeys) {
|
addKey(usedKey, false);
|
||||||
mCachedRecentKeys = null;
|
}
|
||||||
final RecentKey key = (usedKey instanceof RecentKey)
|
|
||||||
? (RecentKey)usedKey : new RecentKey(usedKey);
|
private void addKey(final Key usedKey, final boolean addFirst) {
|
||||||
while (mRecentKeys.remove(key)) {
|
synchronized (mGridKeys) {
|
||||||
|
mCachedGridKeys = null;
|
||||||
|
final GridKey key = new GridKey(usedKey);
|
||||||
|
while (mGridKeys.remove(key)) {
|
||||||
// Remove duplicate keys.
|
// Remove duplicate keys.
|
||||||
}
|
}
|
||||||
mRecentKeys.addFirst(key);
|
if (addFirst) {
|
||||||
while (mRecentKeys.size() > mMaxRecentKeyCount) {
|
mGridKeys.addFirst(key);
|
||||||
mRecentKeys.removeLast();
|
} else {
|
||||||
|
mGridKeys.addLast(key);
|
||||||
|
}
|
||||||
|
while (mGridKeys.size() > mMaxKeyCount) {
|
||||||
|
mGridKeys.removeLast();
|
||||||
}
|
}
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (final RecentKey recentKey : mRecentKeys) {
|
for (final GridKey gridKey : mGridKeys) {
|
||||||
final int keyX = getKeyX(index);
|
final int keyX = getKeyX(index);
|
||||||
final int keyY = getKeyY(index);
|
final int keyY = getKeyY(index);
|
||||||
final int x = keyX+random.nextInt(recentKey.getWidth());
|
gridKey.updateCorrdinates(keyX, keyY);
|
||||||
final int y = keyY+random.nextInt(recentKey.getHeight());
|
|
||||||
recentKey.updateCorrdinates(keyX, keyY);
|
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,26 +106,26 @@ public class DynamicGridKeyboard extends Keyboard {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key[] getKeys() {
|
public Key[] getKeys() {
|
||||||
synchronized (mRecentKeys) {
|
synchronized (mGridKeys) {
|
||||||
if (mCachedRecentKeys != null) {
|
if (mCachedGridKeys != null) {
|
||||||
return mCachedRecentKeys;
|
return mCachedGridKeys;
|
||||||
}
|
}
|
||||||
mCachedRecentKeys = mRecentKeys.toArray(new Key[mRecentKeys.size()]);
|
mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]);
|
||||||
return mCachedRecentKeys;
|
return mCachedGridKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Key[] getNearestKeys(final int x, final int y) {
|
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();
|
return getKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class RecentKey extends Key {
|
static final class GridKey extends Key {
|
||||||
private int mCurrentX;
|
private int mCurrentX;
|
||||||
private int mCurrentY;
|
private int mCurrentY;
|
||||||
|
|
||||||
public RecentKey(final Key originalKey) {
|
public GridKey(final Key originalKey) {
|
||||||
super(originalKey);
|
super(originalKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +156,7 @@ public class DynamicGridKeyboard extends Keyboard {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RecentKey: " + super.toString();
|
return "GridKey: " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue