18ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka/* 28ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * Copyright (C) 2013 The Android Open Source Project 38ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * 48ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 58ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * you may not use this file except in compliance with the License. 68ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * You may obtain a copy of the License at 78ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * 88ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 98ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * 108ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 118ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 128ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * See the License for the specific language governing permissions and 148ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * limitations under the License. 158ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka */ 168ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 179f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokapackage com.android.inputmethod.keyboard.emoji; 188ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 199342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport static com.android.inputmethod.latin.common.Constants.NOT_A_COORDINATE; 208ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 218ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.content.Context; 228ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.content.res.Resources; 238ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.content.res.TypedArray; 2400ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovicimport android.graphics.Color; 25f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataokaimport android.preference.PreferenceManager; 268ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.support.v4.view.ViewPager; 278ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.util.AttributeSet; 285dfbc8af2439152ca6b6759309aced5bb879b518Satoshi Kataokaimport android.util.Pair; 29fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaokaimport android.util.TypedValue; 308ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.view.LayoutInflater; 319204d11525b26be49fc6a4bc6f785d326b1b5984Satoshi Kataokaimport android.view.MotionEvent; 328ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.view.View; 33c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaokaimport android.widget.ImageButton; 348ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.widget.ImageView; 358ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.widget.LinearLayout; 368ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.widget.TabHost; 378ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.widget.TabHost.OnTabChangeListener; 382782f9792708148e4481aa41912239500825d819Tadashi G. Takaokaimport android.widget.TabWidget; 398ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport android.widget.TextView; 408ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 419f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.Key; 429f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 439f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardLayoutSet; 449f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 45d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyDrawParams; 46d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyVisualAttributes; 47c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 48874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaokaimport com.android.inputmethod.latin.AudioAndHapticFeedbackManager; 498ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport com.android.inputmethod.latin.R; 502a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaokaimport com.android.inputmethod.latin.RichInputMethodSubtype; 519342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants; 528ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaokaimport com.android.inputmethod.latin.utils.ResourceUtils; 538ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 548ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka/** 55d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka * View class to implement Emoji palettes. 5627ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka * The Emoji keyboard consists of group of views layout/emoji_palettes_view. 578ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * <ol> 588ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * <li> Emoji category tabs. 598ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * <li> Delete button. 608ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * <li> Emoji keyboard pages that can be scrolled by swiping horizontally or by selecting a tab. 618ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * <li> Back to main keyboard button and enter button. 628ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * </ol> 638ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka * Because of the above reasons, this class doesn't extend {@link KeyboardView}. 648ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka */ 65d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataokapublic final class EmojiPalettesView extends LinearLayout implements OnTabChangeListener, 660e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa ViewPager.OnPageChangeListener, View.OnClickListener, View.OnTouchListener, 67df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa EmojiPageKeyboardView.OnKeyEventListener { 68c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka private final int mFunctionalKeyBackgroundId; 69c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka private final int mSpacebarBackgroundId; 702782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka private final boolean mCategoryIndicatorEnabled; 712782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka private final int mCategoryIndicatorDrawableResId; 722782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka private final int mCategoryIndicatorBackgroundResId; 732782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka private final int mCategoryPageIndicatorColor; 742782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka private final int mCategoryPageIndicatorBackground; 75d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka private EmojiPalettesAdapter mEmojiPalettesAdapter; 762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa private final EmojiLayoutParams mEmojiLayoutParams; 7700ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener; 788ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 79c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka private ImageButton mDeleteKey; 80fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka private TextView mAlphabetKeyLeft; 81fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka private TextView mAlphabetKeyRight; 823558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka private View mSpacebar; 833558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka // TODO: Remove this workaround. 843558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka private View mSpacebarIcon; 858ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka private TabHost mTabHost; 868ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka private ViewPager mEmojiPager; 87f981fe7ed23b269676a95f953728d74f82f68e4bSatoshi Kataoka private int mCurrentPagerPosition = 0; 88250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka private EmojiCategoryPageIndicatorView mEmojiCategoryPageIndicatorView; 898ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 908ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; 918ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 92b0bf7e729b5a3ec6dc481d72f04d7dad0e12672aSatoshi Kataoka private final EmojiCategory mEmojiCategory; 938ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 94d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka public EmojiPalettesView(final Context context, final AttributeSet attrs) { 95d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka this(context, attrs, R.attr.emojiPalettesViewStyle); 968ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 978ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 98d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka public EmojiPalettesView(final Context context, final AttributeSet attrs, final int defStyle) { 998ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka super(context, attrs, defStyle); 1008ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs, 1018ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka R.styleable.KeyboardView, defStyle, R.style.KeyboardView); 102c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka final int keyBackgroundId = keyboardViewAttr.getResourceId( 1038ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka R.styleable.KeyboardView_keyBackground, 0); 104c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka mFunctionalKeyBackgroundId = keyboardViewAttr.getResourceId( 105c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka R.styleable.KeyboardView_functionalKeyBackground, keyBackgroundId); 106c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka mSpacebarBackgroundId = keyboardViewAttr.getResourceId( 107c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka R.styleable.KeyboardView_spacebarBackground, keyBackgroundId); 1088ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka keyboardViewAttr.recycle(); 1098ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder( 1108ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka context, null /* editorInfo */); 1118ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final Resources res = context.getResources(); 1122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mEmojiLayoutParams = new EmojiLayoutParams(res); 1132a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka builder.setSubtype(RichInputMethodSubtype.getEmojiSubtype()); 114be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka builder.setKeyboardGeometry(ResourceUtils.getDefaultKeyboardWidth(res), 115be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka mEmojiLayoutParams.mEmojiKeyboardHeight); 11627ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka final KeyboardLayoutSet layoutSet = builder.build(); 11727ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka final TypedArray emojiPalettesViewAttr = context.obtainStyledAttributes(attrs, 11827ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.styleable.EmojiPalettesView, defStyle, R.style.EmojiPalettesView); 119f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka mEmojiCategory = new EmojiCategory(PreferenceManager.getDefaultSharedPreferences(context), 12027ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka res, layoutSet, emojiPalettesViewAttr); 1212782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mCategoryIndicatorEnabled = emojiPalettesViewAttr.getBoolean( 1222782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka R.styleable.EmojiPalettesView_categoryIndicatorEnabled, false); 1232782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mCategoryIndicatorDrawableResId = emojiPalettesViewAttr.getResourceId( 1242782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka R.styleable.EmojiPalettesView_categoryIndicatorDrawable, 0); 1252782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mCategoryIndicatorBackgroundResId = emojiPalettesViewAttr.getResourceId( 1262782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka R.styleable.EmojiPalettesView_categoryIndicatorBackground, 0); 1272782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mCategoryPageIndicatorColor = emojiPalettesViewAttr.getColor( 1282782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0); 1292782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mCategoryPageIndicatorBackground = emojiPalettesViewAttr.getColor( 1302782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka R.styleable.EmojiPalettesView_categoryPageIndicatorBackground, 0); 13127ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka emojiPalettesViewAttr.recycle(); 13200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(); 1338ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 1348ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 1358ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 1368ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { 1378ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka super.onMeasure(widthMeasureSpec, heightMeasureSpec); 1388ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final Resources res = getContext().getResources(); 1398ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka // The main keyboard expands to the entire this {@link KeyboardView}. 140be819dbe2b7a5c418530a2fa1182766a4d31d6d5Tadashi G. Takaoka final int width = ResourceUtils.getDefaultKeyboardWidth(res) 1418ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka + getPaddingLeft() + getPaddingRight(); 1428ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final int height = ResourceUtils.getDefaultKeyboardHeight(res) 1432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa + res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height) 1448ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka + getPaddingTop() + getPaddingBottom(); 1458ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka setMeasuredDimension(width, height); 1468ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 1478ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 148f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka private void addTab(final TabHost host, final int categoryId) { 1495f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka final String tabId = EmojiCategory.getCategoryName(categoryId, 0 /* categoryPageId */); 1508ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final TabHost.TabSpec tspec = host.newTabSpec(tabId); 1518ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka tspec.setContent(R.id.emoji_keyboard_dummy); 15227ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate( 15327ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka R.layout.emoji_keyboard_tab_icon, null); 15460835872a15992e239cf9bd038b6ee33b405f1d3Chieu Nguyen // TODO: Replace background color with its own setting rather than using the 15560835872a15992e239cf9bd038b6ee33b405f1d3Chieu Nguyen // category page indicator background as a workaround. 15660835872a15992e239cf9bd038b6ee33b405f1d3Chieu Nguyen iconView.setBackgroundColor(mCategoryPageIndicatorBackground); 15727ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka iconView.setImageResource(mEmojiCategory.getCategoryTabIcon(categoryId)); 15827ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka iconView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId)); 15927ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka tspec.setIndicator(iconView); 1608ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka host.addTab(tspec); 1618ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 1628ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 1638ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 1648ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka protected void onFinishInflate() { 1658ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost); 1668ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mTabHost.setup(); 167ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka for (final EmojiCategory.CategoryProperties properties 168ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka : mEmojiCategory.getShownCategories()) { 169f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka addTab(mTabHost, properties.mCategoryId); 17036ccb030ed1c19669116f0bb17d57b3b204fbf04Satoshi Kataoka } 1718ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mTabHost.setOnTabChangedListener(this); 1722782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka final TabWidget tabWidget = mTabHost.getTabWidget(); 1732782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka tabWidget.setStripEnabled(mCategoryIndicatorEnabled); 1742782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka if (mCategoryIndicatorEnabled) { 1752782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka // On TabWidget's strip, what looks like an indicator is actually a background. 1762782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka // And what looks like a background are actually left and right drawables. 1772782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka tabWidget.setBackgroundResource(mCategoryIndicatorDrawableResId); 1782782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka tabWidget.setLeftStripDrawable(mCategoryIndicatorBackgroundResId); 1792782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka tabWidget.setRightStripDrawable(mCategoryIndicatorBackgroundResId); 1802782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka } 1818ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 1822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, this); 183dd072e32014935da120fab855a0d5c07541c51c3Satoshi Kataoka 1848ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mEmojiPager = (ViewPager)findViewById(R.id.emoji_keyboard_pager); 185d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka mEmojiPager.setAdapter(mEmojiPalettesAdapter); 1868ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mEmojiPager.setOnPageChangeListener(this); 1878ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mEmojiPager.setOffscreenPageLimit(0); 1882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mEmojiPager.setPersistentDrawingCache(PERSISTENT_NO_CACHE); 1892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mEmojiLayoutParams.setPagerProperties(mEmojiPager); 190250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka 191250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategoryPageIndicatorView = 192250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka (EmojiCategoryPageIndicatorView)findViewById(R.id.emoji_category_page_id_view); 1932782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mEmojiCategoryPageIndicatorView.setColors( 1942782f9792708148e4481aa41912239500825d819Tadashi G. Takaoka mCategoryPageIndicatorColor, mCategoryPageIndicatorBackground); 1952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView); 1968ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 197f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true /* force */); 1988ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 1992d3d415826fab9e8ebde0f752f4fb1508bb307daSatoshi Kataoka final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar); 2002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa mEmojiLayoutParams.setActionBarProperties(actionBar); 2012d3d415826fab9e8ebde0f752f4fb1508bb307daSatoshi Kataoka 2020e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa // deleteKey depends only on OnTouchListener. 203c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mDeleteKey = (ImageButton)findViewById(R.id.emoji_keyboard_delete); 204c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mDeleteKey.setBackgroundResource(mFunctionalKeyBackgroundId); 205c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mDeleteKey.setTag(Constants.CODE_DELETE); 20600ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mDeleteKey.setOnTouchListener(mDeleteKeyOnTouchListener); 2070e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa 208fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // {@link #mAlphabetKeyLeft}, {@link #mAlphabetKeyRight, and spaceKey depend on 209fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // {@link View.OnClickListener} as well as {@link View.OnTouchListener}. 210fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // {@link View.OnTouchListener} is used as the trigger of key-press, while 211fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // {@link View.OnClickListener} is used as the trigger of key-release which does not occur 212fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // if the event is canceled by moving off the finger from the view. 213fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // The text on alphabet keys are set at 214fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka // {@link #startEmojiPalettes(String,int,float,Typeface)}. 215fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyLeft = (TextView)findViewById(R.id.emoji_keyboard_alphabet_left); 216c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka mAlphabetKeyLeft.setBackgroundResource(mFunctionalKeyBackgroundId); 217fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyLeft.setTag(Constants.CODE_ALPHA_FROM_EMOJI); 218fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyLeft.setOnTouchListener(this); 219fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyLeft.setOnClickListener(this); 220fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyRight = (TextView)findViewById(R.id.emoji_keyboard_alphabet_right); 221c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka mAlphabetKeyRight.setBackgroundResource(mFunctionalKeyBackgroundId); 222fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyRight.setTag(Constants.CODE_ALPHA_FROM_EMOJI); 223fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyRight.setOnTouchListener(this); 224fe39aec08a295ff6bd4622207ebacdbaa746c300Tadashi G. Takaoka mAlphabetKeyRight.setOnClickListener(this); 2253558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka mSpacebar = findViewById(R.id.emoji_keyboard_space); 226c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mSpacebar.setBackgroundResource(mSpacebarBackgroundId); 227c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mSpacebar.setTag(Constants.CODE_SPACE); 228c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mSpacebar.setOnTouchListener(this); 229c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mSpacebar.setOnClickListener(this); 230c1094d69134740ee0209f1ddfb25dd770b37ab25Tadashi G. Takaoka mEmojiLayoutParams.setKeyProperties(mSpacebar); 2313558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka mSpacebarIcon = findViewById(R.id.emoji_keyboard_space_icon); 2328ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 2338ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 2348ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 235b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka public boolean dispatchTouchEvent(final MotionEvent ev) { 236b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka // Add here to the stack trace to nail down the {@link IllegalArgumentException} exception 237b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka // in MotionEvent that sporadically happens. 238b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka // TODO: Remove this override method once the issue has been addressed. 239b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka return super.dispatchTouchEvent(ev); 240b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka } 241b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka 242b6c70f4ed31410eb33cd43e316a53067517c1fe3Tadashi G. Takaoka @Override 2438ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka public void onTabChanged(final String tabId) { 244874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback( 245874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka Constants.CODE_UNSPECIFIED, this); 246f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka final int categoryId = mEmojiCategory.getCategoryId(tabId); 247f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka setCurrentCategoryId(categoryId, false /* force */); 248250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka updateEmojiCategoryPageIdView(); 2498ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 2508ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 2518ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 2528ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka public void onPageSelected(final int position) { 253f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka final Pair<Integer, Integer> newPos = 254f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position); 255f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka setCurrentCategoryId(newPos.first /* categoryId */, false /* force */); 256f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka mEmojiCategory.setCurrentCategoryPageId(newPos.second /* categoryPageId */); 257250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka updateEmojiCategoryPageIdView(); 258f981fe7ed23b269676a95f953728d74f82f68e4bSatoshi Kataoka mCurrentPagerPosition = position; 2598ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 2608ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 2618ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 2628ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka public void onPageScrollStateChanged(final int state) { 2638ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka // Ignore this message. Only want the actual page selected. 2648ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 2658ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 2668ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 2678ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka public void onPageScrolled(final int position, final float positionOffset, 26823574d1231296e090e6efb41a50c7885a116ddb4Dan Zivkovic final int positionOffsetPixels) { 2694c259866c418c4bbb1348ffd122a805e86ec8bbdYohei Yukawa mEmojiPalettesAdapter.onPageScrolled(); 270250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka final Pair<Integer, Integer> newPos = 271250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position); 272250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka final int newCategoryId = newPos.first; 273250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka final int newCategorySize = mEmojiCategory.getCategoryPageSize(newCategoryId); 274250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka final int currentCategoryId = mEmojiCategory.getCurrentCategoryId(); 275250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka final int currentCategoryPageId = mEmojiCategory.getCurrentCategoryPageId(); 276250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka final int currentCategorySize = mEmojiCategory.getCurrentCategoryPageSize(); 277250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka if (newCategoryId == currentCategoryId) { 278250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategoryPageIndicatorView.setCategoryPageId( 279250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka newCategorySize, newPos.second, positionOffset); 280250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka } else if (newCategoryId > currentCategoryId) { 281250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategoryPageIndicatorView.setCategoryPageId( 282250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka currentCategorySize, currentCategoryPageId, positionOffset); 283250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka } else if (newCategoryId < currentCategoryId) { 284250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategoryPageIndicatorView.setCategoryPageId( 285250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka currentCategorySize, currentCategoryPageId, positionOffset - 1); 286250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka } 2878ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 2888ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 2890e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa /** 2900e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnTouchListener} 2910e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * interface to handle touch events from View-based elements such as the space bar. 2920e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * Note that this method is used only for observing {@link MotionEvent#ACTION_DOWN} to trigger 2930e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * {@link KeyboardActionListener#onPressKey}. {@link KeyboardActionListener#onReleaseKey} will 2940e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * be covered by {@link #onClick} as long as the event is not canceled. 2950e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa */ 2968ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 297df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa public boolean onTouch(final View v, final MotionEvent event) { 2980e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa if (event.getActionMasked() != MotionEvent.ACTION_DOWN) { 2990e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa return false; 3000e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa } 301df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa final Object tag = v.getTag(); 302df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa if (!(tag instanceof Integer)) { 303df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa return false; 304df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa } 305df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa final int code = (Integer) tag; 3060e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa mKeyboardActionListener.onPressKey( 3070e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa code, 0 /* repeatCount */, true /* isSinglePointer */); 3080e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa // It's important to return false here. Otherwise, {@link #onClick} and touch-down visual 3090e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa // feedback stop working. 310df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa return false; 3118ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 3128ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 3130e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa /** 3140e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * Called from {@link EmojiPageKeyboardView} through {@link android.view.View.OnClickListener} 3150e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * interface to handle non-canceled touch-up events from View-based elements such as the space 3160e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * bar. 3170e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa */ 3180e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa @Override 3190e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa public void onClick(View v) { 3200e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa final Object tag = v.getTag(); 3210e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa if (!(tag instanceof Integer)) { 3220e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa return; 3230e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa } 3240e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa final int code = (Integer) tag; 3252282e8520a2c1984989a14fb09896536f5033b26Jean Chalard mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE, 3262282e8520a2c1984989a14fb09896536f5033b26Jean Chalard false /* isKeyRepeat */); 3270e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); 3280e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa } 3290e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa 3300e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa /** 3310e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * Called from {@link EmojiPageKeyboardView} through 3329f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaoka * {@link com.android.inputmethod.keyboard.emoji.EmojiPageKeyboardView.OnKeyEventListener} 3330e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * interface to handle touch events from non-View-based elements such as Emoji buttons. 3340e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa */ 335df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa @Override 336df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa public void onPressKey(final Key key) { 337df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa final int code = key.getCode(); 3388ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mKeyboardActionListener.onPressKey(code, 0 /* repeatCount */, true /* isSinglePointer */); 3398ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 3408ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 3410e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa /** 3420e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * Called from {@link EmojiPageKeyboardView} through 3439f4d62cc42ab66f72ecb23996ffc2f8b039c8c4aTadashi G. Takaoka * {@link com.android.inputmethod.keyboard.emoji.EmojiPageKeyboardView.OnKeyEventListener} 3440e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa * interface to handle touch events from non-View-based elements such as Emoji buttons. 3450e04c24a0501d3a7ba7b24622ca3866027a21c3dYohei Yukawa */ 3468ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka @Override 347df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa public void onReleaseKey(final Key key) { 348d76b55297940a65bb9479020a9ed58aa978a0aeaSatoshi Kataoka mEmojiPalettesAdapter.addRecentKey(key); 349f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka mEmojiCategory.saveLastTypedCategoryPage(); 3508ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka final int code = key.getCode(); 3518ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 3528ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mKeyboardActionListener.onTextInput(key.getOutputText()); 353df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa } else { 3542282e8520a2c1984989a14fb09896536f5033b26Jean Chalard mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE, 3552282e8520a2c1984989a14fb09896536f5033b26Jean Chalard false /* isKeyRepeat */); 3568ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 357df10aeb1da87f980e5d0512133261e2c92c688a7Yohei Yukawa mKeyboardActionListener.onReleaseKey(code, false /* withSliding */); 3588ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 3598ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 3608ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) { 361e289441f928eb34463aa823a78fb9690a4d7be72Ken Wakasa if (!enabled) return; 362e289441f928eb34463aa823a78fb9690a4d7be72Ken Wakasa // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off? 363e289441f928eb34463aa823a78fb9690a4d7be72Ken Wakasa setLayerType(LAYER_TYPE_HARDWARE, null); 3648ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 3658ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 366d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka private static void setupAlphabetKey(final TextView alphabetKey, final String label, 36723574d1231296e090e6efb41a50c7885a116ddb4Dan Zivkovic final KeyDrawParams params) { 368d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka alphabetKey.setText(label); 36927ca9f1bf17c1d275faed939d529f07bb57e28f3Tadashi G. Takaoka alphabetKey.setTextColor(params.mFunctionalTextColor); 370d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka alphabetKey.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize); 371d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka alphabetKey.setTypeface(params.mTypeface); 372d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka } 373d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka 374d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka public void startEmojiPalettes(final String switchToAlphaLabel, 37500ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic final KeyVisualAttributes keyVisualAttr, 37600ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic final KeyboardIconsSet iconSet) { 377761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka final int deleteIconResId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_DELETE_KEY); 378761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka if (deleteIconResId != 0) { 379761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka mDeleteKey.setImageResource(deleteIconResId); 380761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka } 381761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka final int spacebarResId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_SPACE_KEY); 382761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka if (spacebarResId != 0) { 3833558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka // TODO: Remove this workaround to place the spacebar icon. 3843558505bee4c5254ee31cb0101b0a5d8d44a46cdTadashi G. Takaoka mSpacebarIcon.setBackgroundResource(spacebarResId); 385761a6812312c48d04bcb91e5c4448364c4925731Tadashi G. Takaoka } 386d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka final KeyDrawParams params = new KeyDrawParams(); 387d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka params.updateParams(mEmojiLayoutParams.getActionBarHeight(), keyVisualAttr); 388d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params); 389d227b00a72a68c59b8d2b2243a68c0f59d919b25Tadashi G. Takaoka setupAlphabetKey(mAlphabetKeyRight, switchToAlphaLabel, params); 3900e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka mEmojiPager.setAdapter(mEmojiPalettesAdapter); 391f981fe7ed23b269676a95f953728d74f82f68e4bSatoshi Kataoka mEmojiPager.setCurrentItem(mCurrentPagerPosition); 3920e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka } 3930e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka 3940e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka public void stopEmojiPalettes() { 3950380421bf7aea2fd3c39f5e3cf13e1593c0da02eTadashi G. Takaoka mEmojiPalettesAdapter.releaseCurrentKey(true /* withKeyRegistering */); 396f981fe7ed23b269676a95f953728d74f82f68e4bSatoshi Kataoka mEmojiPalettesAdapter.flushPendingRecentKeys(); 3970e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka mEmojiPager.setAdapter(null); 3980e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka } 3990e01df9baf3d9e2fc7b9a51b683ce6df6ff547ddSatoshi Kataoka 4008ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka public void setKeyboardActionListener(final KeyboardActionListener listener) { 4018ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka mKeyboardActionListener = listener; 40200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mDeleteKeyOnTouchListener.setKeyboardActionListener(listener); 4038ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 4048ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 405250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka private void updateEmojiCategoryPageIdView() { 406250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka if (mEmojiCategoryPageIndicatorView == null) { 407250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka return; 408250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka } 409250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategoryPageIndicatorView.setCategoryPageId( 410250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategory.getCurrentCategoryPageSize(), 411250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka mEmojiCategory.getCurrentCategoryPageId(), 0.0f /* offset */); 412250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka } 413250a12f6c216f65f3b6459b9fa620d20a6b94475Satoshi Kataoka 414f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka private void setCurrentCategoryId(final int categoryId, final boolean force) { 415e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka final int oldCategoryId = mEmojiCategory.getCurrentCategoryId(); 416e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka if (oldCategoryId == categoryId && !force) { 4178ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka return; 4188ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 4198ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka 420ead058b00216339a8688c604886645fce42fee4aTadashi G. Takaoka if (oldCategoryId == EmojiCategory.ID_RECENTS) { 421e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka // Needs to save pending updates for recent keys when we get out of the recents 422e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka // category because we don't want to move the recent emojis around while the user 423e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka // is in the recents category. 424e6e4c70a237440ad94e4d1590e98f12d53c1cf2bSatoshi Kataoka mEmojiPalettesAdapter.flushPendingRecentKeys(); 425e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka } 426e7ed5cae44b52f22d866e60f5e3c7e87f1375a1fSatoshi Kataoka 427f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka mEmojiCategory.setCurrentCategoryId(categoryId); 428f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId); 429f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka final int newCategoryPageId = mEmojiCategory.getPageIdFromCategoryId(categoryId); 4305dfbc8af2439152ca6b6759309aced5bb879b518Satoshi Kataoka if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition( 431f3f00006cbe2046abbad3a901b436d67497a40f9Satoshi Kataoka mEmojiPager.getCurrentItem()).first != categoryId) { 43244220e727105c23fad8eaf3777390e65747c1401Satoshi Kataoka mEmojiPager.setCurrentItem(newCategoryPageId, false /* smoothScroll */); 4338ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 434dd072e32014935da120fab855a0d5c07541c51c3Satoshi Kataoka if (force || mTabHost.getCurrentTab() != newTabId) { 435dd072e32014935da120fab855a0d5c07541c51c3Satoshi Kataoka mTabHost.setCurrentTab(newTabId); 4368ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 4378ac0eb59e13bce327007ba2cf2f1a7e767eebe0aTadashi G. Takaoka } 43800ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 43900ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic private static class DeleteKeyOnTouchListener implements OnTouchListener { 44000ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic private KeyboardActionListener mKeyboardActionListener = 44100ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic KeyboardActionListener.EMPTY_LISTENER; 44200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 44300ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic public void setKeyboardActionListener(final KeyboardActionListener listener) { 44400ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mKeyboardActionListener = listener; 44500ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 44600ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 44700ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic @Override 44800ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic public boolean onTouch(final View v, final MotionEvent event) { 44900ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic switch (event.getActionMasked()) { 45000ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic case MotionEvent.ACTION_DOWN: 45100ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic onTouchDown(v); 45200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic return true; 45300ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic case MotionEvent.ACTION_MOVE: 45400ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic final float x = event.getX(); 45500ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic final float y = event.getY(); 45600ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) { 45700ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic // Stop generating key events once the finger moves away from the view area. 45800ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic onTouchCanceled(v); 45900ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 46000ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic return true; 46100ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic case MotionEvent.ACTION_CANCEL: 46200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic case MotionEvent.ACTION_UP: 46300ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic onTouchUp(v); 46400ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic return true; 46500ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 46600ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic return false; 46700ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 46800ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 46900ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic private void onTouchDown(final View v) { 47000ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mKeyboardActionListener.onPressKey(Constants.CODE_DELETE, 47100ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 0 /* repeatCount */, true /* isSinglePointer */); 47200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic v.setPressed(true /* pressed */); 47300ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 47400ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 47500ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic private void onTouchUp(final View v) { 47600ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mKeyboardActionListener.onCodeInput(Constants.CODE_DELETE, 47700ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic NOT_A_COORDINATE, NOT_A_COORDINATE, false /* isKeyRepeat */); 47800ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic mKeyboardActionListener.onReleaseKey(Constants.CODE_DELETE, false /* withSliding */); 47900ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic v.setPressed(false /* pressed */); 48000ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 48100ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic 48200ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic private void onTouchCanceled(final View v) { 48300ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic v.setBackgroundColor(Color.TRANSPARENT); 48400ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 48500ae43316ed33df2b845023069b0b2b578982fc8Dan Zivkovic } 48623574d1231296e090e6efb41a50c7885a116ddb4Dan Zivkovic}