1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.inputmethod.keyboard.emoji;
18 
19 import androidx.viewpager.widget.PagerAdapter;
20 import android.util.Log;
21 import android.util.SparseArray;
22 import android.view.LayoutInflater;
23 import android.view.View;
24 import android.view.ViewGroup;
25 
26 import com.android.inputmethod.keyboard.Key;
27 import com.android.inputmethod.keyboard.Keyboard;
28 import com.android.inputmethod.keyboard.KeyboardView;
29 import com.android.inputmethod.latin.R;
30 
31 final class EmojiPalettesAdapter extends PagerAdapter {
32     private static final String TAG = EmojiPalettesAdapter.class.getSimpleName();
33     private static final boolean DEBUG_PAGER = false;
34 
35     private final EmojiPageKeyboardView.OnKeyEventListener mListener;
36     private final DynamicGridKeyboard mRecentsKeyboard;
37     private final SparseArray<EmojiPageKeyboardView> mActiveKeyboardViews = new SparseArray<>();
38     private final EmojiCategory mEmojiCategory;
39     private int mActivePosition = 0;
40 
EmojiPalettesAdapter(final EmojiCategory emojiCategory, final EmojiPageKeyboardView.OnKeyEventListener listener)41     public EmojiPalettesAdapter(final EmojiCategory emojiCategory,
42             final EmojiPageKeyboardView.OnKeyEventListener listener) {
43         mEmojiCategory = emojiCategory;
44         mListener = listener;
45         mRecentsKeyboard = mEmojiCategory.getKeyboard(EmojiCategory.ID_RECENTS, 0);
46     }
47 
flushPendingRecentKeys()48     public void flushPendingRecentKeys() {
49         mRecentsKeyboard.flushPendingRecentKeys();
50         final KeyboardView recentKeyboardView =
51                 mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId());
52         if (recentKeyboardView != null) {
53             recentKeyboardView.invalidateAllKeys();
54         }
55     }
56 
addRecentKey(final Key key)57     public void addRecentKey(final Key key) {
58         if (mEmojiCategory.isInRecentTab()) {
59             mRecentsKeyboard.addPendingKey(key);
60             return;
61         }
62         mRecentsKeyboard.addKeyFirst(key);
63         final KeyboardView recentKeyboardView =
64                 mActiveKeyboardViews.get(mEmojiCategory.getRecentTabId());
65         if (recentKeyboardView != null) {
66             recentKeyboardView.invalidateAllKeys();
67         }
68     }
69 
onPageScrolled()70     public void onPageScrolled() {
71         releaseCurrentKey(false /* withKeyRegistering */);
72     }
73 
releaseCurrentKey(final boolean withKeyRegistering)74     public void releaseCurrentKey(final boolean withKeyRegistering) {
75         // Make sure the delayed key-down event (highlight effect and haptic feedback) will be
76         // canceled.
77         final EmojiPageKeyboardView currentKeyboardView =
78                 mActiveKeyboardViews.get(mActivePosition);
79         if (currentKeyboardView == null) {
80             return;
81         }
82         currentKeyboardView.releaseCurrentKey(withKeyRegistering);
83     }
84 
85     @Override
getCount()86     public int getCount() {
87         return mEmojiCategory.getTotalPageCountOfAllCategories();
88     }
89 
90     @Override
setPrimaryItem(final ViewGroup container, final int position, final Object object)91     public void setPrimaryItem(final ViewGroup container, final int position,
92             final Object object) {
93         if (mActivePosition == position) {
94             return;
95         }
96         final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(mActivePosition);
97         if (oldKeyboardView != null) {
98             oldKeyboardView.releaseCurrentKey(false /* withKeyRegistering */);
99             oldKeyboardView.deallocateMemory();
100         }
101         mActivePosition = position;
102     }
103 
104     @Override
instantiateItem(final ViewGroup container, final int position)105     public Object instantiateItem(final ViewGroup container, final int position) {
106         if (DEBUG_PAGER) {
107             Log.d(TAG, "instantiate item: " + position);
108         }
109         final EmojiPageKeyboardView oldKeyboardView = mActiveKeyboardViews.get(position);
110         if (oldKeyboardView != null) {
111             oldKeyboardView.deallocateMemory();
112             // This may be redundant but wanted to be safer..
113             mActiveKeyboardViews.remove(position);
114         }
115         final Keyboard keyboard =
116                 mEmojiCategory.getKeyboardFromPagePosition(position);
117         final LayoutInflater inflater = LayoutInflater.from(container.getContext());
118         final EmojiPageKeyboardView keyboardView = (EmojiPageKeyboardView)inflater.inflate(
119                 R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
120         keyboardView.setKeyboard(keyboard);
121         keyboardView.setOnKeyEventListener(mListener);
122         container.addView(keyboardView);
123         mActiveKeyboardViews.put(position, keyboardView);
124         return keyboardView;
125     }
126 
127     @Override
isViewFromObject(final View view, final Object object)128     public boolean isViewFromObject(final View view, final Object object) {
129         return view == object;
130     }
131 
132     @Override
destroyItem(final ViewGroup container, final int position, final Object object)133     public void destroyItem(final ViewGroup container, final int position,
134             final Object object) {
135         if (DEBUG_PAGER) {
136             Log.d(TAG, "destroy item: " + position + ", " + object.getClass().getSimpleName());
137         }
138         final EmojiPageKeyboardView keyboardView = mActiveKeyboardViews.get(position);
139         if (keyboardView != null) {
140             keyboardView.deallocateMemory();
141             mActiveKeyboardViews.remove(position);
142         }
143         if (object instanceof View) {
144             container.removeView((View)object);
145         } else {
146             Log.w(TAG, "Warning!!! Emoji palette may be leaking. " + object);
147         }
148     }
149 }
150