1 /*
2  * Copyright (C) 2008-2012  OMRON SOFTWARE Co., Ltd.
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 package jp.co.omronsoft.openwnn;
17 
18 import android.app.AlertDialog;
19 import android.content.Context;
20 import android.content.DialogInterface;
21 import android.content.SharedPreferences;
22 import android.content.res.Resources;
23 import android.graphics.drawable.Drawable;
24 import android.media.AudioManager;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.os.Vibrator;
28 import android.text.Layout;
29 import android.text.SpannableString;
30 import android.text.Spanned;
31 import android.text.style.AbsoluteSizeSpan;
32 import android.text.style.AlignmentSpan;
33 import android.util.DisplayMetrics;
34 import android.util.Log;
35 import android.view.KeyEvent;
36 import android.view.LayoutInflater;
37 import android.view.MotionEvent;
38 import android.view.View;
39 import android.view.ViewGroup;
40 import android.view.View.OnClickListener;
41 import android.view.View.OnLongClickListener;
42 import android.widget.Button;
43 import android.widget.ImageView;
44 import android.widget.LinearLayout;
45 import android.widget.HorizontalScrollView;
46 import android.widget.TextView;
47 
48 import java.util.ArrayList;
49 
50 /**
51  * The default candidates view manager using {@link android.widget.EditText}.
52  *
53  * @author Copyright (C) 2011 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
54  */
55 public class TextCandidates1LineViewManager extends CandidatesViewManager {
56 
57     /** displayCandidates() normal display */
58     private static final int IS_NEXTCANDIDATE_NORMAL = 1;
59     /** displayCandidates() delay display */
60     private static final int IS_NEXTCANDIDATE_DELAY = 2;
61     /** displayCandidates() display end */
62     private static final int IS_NEXTCANDIDATE_END = 3;
63 
64     /** Delay of set candidate */
65     private static final int SET_CANDIDATE_DELAY = 50;
66     /** Delay Millis */
67     private static final int CANDIDATE_DELAY_MILLIS = 500;
68 
69     /** Scroll distance */
70     private static final float SCROLL_DISTANCE = 0.9f;
71 
72     /** Body view of the candidates list */
73     private ViewGroup  mViewBody;
74     /** Scroller */
75     private HorizontalScrollView mViewBodyScroll;
76     /** Left more button */
77     private ImageView mLeftMoreButton;
78     /** Right more button */
79     private ImageView mRightMoreButton;
80     /** Candidate view */
81     private LinearLayout mViewCandidateList;
82 
83     /** {@link OpenWnn} instance using this manager */
84     private OpenWnn mWnn;
85     /** View type (VIEW_TYPE_NORMAL or VIEW_TYPE_FULL or VIEW_TYPE_CLOSE) */
86     private int mViewType;
87 
88     /** view width */
89     private int mViewWidth;
90     /** Minimum width of candidate view */
91     private int mCandidateMinimumWidth;
92     /** Minimum height of candidate view */
93     private int mCandidateMinimumHeight;
94 
95     /** Minimum width of candidate view */
96     private static final int CANDIDATE_MINIMUM_WIDTH = 48;
97 
98     /** Whether hide the view if there is no candidate */
99     private boolean mAutoHideMode;
100     /** The converter to get candidates from and notice the selected candidate to. */
101     private WnnEngine mConverter;
102     /** Limitation of displaying candidates */
103     private int mDisplayLimit;
104 
105     /** Vibrator for touch vibration */
106     private Vibrator mVibrator = null;
107     /** AudioManager for click sound */
108     private AudioManager mSound = null;
109 
110     /** Number of candidates displaying */
111     private int mWordCount;
112     /** List of candidates */
113     private ArrayList<WnnWord> mWnnWordArray;
114 
115     /** Character width of the candidate area */
116     private int mLineLength = 0;
117     /** Maximum width of candidate view */
118     private int mCandidateMaxWidth = 0;
119     /** general information about a display */
120     private final DisplayMetrics mMetrics = new DisplayMetrics();
121     /** Focus is none now */
122     private static final int FOCUS_NONE = -1;
123     /** Handler for set  Candidate */
124     private static final int MSG_SET_CANDIDATES = 1;
125     /** List of textView for CandiData List */
126     private ArrayList<TextView> mTextViewArray = new ArrayList<TextView>();
127     /** Now focus textView index */
128     private int mCurrentFocusIndex = FOCUS_NONE;
129     /** Focused View */
130     private View mFocusedView = null;
131     /** Focused View Background */
132     private Drawable mFocusedViewBackground = null;
133     /** Scale up text size */
134     private AbsoluteSizeSpan mSizeSpan;
135     /** Scale up text alignment */
136     private AlignmentSpan.Standard mCenterSpan;
137     /** Whether candidates long click enable */
138     private boolean mEnableCandidateLongClick = true;
139 
140    /** {@code Handler} Handler for focus Candidate wait delay */
141     private Handler mHandler = new Handler() {
142             @Override public void handleMessage(Message msg) {
143 
144             switch (msg.what) {
145                 case MSG_SET_CANDIDATES:
146                     displayCandidatesDelay(mConverter);
147                     break;
148 
149                 default:
150                     break;
151                 }
152             }
153         };
154 
155     /** Event listener for touching a candidate */
156     private OnClickListener mCandidateOnClick = new OnClickListener() {
157         public void onClick(View v) {
158             if (!v.isShown()) {
159                 return;
160             }
161             playSoundAndVibration();
162 
163             if (v instanceof CandidateTextView) {
164                 CandidateTextView text = (CandidateTextView)v;
165                 int wordcount = text.getId();
166                 WnnWord word = getWnnWord(wordcount);
167                 clearFocusCandidate();
168                 selectCandidate(word);
169             }
170         }
171     };
172 
173     /** Event listener for long-clicking a candidate */
174     private OnLongClickListener mCandidateOnLongClick = new OnLongClickListener() {
175         public boolean onLongClick(View v) {
176             if (!v.isShown()) {
177                 return true;
178             }
179 
180             if (!mEnableCandidateLongClick) {
181                 return false;
182             }
183 
184             clearFocusCandidate();
185 
186             int wordcount = ((TextView)v).getId();
187             mWord = mWnnWordArray.get(wordcount);
188 
189             displayDialog(v, mWord);
190             return true;
191         }
192     };
193 
194     /**
195      * Constructor
196      */
TextCandidates1LineViewManager()197     public TextCandidates1LineViewManager() {
198         this(300);
199     }
200 
201     /**
202      * Constructor
203      *
204      * @param displayLimit      The limit of display
205      */
TextCandidates1LineViewManager(int displayLimit)206     public TextCandidates1LineViewManager(int displayLimit) {
207         mDisplayLimit = displayLimit;
208         mWnnWordArray = new ArrayList<WnnWord>();
209         mAutoHideMode = true;
210         mMetrics.setToDefaults();
211     }
212 
213     /**
214      * Set auto-hide mode.
215      * @param hide      {@code true} if the view will hidden when no candidate exists;
216      *                  {@code false} if the view is always shown.
217      */
setAutoHide(boolean hide)218     public void setAutoHide(boolean hide) {
219         mAutoHideMode = hide;
220     }
221 
222     /** @see CandidatesViewManager */
initView(OpenWnn parent, int width, int height)223     public View initView(OpenWnn parent, int width, int height) {
224         mWnn = parent;
225         mViewWidth = width;
226 
227         Resources r = mWnn.getResources();
228 
229         mCandidateMinimumWidth = (int)(CANDIDATE_MINIMUM_WIDTH * mMetrics.density);
230         mCandidateMinimumHeight = r.getDimensionPixelSize(R.dimen.candidate_layout_height);
231 
232         LayoutInflater inflater = parent.getLayoutInflater();
233         mViewBody = (ViewGroup)inflater.inflate(R.layout.candidates_1line, null);
234         mViewBodyScroll = (HorizontalScrollView)mViewBody.findViewById(R.id.candview_scroll_1line);
235         mViewBodyScroll.setOverScrollMode(View.OVER_SCROLL_NEVER);
236         mViewBodyScroll.setOnTouchListener(new View.OnTouchListener() {
237             public boolean onTouch(View v, MotionEvent event) {
238                 switch (event.getAction()) {
239                 case MotionEvent.ACTION_DOWN:
240                 case MotionEvent.ACTION_MOVE:
241                     if (mHandler.hasMessages(MSG_SET_CANDIDATES)) {
242                         mHandler.removeMessages(MSG_SET_CANDIDATES);
243                         mHandler.sendEmptyMessageDelayed(MSG_SET_CANDIDATES, CANDIDATE_DELAY_MILLIS);
244                     }
245                     break;
246 
247                 default:
248                     break;
249 
250                 }
251                 return false;
252             }
253         });
254 
255         mLeftMoreButton = (ImageView)mViewBody.findViewById(R.id.left_more_imageview);
256         mLeftMoreButton.setOnClickListener(new View.OnClickListener() {
257             public void onClick(View v) {
258                 if (!v.isShown()) {
259                     return;
260                 }
261                 playSoundAndVibration();
262                 if (mViewBodyScroll.getScrollX() > 0) {
263                     mViewBodyScroll.smoothScrollBy(
264                                         (int)(mViewBodyScroll.getWidth() * -SCROLL_DISTANCE), 0);
265                 }
266             }
267         });
268         mLeftMoreButton.setOnLongClickListener(new View.OnLongClickListener() {
269             public boolean onLongClick(View v) {
270                 if (!v.isShown()) {
271                     return false;
272                 }
273                 if (!mViewBodyScroll.fullScroll(View.FOCUS_LEFT)) {
274                     mViewBodyScroll.scrollTo(mViewBodyScroll.getChildAt(0).getWidth(), 0);
275                 }
276                 return true;
277             }
278         });
279 
280         mRightMoreButton = (ImageView)mViewBody.findViewById(R.id.right_more_imageview);
281         mRightMoreButton.setOnClickListener(new View.OnClickListener() {
282             public void onClick(View v) {
283                 if (!v.isShown()) {
284                     return;
285                 }
286                 int width = mViewBodyScroll.getWidth();
287                 int scrollMax = mViewBodyScroll.getChildAt(0).getRight();
288 
289                 if ((mViewBodyScroll.getScrollX() + width) < scrollMax) {
290                     mViewBodyScroll.smoothScrollBy((int)(width * SCROLL_DISTANCE), 0);
291                 }
292             }
293         });
294         mRightMoreButton.setOnLongClickListener(new View.OnLongClickListener() {
295             public boolean onLongClick(View v) {
296                 if (!v.isShown()) {
297                     return false;
298                 }
299                 if (!mViewBodyScroll.fullScroll(View.FOCUS_RIGHT)) {
300                     mViewBodyScroll.scrollTo(0, 0);
301                 }
302                 return true;
303             }
304         });
305 
306         mViewLongPressDialog = (View)inflater.inflate(R.layout.candidate_longpress_dialog, null);
307 
308         /* select button */
309         Button longPressDialogButton = (Button)mViewLongPressDialog.findViewById(R.id.candidate_longpress_dialog_select);
310         longPressDialogButton.setOnClickListener(new View.OnClickListener() {
311                 public void onClick(View v) {
312                     playSoundAndVibration();
313                     clearFocusCandidate();
314                     selectCandidate(mWord);
315                     closeDialog();
316                 }
317             });
318 
319         /* cancel button */
320         longPressDialogButton = (Button)mViewLongPressDialog.findViewById(R.id.candidate_longpress_dialog_cancel);
321         longPressDialogButton.setOnClickListener(new View.OnClickListener() {
322                 public void onClick(View v) {
323                     playSoundAndVibration();
324                     mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.LIST_CANDIDATES_NORMAL));
325                     mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.UPDATE_CANDIDATE));
326                     closeDialog();
327                 }
328             });
329 
330         int buttonWidth = r.getDimensionPixelSize(R.dimen.candidate_layout_width);
331         mCandidateMaxWidth = (mViewWidth - buttonWidth * 2) / 2;
332 
333         mSizeSpan = new AbsoluteSizeSpan(r.getDimensionPixelSize(R.dimen.candidate_delete_word_size));
334         mCenterSpan = new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER);
335 
336         createNormalCandidateView();
337 
338         setViewType(CandidatesViewManager.VIEW_TYPE_CLOSE);
339 
340         return mViewBody;
341     }
342 
343     /**
344      * Create normal candidate view
345      */
createNormalCandidateView()346     private void createNormalCandidateView() {
347         mViewCandidateList = (LinearLayout)mViewBody.findViewById(R.id.candidates_view_1line);
348 
349         Context context = mViewBodyScroll.getContext();
350         for (int i = 0; i < mDisplayLimit; i++) {
351             mViewCandidateList.addView(new CandidateTextView(context,
352                                                             mCandidateMinimumHeight,
353                                                             mCandidateMinimumWidth,
354                                                             mCandidateMaxWidth));
355         }
356     }
357 
358     /** @see CandidatesViewManager#getCurrentView */
getCurrentView()359     public View getCurrentView() {
360         return mViewBody;
361     }
362 
363     /** @see CandidatesViewManager#setViewType */
setViewType(int type)364     public void setViewType(int type) {
365         mViewType = type;
366 
367         if (type == CandidatesViewManager.VIEW_TYPE_NORMAL) {
368             mViewCandidateList.setMinimumHeight(mCandidateMinimumHeight);
369         } else {
370             mViewCandidateList.setMinimumHeight(-1);
371             mHandler.removeMessages(MSG_SET_CANDIDATES);
372 
373             if (mViewBody.isShown()) {
374                 mWnn.setCandidatesViewShown(false);
375             }
376         }
377     }
378 
379     /** @see CandidatesViewManager#getViewType */
getViewType()380     public int getViewType() {
381         return mViewType;
382     }
383 
384     /** @see CandidatesViewManager#displayCandidates */
displayCandidates(WnnEngine converter)385     public void displayCandidates(WnnEngine converter) {
386 
387         mHandler.removeMessages(MSG_SET_CANDIDATES);
388 
389         closeDialog();
390         clearCandidates();
391         mConverter = converter;
392 
393         int isNextCandidate = IS_NEXTCANDIDATE_NORMAL;
394         while(isNextCandidate == IS_NEXTCANDIDATE_NORMAL) {
395             isNextCandidate = displayCandidatesNormal(converter);
396         }
397 
398         if (isNextCandidate == IS_NEXTCANDIDATE_DELAY) {
399             isNextCandidate = displayCandidatesDelay(converter);
400         }
401 
402         mViewBodyScroll.scrollTo(0,0);
403     }
404 
405 
406     /**
407      * Display the candidates.
408      * @param converter  {@link WnnEngine} which holds candidates.
409      */
displayCandidatesNormal(WnnEngine converter)410     private int displayCandidatesNormal(WnnEngine converter) {
411         int isNextCandidate = IS_NEXTCANDIDATE_NORMAL;
412 
413         if (converter == null) {
414             return IS_NEXTCANDIDATE_END;
415         }
416 
417         /* Get candidates */
418         WnnWord result = converter.getNextCandidate();
419         if (result == null) {
420             return IS_NEXTCANDIDATE_END;
421         }
422 
423         mLineLength += setCandidate(result);
424         if (mLineLength >= mViewWidth) {
425             isNextCandidate = IS_NEXTCANDIDATE_DELAY;
426         }
427 
428         if (mWordCount < 1) { /* no candidates */
429             if (mAutoHideMode) {
430                 mWnn.setCandidatesViewShown(false);
431                 return IS_NEXTCANDIDATE_END;
432             }
433         }
434 
435         if (mWordCount > mDisplayLimit) {
436             return IS_NEXTCANDIDATE_END;
437         }
438 
439         if (!(mViewBody.isShown())) {
440             mWnn.setCandidatesViewShown(true);
441         }
442         return isNextCandidate;
443     }
444 
445     /**
446      * Display the candidates.
447      * @param converter  {@link WnnEngine} which holds candidates.
448      */
displayCandidatesDelay(WnnEngine converter)449     private int displayCandidatesDelay(WnnEngine converter) {
450         int isNextCandidate = IS_NEXTCANDIDATE_DELAY;
451 
452         if (converter == null) {
453             return IS_NEXTCANDIDATE_END;
454         }
455 
456         /* Get candidates */
457         WnnWord result = converter.getNextCandidate();
458         if (result == null) {
459             return IS_NEXTCANDIDATE_END;
460         }
461 
462         setCandidate(result);
463 
464         if (mWordCount > mDisplayLimit) {
465             return IS_NEXTCANDIDATE_END;
466         }
467 
468         mHandler.sendEmptyMessageDelayed(MSG_SET_CANDIDATES, SET_CANDIDATE_DELAY);
469 
470         return isNextCandidate;
471     }
472 
473     /**
474      * Set the candidate for candidate view
475      * @param word set word
476      * @return int Set width
477      */
setCandidate(WnnWord word)478     private int setCandidate(WnnWord word) {
479         CandidateTextView candidateTextView =
480                 (CandidateTextView) mViewCandidateList.getChildAt(mWordCount);
481         candidateTextView.setCandidateTextView(word, mWordCount, mCandidateOnClick,
482                                                     mCandidateOnLongClick);
483         mWnnWordArray.add(mWordCount, word);
484         mWordCount++;
485         mTextViewArray.add(candidateTextView);
486 
487         return candidateTextView.getWidth();
488     }
489 
490     /**
491      * Clear the candidate view
492      */
clearNormalViewCandidate()493     private void clearNormalViewCandidate() {
494         int candidateNum = mViewCandidateList.getChildCount();
495         for (int i = 0; i < candidateNum; i++) {
496             View v = mViewCandidateList.getChildAt(i);
497             v.setVisibility(View.GONE);
498         }
499     }
500 
501     /** @see CandidatesViewManager#clearCandidates */
clearCandidates()502     public void clearCandidates() {
503         clearFocusCandidate();
504         clearNormalViewCandidate();
505 
506         mLineLength = 0;
507 
508         mWordCount = 0;
509         mWnnWordArray.clear();
510         mTextViewArray.clear();
511 
512         if (mAutoHideMode && mViewBody.isShown()) {
513             mWnn.setCandidatesViewShown(false);
514         }
515     }
516 
517     /** @see CandidatesViewManager#setPreferences */
setPreferences(SharedPreferences pref)518     public void setPreferences(SharedPreferences pref) {
519         try {
520             if (pref.getBoolean("key_vibration", false)) {
521                 mVibrator = (Vibrator)mWnn.getSystemService(Context.VIBRATOR_SERVICE);
522             } else {
523                 mVibrator = null;
524             }
525             if (pref.getBoolean("key_sound", false)) {
526                 mSound = (AudioManager)mWnn.getSystemService(Context.AUDIO_SERVICE);
527             } else {
528                 mSound = null;
529             }
530         } catch (Exception ex) {
531             Log.d("OpenWnn", "NO VIBRATOR");
532         }
533     }
534 
535     /**
536      * Select a candidate.
537      * <br>
538      * This method notices the selected word to {@link OpenWnn}.
539      *
540      * @param word  The selected word
541      */
selectCandidate(WnnWord word)542     private void selectCandidate(WnnWord word) {
543         mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.SELECT_CANDIDATE, word));
544     }
545 
playSoundAndVibration()546     private void playSoundAndVibration() {
547         if (mVibrator != null) {
548             try {
549                 mVibrator.vibrate(5);
550             } catch (Exception ex) {
551                 Log.e("OpenWnn", "TextCandidates1LineViewManager::selectCandidate Vibrator " + ex.toString());
552             }
553         }
554         if (mSound != null) {
555             try {
556                 mSound.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, 1.0f);
557             } catch (Exception ex) {
558                 Log.e("OpenWnn", "TextCandidates1LineViewManager::selectCandidate Sound " + ex.toString());
559             }
560         }
561     }
562 
563     /**
564      * KeyEvent action for the candidate view.
565      *
566      * @param key    Key event
567      */
processMoveKeyEvent(int key)568     public void processMoveKeyEvent(int key) {
569         if (!mViewBody.isShown()) {
570             return;
571         }
572 
573         switch (key) {
574         case KeyEvent.KEYCODE_DPAD_LEFT:
575             moveFocus(-1);
576             break;
577 
578         case KeyEvent.KEYCODE_DPAD_RIGHT:
579             moveFocus(1);
580             break;
581 
582         case KeyEvent.KEYCODE_DPAD_UP:
583             moveFocus(-1);
584             break;
585 
586         case KeyEvent.KEYCODE_DPAD_DOWN:
587             moveFocus(1);
588             break;
589 
590         default:
591             break;
592 
593         }
594     }
595 
596     /**
597      * Get a flag candidate is focused now.
598      *
599      * @return the Candidate is focused of a flag.
600      */
isFocusCandidate()601     public boolean isFocusCandidate(){
602         if (mCurrentFocusIndex != FOCUS_NONE) {
603             return true;
604         }
605         return false;
606     }
607 
608     /**
609      * Give focus to View of candidate.
610      */
setViewStatusOfFocusedCandidate()611     private void setViewStatusOfFocusedCandidate() {
612         View view = mFocusedView;
613         if (view != null) {
614             view.setBackgroundDrawable(mFocusedViewBackground);
615         }
616 
617         TextView v = getFocusedView();
618         mFocusedView = v;
619         if (v != null) {
620             mFocusedViewBackground = v.getBackground();
621             v.setBackgroundResource(R.drawable.cand_back_focuse);
622 
623             int viewBodyLeft = getViewLeftOnScreen(mViewBodyScroll);
624             int viewBodyRight = viewBodyLeft + mViewBodyScroll.getWidth();
625             int focusedViewLeft = getViewLeftOnScreen(v);
626             int focusedViewRight = focusedViewLeft + v.getWidth();
627 
628             if (focusedViewRight > viewBodyRight) {
629                 mViewBodyScroll.scrollBy((focusedViewRight - viewBodyRight), 0);
630             } else if (focusedViewLeft < viewBodyLeft) {
631                 mViewBodyScroll.scrollBy((focusedViewLeft - viewBodyLeft), 0);
632             }
633         }
634     }
635 
636     /**
637      * Clear focus to selected candidate.
638      */
clearFocusCandidate()639     private void clearFocusCandidate(){
640         View view = mFocusedView;
641         if (view != null) {
642             view.setBackgroundDrawable(mFocusedViewBackground);
643             mFocusedView = null;
644         }
645 
646         mCurrentFocusIndex = FOCUS_NONE;
647 
648         mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.FOCUS_CANDIDATE_END));
649     }
650 
651     /**
652      * Select candidate that has focus.
653      */
selectFocusCandidate()654     public void selectFocusCandidate(){
655         if (mCurrentFocusIndex != FOCUS_NONE) {
656             selectCandidate(getFocusedWnnWord());
657         }
658     }
659 
660     /**
661      * Get View of focus candidate.
662      */
getFocusedView()663     private TextView getFocusedView() {
664         if (mCurrentFocusIndex == FOCUS_NONE) {
665             return null;
666         }
667         return mTextViewArray.get(mCurrentFocusIndex);
668     }
669 
670     /**
671      * Move the focus to next candidate.
672      *
673      * @param direction  The direction of increment or decrement.
674      */
moveFocus(int direction)675     private void moveFocus(int direction) {
676         boolean isStart = (mCurrentFocusIndex == FOCUS_NONE);
677         int size = mTextViewArray.size();
678         int index = isStart ? 0 : (mCurrentFocusIndex + direction);
679 
680         if (index < 0) {
681             index = size - 1;
682         } else {
683             if (index >= size) {
684                 index = 0;
685             }
686         }
687 
688         mCurrentFocusIndex = index;
689         setViewStatusOfFocusedCandidate();
690 
691         if (isStart) {
692             mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.FOCUS_CANDIDATE_START));
693         }
694     }
695 
696     /**
697      * Get view top position on screen.
698      *
699      * @param view target view.
700      * @return int view top position on screen
701      */
getViewLeftOnScreen(View view)702     private int getViewLeftOnScreen(View view) {
703         int[] location = new int[2];
704         view.getLocationOnScreen(location);
705         return location[0];
706     }
707 
708     /** @see CandidatesViewManager#getFocusedWnnWord */
getFocusedWnnWord()709     public WnnWord getFocusedWnnWord() {
710         return getWnnWord(mCurrentFocusIndex);
711     }
712 
713     /**
714      * Get WnnWord.
715      *
716      * @return WnnWord word
717      */
getWnnWord(int index)718     public WnnWord getWnnWord(int index) {
719         return mWnnWordArray.get(index);
720     }
721 
722     /** @see CandidatesViewManager#setCandidateMsgRemove */
setCandidateMsgRemove()723     public void setCandidateMsgRemove() {
724         mHandler.removeMessages(MSG_SET_CANDIDATES);
725     }
726 }
727