Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cdc2ce8c authored by Satoshi Kataoka's avatar Satoshi Kataoka Committed by Android (Google) Code Review
Browse files

Merge "Use DynamicGridKeyboard for EmojiPager"

parents 505b6ba1 b0bf7e72
Loading
Loading
Loading
Loading
+92 −19
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Context;
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.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
@@ -37,7 +38,9 @@ import android.widget.TabHost;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TextView;

import com.android.inputmethod.keyboard.internal.CodesArrayParser;
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.ScrollViewWithNotifier;
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 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,8 +81,6 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange

    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_RECENTS = 0;
    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_SYMBOLS = 5;
    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 = {
                "recents",
                "people",
@@ -111,10 +118,18 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
                KeyboardId.ELEMENT_EMOJI_CATEGORY4,
                KeyboardId.ELEMENT_EMOJI_CATEGORY5,
                KeyboardId.ELEMENT_EMOJI_CATEGORY6, };
        private Resources mRes;
        private final KeyboardLayoutSet mLayoutSet;
        private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
        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) {
                mCategoryNameToIdMap.put(sCategoryName[i], i);
            }
@@ -185,12 +200,71 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
            return mShownCategories.get(tabId);
        }

        public int getElementIdFromTabId(int tabId) {
            return sCategoryElementId[getCategoryFromTabId(tabId)];
        public DynamicGridKeyboard getKeyboard(int category, int id) {
            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 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);
@@ -219,6 +293,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
                        + res.getDimensionPixelSize(R.dimen.suggestions_strip_height));
        builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */);
        mLayoutSet = builder.build();
        mEmojiCategory = new EmojiCategory(context.getResources(), builder.build());
        // TODO: Save/restore recent keys from/to preferences.
    }

@@ -388,15 +463,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
            mEmojiCategory = emojiCategory;
            mListener = listener;
            mLayoutSet = layoutSet;
            mRecentsKeyboard = new DynamicGridKeyboard(
                    layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS));
            mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_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) {
@@ -424,9 +498,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.getKeyboard(mEmojiCategory.getCategoryFromTabId(position), 0);
            final LayoutInflater inflater = LayoutInflater.from(container.getContext());
            final View view = inflater.inflate(
                    R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
+35 −30
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.utils.CollectionUtils;

import java.util.ArrayDeque;
import java.util.Random;

/**
 * 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 mVerticalStep;
    private final int mColumnsNum;
    private final int mMaxRecentKeyCount;
    private final ArrayDeque<RecentKey> mRecentKeys = CollectionUtils.newArrayDeque();
    private final int mMaxKeyCount;
    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);
        final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
        final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
@@ -50,8 +49,7 @@ 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 = mColumnsNum * maxRows;
    }

    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);
    }

    private final Random random = new Random();
    public void addKeyFirst(final Key usedKey) {
        addKey(usedKey, true);
    }

    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++;
            }
        }
@@ -101,26 +106,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 +156,7 @@ public class DynamicGridKeyboard extends Keyboard {

        @Override
        public String toString() {
            return "RecentKey: " + super.toString();
            return "GridKey: " + super.toString();
        }
    }
}