1 /*
2  * Copyright (C) 2011 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.latin.suggestions;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.content.res.TypedArray;
22 import android.graphics.Color;
23 import android.graphics.drawable.Drawable;
24 import android.support.v4.view.ViewCompat;
25 import android.text.TextUtils;
26 import android.util.AttributeSet;
27 import android.util.TypedValue;
28 import android.view.GestureDetector;
29 import android.view.LayoutInflater;
30 import android.view.MotionEvent;
31 import android.view.View;
32 import android.view.View.OnClickListener;
33 import android.view.View.OnLongClickListener;
34 import android.view.ViewGroup;
35 import android.view.ViewParent;
36 import android.view.accessibility.AccessibilityEvent;
37 import android.widget.ImageButton;
38 import android.widget.RelativeLayout;
39 import android.widget.TextView;
40 
41 import com.android.inputmethod.accessibility.AccessibilityUtils;
42 import com.android.inputmethod.keyboard.Keyboard;
43 import com.android.inputmethod.keyboard.MainKeyboardView;
44 import com.android.inputmethod.keyboard.MoreKeysPanel;
45 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
46 import com.android.inputmethod.latin.Constants;
47 import com.android.inputmethod.latin.R;
48 import com.android.inputmethod.latin.SuggestedWords;
49 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
50 import com.android.inputmethod.latin.define.DebugFlags;
51 import com.android.inputmethod.latin.settings.Settings;
52 import com.android.inputmethod.latin.settings.SettingsValues;
53 import com.android.inputmethod.latin.suggestions.MoreSuggestionsView.MoreSuggestionsListener;
54 import com.android.inputmethod.latin.utils.ImportantNoticeUtils;
55 
56 import java.util.ArrayList;
57 
58 public final class SuggestionStripView extends RelativeLayout implements OnClickListener,
59         OnLongClickListener {
60     public interface Listener {
addWordToUserDictionary(String word)61         public void addWordToUserDictionary(String word);
showImportantNoticeContents()62         public void showImportantNoticeContents();
pickSuggestionManually(SuggestedWordInfo word)63         public void pickSuggestionManually(SuggestedWordInfo word);
onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat)64         public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
65     }
66 
67     static final boolean DBG = DebugFlags.DEBUG_ENABLED;
68     private static final float DEBUG_INFO_TEXT_SIZE_IN_DIP = 6.0f;
69 
70     private final ViewGroup mSuggestionsStrip;
71     private final ImageButton mVoiceKey;
72     private final ViewGroup mAddToDictionaryStrip;
73     private final View mImportantNoticeStrip;
74     MainKeyboardView mMainKeyboardView;
75 
76     private final View mMoreSuggestionsContainer;
77     private final MoreSuggestionsView mMoreSuggestionsView;
78     private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
79 
80     private final ArrayList<TextView> mWordViews = new ArrayList<>();
81     private final ArrayList<TextView> mDebugInfoViews = new ArrayList<>();
82     private final ArrayList<View> mDividerViews = new ArrayList<>();
83 
84     Listener mListener;
85     private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
86     private int mStartIndexOfMoreSuggestions;
87 
88     private final SuggestionStripLayoutHelper mLayoutHelper;
89     private final StripVisibilityGroup mStripVisibilityGroup;
90 
91     private static class StripVisibilityGroup {
92         private final View mSuggestionStripView;
93         private final View mSuggestionsStrip;
94         private final View mAddToDictionaryStrip;
95         private final View mImportantNoticeStrip;
96 
StripVisibilityGroup(final View suggestionStripView, final ViewGroup suggestionsStrip, final ViewGroup addToDictionaryStrip, final View importantNoticeStrip)97         public StripVisibilityGroup(final View suggestionStripView,
98                 final ViewGroup suggestionsStrip, final ViewGroup addToDictionaryStrip,
99                 final View importantNoticeStrip) {
100             mSuggestionStripView = suggestionStripView;
101             mSuggestionsStrip = suggestionsStrip;
102             mAddToDictionaryStrip = addToDictionaryStrip;
103             mImportantNoticeStrip = importantNoticeStrip;
104             showSuggestionsStrip();
105         }
106 
setLayoutDirection(final boolean isRtlLanguage)107         public void setLayoutDirection(final boolean isRtlLanguage) {
108             final int layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL
109                     : ViewCompat.LAYOUT_DIRECTION_LTR;
110             ViewCompat.setLayoutDirection(mSuggestionStripView, layoutDirection);
111             ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection);
112             ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection);
113             ViewCompat.setLayoutDirection(mImportantNoticeStrip, layoutDirection);
114         }
115 
showSuggestionsStrip()116         public void showSuggestionsStrip() {
117             mSuggestionsStrip.setVisibility(VISIBLE);
118             mAddToDictionaryStrip.setVisibility(INVISIBLE);
119             mImportantNoticeStrip.setVisibility(INVISIBLE);
120         }
121 
showAddToDictionaryStrip()122         public void showAddToDictionaryStrip() {
123             mSuggestionsStrip.setVisibility(INVISIBLE);
124             mAddToDictionaryStrip.setVisibility(VISIBLE);
125             mImportantNoticeStrip.setVisibility(INVISIBLE);
126         }
127 
showImportantNoticeStrip()128         public void showImportantNoticeStrip() {
129             mSuggestionsStrip.setVisibility(INVISIBLE);
130             mAddToDictionaryStrip.setVisibility(INVISIBLE);
131             mImportantNoticeStrip.setVisibility(VISIBLE);
132         }
133 
isShowingAddToDictionaryStrip()134         public boolean isShowingAddToDictionaryStrip() {
135             return mAddToDictionaryStrip.getVisibility() == VISIBLE;
136         }
137     }
138 
139     /**
140      * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user.
141      * @param context
142      * @param attrs
143      */
SuggestionStripView(final Context context, final AttributeSet attrs)144     public SuggestionStripView(final Context context, final AttributeSet attrs) {
145         this(context, attrs, R.attr.suggestionStripViewStyle);
146     }
147 
SuggestionStripView(final Context context, final AttributeSet attrs, final int defStyle)148     public SuggestionStripView(final Context context, final AttributeSet attrs,
149             final int defStyle) {
150         super(context, attrs, defStyle);
151 
152         final LayoutInflater inflater = LayoutInflater.from(context);
153         inflater.inflate(R.layout.suggestions_strip, this);
154 
155         mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
156         mVoiceKey = (ImageButton)findViewById(R.id.suggestions_strip_voice_key);
157         mAddToDictionaryStrip = (ViewGroup)findViewById(R.id.add_to_dictionary_strip);
158         mImportantNoticeStrip = findViewById(R.id.important_notice_strip);
159         mStripVisibilityGroup = new StripVisibilityGroup(this, mSuggestionsStrip,
160                 mAddToDictionaryStrip, mImportantNoticeStrip);
161 
162         for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) {
163             final TextView word = new TextView(context, null, R.attr.suggestionWordStyle);
164             word.setOnClickListener(this);
165             word.setOnLongClickListener(this);
166             mWordViews.add(word);
167             final View divider = inflater.inflate(R.layout.suggestion_divider, null);
168             mDividerViews.add(divider);
169             final TextView info = new TextView(context, null, R.attr.suggestionWordStyle);
170             info.setTextColor(Color.WHITE);
171             info.setTextSize(TypedValue.COMPLEX_UNIT_DIP, DEBUG_INFO_TEXT_SIZE_IN_DIP);
172             mDebugInfoViews.add(info);
173         }
174 
175         mLayoutHelper = new SuggestionStripLayoutHelper(
176                 context, attrs, defStyle, mWordViews, mDividerViews, mDebugInfoViews);
177 
178         mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
179         mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
180                 .findViewById(R.id.more_suggestions_view);
181         mMoreSuggestionsBuilder = new MoreSuggestions.Builder(context, mMoreSuggestionsView);
182 
183         final Resources res = context.getResources();
184         mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
185                 R.dimen.config_more_suggestions_modal_tolerance);
186         mMoreSuggestionsSlidingDetector = new GestureDetector(
187                 context, mMoreSuggestionsSlidingListener);
188 
189         final TypedArray keyboardAttr = context.obtainStyledAttributes(attrs,
190                 R.styleable.Keyboard, defStyle, R.style.SuggestionStripView);
191         final Drawable iconVoice = keyboardAttr.getDrawable(R.styleable.Keyboard_iconShortcutKey);
192         keyboardAttr.recycle();
193         mVoiceKey.setImageDrawable(iconVoice);
194         mVoiceKey.setOnClickListener(this);
195     }
196 
197     /**
198      * A connection back to the input method.
199      * @param listener
200      */
setListener(final Listener listener, final View inputView)201     public void setListener(final Listener listener, final View inputView) {
202         mListener = listener;
203         mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view);
204     }
205 
updateVisibility(final boolean shouldBeVisible, final boolean isFullscreenMode)206     public void updateVisibility(final boolean shouldBeVisible, final boolean isFullscreenMode) {
207         final int visibility = shouldBeVisible ? VISIBLE : (isFullscreenMode ? GONE : INVISIBLE);
208         setVisibility(visibility);
209         final SettingsValues currentSettingsValues = Settings.getInstance().getCurrent();
210         mVoiceKey.setVisibility(currentSettingsValues.mShowsVoiceInputKey ? VISIBLE : INVISIBLE);
211     }
212 
setSuggestions(final SuggestedWords suggestedWords, final boolean isRtlLanguage)213     public void setSuggestions(final SuggestedWords suggestedWords, final boolean isRtlLanguage) {
214         clear();
215         mStripVisibilityGroup.setLayoutDirection(isRtlLanguage);
216         mSuggestedWords = suggestedWords;
217         mStartIndexOfMoreSuggestions = mLayoutHelper.layoutAndReturnStartIndexOfMoreSuggestions(
218                 mSuggestedWords, mSuggestionsStrip, this);
219         mStripVisibilityGroup.showSuggestionsStrip();
220     }
221 
setMoreSuggestionsHeight(final int remainingHeight)222     public void setMoreSuggestionsHeight(final int remainingHeight) {
223         mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
224     }
225 
isShowingAddToDictionaryHint()226     public boolean isShowingAddToDictionaryHint() {
227         return mStripVisibilityGroup.isShowingAddToDictionaryStrip();
228     }
229 
showAddToDictionaryHint(final String word)230     public void showAddToDictionaryHint(final String word) {
231         mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip);
232         // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word
233         // will be extracted at {@link #onClick(View)}.
234         mAddToDictionaryStrip.setTag(word);
235         mAddToDictionaryStrip.setOnClickListener(this);
236         mStripVisibilityGroup.showAddToDictionaryStrip();
237     }
238 
dismissAddToDictionaryHint()239     public boolean dismissAddToDictionaryHint() {
240         if (isShowingAddToDictionaryHint()) {
241             clear();
242             return true;
243         }
244         return false;
245     }
246 
247     // This method checks if we should show the important notice (checks on permanent storage if
248     // it has been shown once already or not, and if in the setup wizard). If applicable, it shows
249     // the notice. In all cases, it returns true if it was shown, false otherwise.
maybeShowImportantNoticeTitle()250     public boolean maybeShowImportantNoticeTitle() {
251         if (!ImportantNoticeUtils.shouldShowImportantNotice(getContext())) {
252             return false;
253         }
254         if (getWidth() <= 0) {
255             return false;
256         }
257         final String importantNoticeTitle = ImportantNoticeUtils.getNextImportantNoticeTitle(
258                 getContext());
259         if (TextUtils.isEmpty(importantNoticeTitle)) {
260             return false;
261         }
262         if (isShowingMoreSuggestionPanel()) {
263             dismissMoreSuggestionsPanel();
264         }
265         mLayoutHelper.layoutImportantNotice(mImportantNoticeStrip, importantNoticeTitle);
266         mStripVisibilityGroup.showImportantNoticeStrip();
267         mImportantNoticeStrip.setOnClickListener(this);
268         return true;
269     }
270 
clear()271     public void clear() {
272         mSuggestionsStrip.removeAllViews();
273         removeAllDebugInfoViews();
274         mStripVisibilityGroup.showSuggestionsStrip();
275         dismissMoreSuggestionsPanel();
276     }
277 
removeAllDebugInfoViews()278     private void removeAllDebugInfoViews() {
279         // The debug info views may be placed as children views of this {@link SuggestionStripView}.
280         for (final View debugInfoView : mDebugInfoViews) {
281             final ViewParent parent = debugInfoView.getParent();
282             if (parent instanceof ViewGroup) {
283                 ((ViewGroup)parent).removeView(debugInfoView);
284             }
285         }
286     }
287 
288     private final MoreSuggestionsListener mMoreSuggestionsListener = new MoreSuggestionsListener() {
289         @Override
290         public void onSuggestionSelected(final SuggestedWordInfo wordInfo) {
291             mListener.pickSuggestionManually(wordInfo);
292             dismissMoreSuggestionsPanel();
293         }
294 
295         @Override
296         public void onCancelInput() {
297             dismissMoreSuggestionsPanel();
298         }
299     };
300 
301     private final MoreKeysPanel.Controller mMoreSuggestionsController =
302             new MoreKeysPanel.Controller() {
303         @Override
304         public void onDismissMoreKeysPanel() {
305             mMainKeyboardView.onDismissMoreKeysPanel();
306         }
307 
308         @Override
309         public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
310             mMainKeyboardView.onShowMoreKeysPanel(panel);
311         }
312 
313         @Override
314         public void onCancelMoreKeysPanel() {
315             dismissMoreSuggestionsPanel();
316         }
317     };
318 
isShowingMoreSuggestionPanel()319     public boolean isShowingMoreSuggestionPanel() {
320         return mMoreSuggestionsView.isShowingInParent();
321     }
322 
dismissMoreSuggestionsPanel()323     public void dismissMoreSuggestionsPanel() {
324         mMoreSuggestionsView.dismissMoreKeysPanel();
325     }
326 
327     @Override
onLongClick(final View view)328     public boolean onLongClick(final View view) {
329         AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
330                 Constants.NOT_A_CODE, this);
331         return showMoreSuggestions();
332     }
333 
showMoreSuggestions()334     boolean showMoreSuggestions() {
335         final Keyboard parentKeyboard = mMainKeyboardView.getKeyboard();
336         if (parentKeyboard == null) {
337             return false;
338         }
339         final SuggestionStripLayoutHelper layoutHelper = mLayoutHelper;
340         if (mSuggestedWords.size() <= mStartIndexOfMoreSuggestions) {
341             return false;
342         }
343         // Dismiss another {@link MoreKeysPanel} that may be being showed, for example
344         // {@link MoreKeysKeyboardView}.
345         mMainKeyboardView.onDismissMoreKeysPanel();
346         // Dismiss all key previews and sliding key input preview that may be being showed.
347         mMainKeyboardView.dismissAllKeyPreviews();
348         mMainKeyboardView.dismissSlidingKeyInputPreview();
349         final int stripWidth = getWidth();
350         final View container = mMoreSuggestionsContainer;
351         final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight();
352         final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
353         builder.layout(mSuggestedWords, mStartIndexOfMoreSuggestions, maxWidth,
354                 (int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth),
355                 layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard);
356         mMoreSuggestionsView.setKeyboard(builder.build());
357         container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
358 
359         final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
360         final int pointX = stripWidth / 2;
361         final int pointY = -layoutHelper.mMoreSuggestionsBottomGap;
362         moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY,
363                 mMoreSuggestionsListener);
364         mOriginX = mLastX;
365         mOriginY = mLastY;
366         for (int i = 0; i < mStartIndexOfMoreSuggestions; i++) {
367             mWordViews.get(i).setPressed(false);
368         }
369         return true;
370     }
371 
372     // Working variables for {@link onInterceptTouchEvent(MotionEvent)} and
373     // {@link onTouchEvent(MotionEvent)}.
374     private int mLastX;
375     private int mLastY;
376     private int mOriginX;
377     private int mOriginY;
378     private final int mMoreSuggestionsModalTolerance;
379     private boolean mNeedsToTransformTouchEventToHoverEvent;
380     private boolean mIsDispatchingHoverEventToMoreSuggestions;
381     private final GestureDetector mMoreSuggestionsSlidingDetector;
382     private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener =
383             new GestureDetector.SimpleOnGestureListener() {
384         @Override
385         public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) {
386             final float dy = me.getY() - down.getY();
387             if (deltaY > 0 && dy < 0) {
388                 return showMoreSuggestions();
389             }
390             return false;
391         }
392     };
393 
394     @Override
onInterceptTouchEvent(final MotionEvent me)395     public boolean onInterceptTouchEvent(final MotionEvent me) {
396         if (!mMoreSuggestionsView.isShowingInParent()) {
397             mLastX = (int)me.getX();
398             mLastY = (int)me.getY();
399             return mMoreSuggestionsSlidingDetector.onTouchEvent(me);
400         }
401 
402         final int action = me.getAction();
403         final int index = me.getActionIndex();
404         final int x = (int)me.getX(index);
405         final int y = (int)me.getY(index);
406         if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance
407                 || mOriginY - y >= mMoreSuggestionsModalTolerance) {
408             // Decided to be in the sliding suggestion mode only when the touch point has been moved
409             // upward. Further {@link MotionEvent}s will be delivered to
410             // {@link #onTouchEvent(MotionEvent)}.
411             mNeedsToTransformTouchEventToHoverEvent =
412                     AccessibilityUtils.getInstance().isTouchExplorationEnabled();
413             mIsDispatchingHoverEventToMoreSuggestions = false;
414             return true;
415         }
416 
417         if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
418             // Decided to be in the modal input mode.
419             mMoreSuggestionsView.adjustVerticalCorrectionForModalMode();
420         }
421         return false;
422     }
423 
424     @Override
dispatchPopulateAccessibilityEvent(final AccessibilityEvent event)425     public boolean dispatchPopulateAccessibilityEvent(final AccessibilityEvent event) {
426         // Don't populate accessibility event with suggested words and voice key.
427         return true;
428     }
429 
430     @Override
onTouchEvent(final MotionEvent me)431     public boolean onTouchEvent(final MotionEvent me) {
432         // In the sliding input mode. {@link MotionEvent} should be forwarded to
433         // {@link MoreSuggestionsView}.
434         final int index = me.getActionIndex();
435         final int x = mMoreSuggestionsView.translateX((int)me.getX(index));
436         final int y = mMoreSuggestionsView.translateY((int)me.getY(index));
437         me.setLocation(x, y);
438         if (!mNeedsToTransformTouchEventToHoverEvent) {
439             mMoreSuggestionsView.onTouchEvent(me);
440             return true;
441         }
442         // In sliding suggestion mode with accessibility mode on, a touch event should be
443         // transformed to a hover event.
444         final int width = mMoreSuggestionsView.getWidth();
445         final int height = mMoreSuggestionsView.getHeight();
446         final boolean onMoreSuggestions = (x >= 0 && x < width && y >= 0 && y < height);
447         if (!onMoreSuggestions && !mIsDispatchingHoverEventToMoreSuggestions) {
448             // Just drop this touch event because dispatching hover event isn't started yet and
449             // the touch event isn't on {@link MoreSuggestionsView}.
450             return true;
451         }
452         final int hoverAction;
453         if (onMoreSuggestions && !mIsDispatchingHoverEventToMoreSuggestions) {
454             // Transform this touch event to a hover enter event and start dispatching a hover
455             // event to {@link MoreSuggestionsView}.
456             mIsDispatchingHoverEventToMoreSuggestions = true;
457             hoverAction = MotionEvent.ACTION_HOVER_ENTER;
458         } else if (me.getActionMasked() == MotionEvent.ACTION_UP) {
459             // Transform this touch event to a hover exit event and stop dispatching a hover event
460             // after this.
461             mIsDispatchingHoverEventToMoreSuggestions = false;
462             mNeedsToTransformTouchEventToHoverEvent = false;
463             hoverAction = MotionEvent.ACTION_HOVER_EXIT;
464         } else {
465             // Transform this touch event to a hover move event.
466             hoverAction = MotionEvent.ACTION_HOVER_MOVE;
467         }
468         me.setAction(hoverAction);
469         mMoreSuggestionsView.onHoverEvent(me);
470         return true;
471     }
472 
473     @Override
onClick(final View view)474     public void onClick(final View view) {
475         AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
476                 Constants.CODE_UNSPECIFIED, this);
477         if (view == mImportantNoticeStrip) {
478             mListener.showImportantNoticeContents();
479             return;
480         }
481         if (view == mVoiceKey) {
482             mListener.onCodeInput(Constants.CODE_SHORTCUT,
483                     Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE,
484                     false /* isKeyRepeat */);
485             return;
486         }
487         final Object tag = view.getTag();
488         // {@link String} tag is set at {@link #showAddToDictionaryHint(String,CharSequence)}.
489         if (tag instanceof String) {
490             final String wordToSave = (String)tag;
491             mListener.addWordToUserDictionary(wordToSave);
492             clear();
493             return;
494         }
495 
496         // {@link Integer} tag is set at
497         // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and
498         // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup}
499         if (tag instanceof Integer) {
500             final int index = (Integer) tag;
501             if (index >= mSuggestedWords.size()) {
502                 return;
503             }
504             final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index);
505             mListener.pickSuggestionManually(wordInfo);
506         }
507     }
508 
509     @Override
onDetachedFromWindow()510     protected void onDetachedFromWindow() {
511         super.onDetachedFromWindow();
512         dismissMoreSuggestionsPanel();
513     }
514 
515     @Override
onSizeChanged(final int w, final int h, final int oldw, final int oldh)516     protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
517         // Called by the framework when the size is known. Show the important notice if applicable.
518         // This may be overriden by showing suggestions later, if applicable.
519         if (oldw <= 0 && w > 0) {
520             maybeShowImportantNoticeTitle();
521         }
522     }
523 }
524