SuggestionStripView.java revision 2fa3693c264a4c150ac307d9bb7f6f8f18cc4ffc
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
3e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
7e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
178c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokapackage com.android.inputmethod.latin.suggestions;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
2066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources;
21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
223fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaokaimport android.view.GestureDetector;
23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
2429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.view.MotionEvent;
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
26e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
27ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener;
28e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
29c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokaimport android.widget.RelativeLayout;
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
327339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
337339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
34d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView;
3529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel;
366f9105383a56c9ae15e35d3abf19c33d1efe5636Tadashi G. Takaokaimport com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
375faf41951929301af80026bc3191812ef874fd5aTadashi G. Takaokaimport com.android.inputmethod.latin.Constants;
388c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
398c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
408c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
419310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
42a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag;
436f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionsListener;
44e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils;
456b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger;
46ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
47179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
48179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
49a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class SuggestionStripView extends RelativeLayout implements OnClickListener,
50c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        OnLongClickListener {
51c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    public interface Listener {
5218d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard        public void addWordToUserDictionary(String word);
539310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard        public void pickSuggestionManually(int index, SuggestedWordInfo word);
54c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    }
55c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka
5686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
5729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    public static final int MAX_SUGGESTIONS = 18;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
598c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaoka    static final boolean DBG = LatinImeLogger.sDBG;
606f7218627eda110a8454053f8ecb7b80edfdc8cesatok
61913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private final ViewGroup mSuggestionsStrip;
62d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    MainKeyboardView mMainKeyboardView;
6374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
6429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final View mMoreSuggestionsContainer;
6529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestionsView mMoreSuggestionsView;
6629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
6729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
68500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka    private final ArrayList<TextView> mWordViews = CollectionUtils.newArrayList();
69500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka    private final ArrayList<TextView> mDebugInfoViews = CollectionUtils.newArrayList();
70500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka    private final ArrayList<View> mDividerViews = CollectionUtils.newArrayList();
7174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
723e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    Listener mListener;
736f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaoka    private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
746a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
75653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final SuggestionStripLayoutHelper mLayoutHelper;
7674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
784702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka     * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user.
79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
823e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public SuggestionStripView(final Context context, final AttributeSet attrs) {
834702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        this(context, attrs, R.attr.suggestionStripViewStyle);
8408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
8508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
863e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public SuggestionStripView(final Context context, final AttributeSet attrs,
873e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka            final int defStyle) {
88c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        super(context, attrs, defStyle);
89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
9016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
91913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        inflater.inflate(R.layout.suggestions_strip, this);
9286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
93913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
9460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
95913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
962442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
97ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            word.setOnLongClickListener(this);
98500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka            mWordViews.add(word);
99913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final View divider = inflater.inflate(R.layout.suggestion_divider, null);
100a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
101500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka            mDividerViews.add(divider);
102500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka            mDebugInfoViews.add((TextView)inflater.inflate(R.layout.suggestion_info, null));
103c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
104179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
105653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mLayoutHelper = new SuggestionStripLayoutHelper(
106500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka                context, attrs, defStyle, mWordViews, mDividerViews, mDebugInfoViews);
10729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
10829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
10929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
11029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                .findViewById(R.id.more_suggestions_view);
11108ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka        mMoreSuggestionsBuilder = new MoreSuggestions.Builder(context, mMoreSuggestionsView);
112bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka
11350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        final Resources res = context.getResources();
11450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
1152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa                R.dimen.config_more_suggestions_modal_tolerance);
1163fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        mMoreSuggestionsSlidingDetector = new GestureDetector(
1173fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                context, mMoreSuggestionsSlidingListener);
118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
119c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
121c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
1243e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public void setListener(final Listener listener, final View inputView) {
125c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
126d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view);
127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1293e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public void setSuggestions(final SuggestedWords suggestedWords) {
130e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
131e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        mSuggestedWords = suggestedWords;
132500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka        mLayoutHelper.layout(mSuggestedWords, mSuggestionsStrip, this);
1339c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa        if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
1344702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords);
135a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        }
13616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
13774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
138c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa    public int setMoreSuggestionsHeight(final int remainingHeight) {
139c160a3932f74fea72c5347798c001d4ae961864cKen Wakasa        return mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
140c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka    }
141b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
142b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
143913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        return mSuggestionsStrip.getChildCount() > 0
144653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                && mLayoutHelper.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0));
145b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
146b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
147bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public void showAddToDictionaryHint(final String word, final CharSequence hintText) {
148c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        clear();
149653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mLayoutHelper.layoutAddToDictionaryHint(
150653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                word, mSuggestionsStrip, getWidth(), hintText, this);
15166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
15266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
1536558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
154c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (isShowingAddToDictionaryHint()) {
155c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            clear();
156c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return true;
157c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
158c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return false;
1596558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
1606558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
162913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip.removeAllViews();
163c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        removeAllViews();
164c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        addView(mSuggestionsStrip);
16509e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka        mMoreSuggestionsView.dismissMoreKeysPanel();
166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1686f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaoka    private final MoreSuggestionsListener mMoreSuggestionsListener = new MoreSuggestionsListener() {
16929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
1706f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaoka        public void onSuggestionSelected(final int index, final SuggestedWordInfo wordInfo) {
1719310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard            mListener.pickSuggestionManually(index, wordInfo);
17209e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka            mMoreSuggestionsView.dismissMoreKeysPanel();
17329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
17429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
17529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
17629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public void onCancelInput() {
17709e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka            mMoreSuggestionsView.dismissMoreKeysPanel();
17829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
17929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
18029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
18129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreKeysPanel.Controller mMoreSuggestionsController =
18229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new MoreKeysPanel.Controller() {
18329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
1840e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka        public void onDismissMoreKeysPanel(final MoreKeysPanel panel) {
1850e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka            mMainKeyboardView.onDismissMoreKeysPanel(panel);
186fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        }
187fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang
188fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        @Override
189a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
190d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka            mMainKeyboardView.onShowMoreKeysPanel(panel);
19129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
192ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang
193ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        @Override
1940e08d70fe52737582b6c83dbf48aaf4d83063566Tadashi G. Takaoka        public void onCancelMoreKeysPanel(final MoreKeysPanel panel) {
19509e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka            mMoreSuggestionsView.dismissMoreKeysPanel();
196ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        }
19729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
19829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
199e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
2003e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public boolean onLongClick(final View view) {
201ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
2026f9105383a56c9ae15e35d3abf19c33d1efe5636Tadashi G. Takaoka                Constants.NOT_A_CODE, this);
2033fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        return showMoreSuggestions();
2043fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    }
2053fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka
2063e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    boolean showMoreSuggestions() {
2077339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard();
2087339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        if (parentKeyboard == null) {
2097339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka            return false;
210ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
211653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final SuggestionStripLayoutHelper layoutHelper = mLayoutHelper;
212653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (!layoutHelper.mMoreSuggestionsAvailable) {
2137339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka            return false;
2147339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        }
2157339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int stripWidth = getWidth();
2167339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final View container = mMoreSuggestionsContainer;
2177339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight();
2187339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
219653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        builder.layout(mSuggestedWords, layoutHelper.mSuggestionsCountInStrip, maxWidth,
220653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                (int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth),
221653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard);
2227339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mMoreSuggestionsView.setKeyboard(builder.build());
2237339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
2247339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka
2257339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
2267339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int pointX = stripWidth / 2;
227653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int pointY = -layoutHelper.mMoreSuggestionsBottomGap;
2287339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY,
229fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang                mMoreSuggestionsListener);
2307339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING;
2317339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mOriginX = mLastX;
2327339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mOriginY = mLastY;
233653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        for (int i = 0; i < layoutHelper.mSuggestionsCountInStrip; i++) {
234500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka            mWordViews.get(i).setPressed(false);
2357339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        }
2367339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        return true;
237ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    }
238ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
23950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    // Working variables for onLongClick and dispatchTouchEvent.
240d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
241d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0;
242d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1;
243d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2;
24450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mLastX;
24550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mLastY;
24650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mOriginX;
24750e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mOriginY;
24850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private final int mMoreSuggestionsModalTolerance;
2493fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private final GestureDetector mMoreSuggestionsSlidingDetector;
2503fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener =
2513fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            new GestureDetector.SimpleOnGestureListener() {
2523fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        @Override
2533fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) {
2543fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            final float dy = me.getY() - down.getY();
2553fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            if (deltaY > 0 && dy < 0) {
2563fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                return showMoreSuggestions();
2573fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
2583fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            return false;
2593fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        }
2603fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    };
26150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka
262ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    @Override
2633e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public boolean dispatchTouchEvent(final MotionEvent me) {
26451c38a441a09a4920703e765cb26179e7a80f029Tadashi G. Takaoka        if (!mMoreSuggestionsView.isShowingInParent()) {
26550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mLastX = (int)me.getX();
26650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mLastY = (int)me.getY();
2673fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) {
2683fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                return true;
2693fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
27029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return super.dispatchTouchEvent(me);
27129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
2728ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
27329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int action = me.getAction();
27429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int index = me.getActionIndex();
2758ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int x = (int)me.getX(index);
2768ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int y = (int)me.getY(index);
2778ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
278d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) {
27987104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka            if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance
28087104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                    || mOriginY - y >= mMoreSuggestionsModalTolerance) {
28187104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                // Decided to be in the sliding input mode only when the touch point has been moved
28287104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                // upward.
283d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE;
28450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
28550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka                // Decided to be in the modal input mode
286d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
28751c38a441a09a4920703e765cb26179e7a80f029Tadashi G. Takaoka                mMoreSuggestionsView.adjustVerticalCorrectionForModalMode();
28850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            }
28950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            return true;
29050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        }
29150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka
292d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        // MORE_SUGGESTIONS_IN_SLIDING_MODE
29333482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka        me.setLocation(mMoreSuggestionsView.translateX(x), mMoreSuggestionsView.translateY(y));
29433482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka        mMoreSuggestionsView.onTouchEvent(me);
29529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        return true;
29629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    }
29729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
29829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    @Override
2993e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public void onClick(final View view) {
300653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (mLayoutHelper.isAddToDictionaryShowing(view)) {
3019b570b5e62581f41c40c4558d95c77ad5896934cTadashi G. Takaoka            mListener.addWordToUserDictionary(mLayoutHelper.getAddToDictionaryWord());
302717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
303717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
304717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
305717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
30686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
3079b570b5e62581f41c40c4558d95c77ad5896934cTadashi G. Takaoka        // Integer tag is set at
3089b570b5e62581f41c40c4558d95c77ad5896934cTadashi G. Takaoka        // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and
3099b570b5e62581f41c40c4558d95c77ad5896934cTadashi G. Takaoka        // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup}
310500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka        if (!(tag instanceof Integer)) {
31186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
312500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka        }
31386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
314500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka        if (index >= mSuggestedWords.size()) {
31537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
316500a9752b1e61885f37b0fb26f09dfdd65da4e5eTadashi G. Takaoka        }
31786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
3189310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard        final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index);
3199310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard        mListener.pickSuggestionManually(index, wordInfo);
320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
32182411d47ba7e8133ed2390c6920945e139a738cesatok
3226ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
32373cd4c1428ac370e1c15c5f61b1ce499f0d4f4c7Tadashi G. Takaoka    protected void onDetachedFromWindow() {
3246ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
32509e4530ca75d4664eb72708face83b466839c522Tadashi G. Takaoka        mMoreSuggestionsView.dismissMoreKeysPanel();
3266ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
328