Home | History | Annotate | Download | only in suggestions
      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 {
     61         public void addWordToUserDictionary(String word);
     62         public void showImportantNoticeContents();
     63         public void pickSuggestionManually(SuggestedWordInfo word);
     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 
     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 
    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 
    116         public void showSuggestionsStrip() {
    117             mSuggestionsStrip.setVisibility(VISIBLE);
    118             mAddToDictionaryStrip.setVisibility(INVISIBLE);
    119             mImportantNoticeStrip.setVisibility(INVISIBLE);
    120         }
    121 
    122         public void showAddToDictionaryStrip() {
    123             mSuggestionsStrip.setVisibility(INVISIBLE);
    124             mAddToDictionaryStrip.setVisibility(VISIBLE);
    125             mImportantNoticeStrip.setVisibility(INVISIBLE);
    126         }
    127 
    128         public void showImportantNoticeStrip() {
    129             mSuggestionsStrip.setVisibility(INVISIBLE);
    130             mAddToDictionaryStrip.setVisibility(INVISIBLE);
    131             mImportantNoticeStrip.setVisibility(VISIBLE);
    132         }
    133 
    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      */
    144     public SuggestionStripView(final Context context, final AttributeSet attrs) {
    145         this(context, attrs, R.attr.suggestionStripViewStyle);
    146     }
    147 
    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      */
    201     public void setListener(final Listener listener, final View inputView) {
    202         mListener = listener;
    203         mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view);
    204     }
    205 
    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 
    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 
    222     public void setMoreSuggestionsHeight(final int remainingHeight) {
    223         mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
    224     }
    225 
    226     public boolean isShowingAddToDictionaryHint() {
    227         return mStripVisibilityGroup.isShowingAddToDictionaryStrip();
    228     }
    229 
    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 
    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.
    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 
    271     public void clear() {
    272         mSuggestionsStrip.removeAllViews();
    273         removeAllDebugInfoViews();
    274         mStripVisibilityGroup.showSuggestionsStrip();
    275         dismissMoreSuggestionsPanel();
    276     }
    277 
    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 
    319     public boolean isShowingMoreSuggestionPanel() {
    320         return mMoreSuggestionsView.isShowingInParent();
    321     }
    322 
    323     public void dismissMoreSuggestionsPanel() {
    324         mMoreSuggestionsView.dismissMoreKeysPanel();
    325     }
    326 
    327     @Override
    328     public boolean onLongClick(final View view) {
    329         AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
    330                 Constants.NOT_A_CODE, this);
    331         return showMoreSuggestions();
    332     }
    333 
    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
    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
    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
    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
    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
    510     protected void onDetachedFromWindow() {
    511         super.onDetachedFromWindow();
    512         dismissMoreSuggestionsPanel();
    513     }
    514 
    515     @Override
    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