@@ -9596,6 +9596,8 @@ public boolean isShowing() {
95969596
95979597 private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
95989598 private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan .SUGGESTIONS_MAX_SIZE ;
9599+ private static final int ADD_TO_DICTIONARY = -1 ;
9600+ private static final int DELETE_TEXT = -2 ;
95999601 private SuggestionInfo [] mSuggestionInfos ;
96009602 private int mNumberOfSuggestions ;
96019603 private boolean mCursorWasVisibleBeforeSuggestions ;
@@ -9647,9 +9649,9 @@ protected void initContentView() {
96479649 listView .setOnItemClickListener (this );
96489650 mContentView = listView ;
96499651
9650- // Inflate the suggestion items once and for all. +1 for add to dictionary
9651- mSuggestionInfos = new SuggestionInfo [MAX_NUMBER_SUGGESTIONS + 1 ];
9652- for (int i = 0 ; i < MAX_NUMBER_SUGGESTIONS + 1 ; i ++) {
9652+ // Inflate the suggestion items once and for all. + 2 for add to dictionary and delete
9653+ mSuggestionInfos = new SuggestionInfo [MAX_NUMBER_SUGGESTIONS + 2 ];
9654+ for (int i = 0 ; i < mSuggestionInfos . length ; i ++) {
96539655 mSuggestionInfos [i ] = new SuggestionInfo ();
96549656 }
96559657 }
@@ -9700,7 +9702,19 @@ public View getView(int position, View convertView, ViewGroup parent) {
97009702 false );
97019703 }
97029704
9703- textView .setText (mSuggestionInfos [position ].text );
9705+ final SuggestionInfo suggestionInfo = mSuggestionInfos [position ];
9706+ textView .setText (suggestionInfo .text );
9707+
9708+ if (suggestionInfo .suggestionIndex == ADD_TO_DICTIONARY ) {
9709+ textView .setCompoundDrawablesWithIntrinsicBounds (
9710+ com .android .internal .R .drawable .ic_suggestions_add , 0 , 0 , 0 );
9711+ } else if (suggestionInfo .suggestionIndex == DELETE_TEXT ) {
9712+ textView .setCompoundDrawablesWithIntrinsicBounds (
9713+ com .android .internal .R .drawable .ic_suggestions_delete , 0 , 0 , 0 );
9714+ } else {
9715+ textView .setCompoundDrawables (null , null , null , null );
9716+ }
9717+
97049718 return textView ;
97059719 }
97069720 }
@@ -9751,11 +9765,10 @@ private SuggestionSpan[] getSuggestionSpans() {
97519765 public void show () {
97529766 if (!(mText instanceof Editable )) return ;
97539767
9754- if (updateSuggestions ()) {
9755- mCursorWasVisibleBeforeSuggestions = mCursorVisible ;
9756- setCursorVisible (false );
9757- super .show ();
9758- }
9768+ updateSuggestions ();
9769+ mCursorWasVisibleBeforeSuggestions = mCursorVisible ;
9770+ setCursorVisible (false );
9771+ super .show ();
97599772 }
97609773
97619774 @ Override
@@ -9810,7 +9823,7 @@ public void hide() {
98109823 super .hide ();
98119824 }
98129825
9813- private boolean updateSuggestions () {
9826+ private void updateSuggestions () {
98149827 Spannable spannable = (Spannable ) TextView .this .mText ;
98159828 SuggestionSpan [] suggestionSpans = getSuggestionSpans ();
98169829
@@ -9859,21 +9872,28 @@ private boolean updateSuggestions() {
98599872 highlightTextDifferences (mSuggestionInfos [i ], spanUnionStart , spanUnionEnd );
98609873 }
98619874
9875+ // Add to dictionary item is there a span with the misspelled flag
98629876 if (misspelledSpan != null ) {
98639877 final int misspelledStart = spannable .getSpanStart (misspelledSpan );
98649878 final int misspelledEnd = spannable .getSpanEnd (misspelledSpan );
98659879 if (misspelledStart >= 0 && misspelledEnd > misspelledStart ) {
98669880 SuggestionInfo suggestionInfo = mSuggestionInfos [mNumberOfSuggestions ];
98679881 suggestionInfo .suggestionSpan = misspelledSpan ;
9868- suggestionInfo .suggestionIndex = - 1 ;
9882+ suggestionInfo .suggestionIndex = ADD_TO_DICTIONARY ;
98699883 suggestionInfo .text .replace (0 , suggestionInfo .text .length (),
98709884 getContext ().getString (com .android .internal .R .string .addToDictionary ));
98719885
98729886 mNumberOfSuggestions ++;
98739887 }
98749888 }
98759889
9876- if (mNumberOfSuggestions == 0 ) return false ;
9890+ // Delete item
9891+ SuggestionInfo suggestionInfo = mSuggestionInfos [mNumberOfSuggestions ];
9892+ suggestionInfo .suggestionSpan = null ;
9893+ suggestionInfo .suggestionIndex = DELETE_TEXT ;
9894+ suggestionInfo .text .replace (0 , suggestionInfo .text .length (),
9895+ getContext ().getString (com .android .internal .R .string .deleteText ));
9896+ mNumberOfSuggestions ++;
98779897
98789898 if (mSuggestionRangeSpan == null ) mSuggestionRangeSpan = new SuggestionRangeSpan ();
98799899 if (underlineColor == 0 ) {
@@ -9889,8 +9909,6 @@ private boolean updateSuggestions() {
98899909 Spanned .SPAN_EXCLUSIVE_EXCLUSIVE );
98909910
98919911 mSuggestionsAdapter .notifyDataSetChanged ();
9892-
9893- return true ;
98949912 }
98959913
98969914 private void highlightTextDifferences (SuggestionInfo suggestionInfo , int unionStart ,
@@ -9915,77 +9933,94 @@ private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionSt
99159933
99169934 @ Override
99179935 public void onItemClick (AdapterView <?> parent , View view , int position , long id ) {
9918- hide ();
9919-
9920- if (view instanceof TextView ) {
9921- TextView textView = (TextView ) view ;
9922- Editable editable = (Editable ) mText ;
9923-
9924- SuggestionInfo suggestionInfo = mSuggestionInfos [position ];
9925- final int spanStart = editable .getSpanStart (suggestionInfo .suggestionSpan );
9926- final int spanEnd = editable .getSpanEnd (suggestionInfo .suggestionSpan );
9927- if (spanStart < 0 || spanEnd < 0 ) return ; // Span has been removed
9928- final String originalText = mText .subSequence (spanStart , spanEnd ).toString ();
9929-
9930- if (suggestionInfo .suggestionIndex < 0 ) {
9931- Intent intent = new Intent (Settings .ACTION_USER_DICTIONARY_INSERT );
9932- intent .putExtra ("word" , originalText );
9933- intent .setFlags (intent .getFlags () | Intent .FLAG_ACTIVITY_NEW_TASK );
9934- getContext ().startActivity (intent );
9935- suggestionInfo .removeMisspelledFlag ();
9936- } else {
9937- // SuggestionSpans are removed by replace: save them before
9938- SuggestionSpan [] suggestionSpans = editable .getSpans (spanStart , spanEnd ,
9939- SuggestionSpan .class );
9940- final int length = suggestionSpans .length ;
9941- int [] suggestionSpansStarts = new int [length ];
9942- int [] suggestionSpansEnds = new int [length ];
9943- int [] suggestionSpansFlags = new int [length ];
9944- for (int i = 0 ; i < length ; i ++) {
9945- final SuggestionSpan suggestionSpan = suggestionSpans [i ];
9946- suggestionSpansStarts [i ] = editable .getSpanStart (suggestionSpan );
9947- suggestionSpansEnds [i ] = editable .getSpanEnd (suggestionSpan );
9948- suggestionSpansFlags [i ] = editable .getSpanFlags (suggestionSpan );
9949- }
9936+ TextView textView = (TextView ) view ;
9937+ Editable editable = (Editable ) mText ;
99509938
9951- final int suggestionStart = suggestionInfo .suggestionStart ;
9952- final int suggestionEnd = suggestionInfo .suggestionEnd ;
9953- final String suggestion = textView .getText ().subSequence (
9954- suggestionStart , suggestionEnd ).toString ();
9955- editable .replace (spanStart , spanEnd , suggestion );
9939+ SuggestionInfo suggestionInfo = mSuggestionInfos [position ];
99569940
9957- suggestionInfo .removeMisspelledFlag ();
9941+ if (suggestionInfo .suggestionIndex == DELETE_TEXT ) {
9942+ final int spanUnionStart = editable .getSpanStart (mSuggestionRangeSpan );
9943+ int spanUnionEnd = editable .getSpanEnd (mSuggestionRangeSpan );
9944+ // Do not leave two adjacent spaces after deletion, or one at beginning of text
9945+ if (spanUnionEnd < editable .length () &&
9946+ Character .isSpaceChar (editable .charAt (spanUnionEnd )) &&
9947+ (spanUnionStart == 0 ||
9948+ Character .isSpaceChar (editable .charAt (spanUnionStart - 1 )))) {
9949+ spanUnionEnd = spanUnionEnd + 1 ;
9950+ }
9951+ editable .replace (spanUnionStart , spanUnionEnd , "" );
9952+ hide ();
9953+ return ;
9954+ }
99589955
9959- // Notify source IME of the suggestion pick. Do this before swaping texts.
9960- if (!TextUtils .isEmpty (
9961- suggestionInfo .suggestionSpan .getNotificationTargetClassName ())) {
9962- InputMethodManager imm = InputMethodManager .peekInstance ();
9963- imm .notifySuggestionPicked (suggestionInfo .suggestionSpan , originalText ,
9964- suggestionInfo .suggestionIndex );
9965- }
9956+ final int spanStart = editable .getSpanStart (suggestionInfo .suggestionSpan );
9957+ final int spanEnd = editable .getSpanEnd (suggestionInfo .suggestionSpan );
9958+ if (spanStart < 0 || spanEnd < 0 ) {
9959+ // Span has been removed
9960+ hide ();
9961+ return ;
9962+ }
9963+ final String originalText = mText .subSequence (spanStart , spanEnd ).toString ();
99669964
9967- // Swap text content between actual text and Suggestion span
9968- String [] suggestions = suggestionInfo .suggestionSpan .getSuggestions ();
9969- suggestions [suggestionInfo .suggestionIndex ] = originalText ;
9970-
9971- // Restore previous SuggestionSpans
9972- final int lengthDifference = suggestion .length () - (spanEnd - spanStart );
9973- for (int i = 0 ; i < length ; i ++) {
9974- // Only spans that include the modified region make sense after replacement
9975- // Spans partially included in the replaced region are removed, there is no
9976- // way to assign them a valid range after replacement
9977- if (suggestionSpansStarts [i ] <= spanStart &&
9978- suggestionSpansEnds [i ] >= spanEnd ) {
9979- editable .setSpan (suggestionSpans [i ], suggestionSpansStarts [i ],
9980- suggestionSpansEnds [i ] + lengthDifference ,
9981- suggestionSpansFlags [i ]);
9982- }
9965+ if (suggestionInfo .suggestionIndex == ADD_TO_DICTIONARY ) {
9966+ Intent intent = new Intent (Settings .ACTION_USER_DICTIONARY_INSERT );
9967+ intent .putExtra ("word" , originalText );
9968+ intent .setFlags (intent .getFlags () | Intent .FLAG_ACTIVITY_NEW_TASK );
9969+ getContext ().startActivity (intent );
9970+ suggestionInfo .removeMisspelledFlag ();
9971+ } else {
9972+ // SuggestionSpans are removed by replace: save them before
9973+ SuggestionSpan [] suggestionSpans = editable .getSpans (spanStart , spanEnd ,
9974+ SuggestionSpan .class );
9975+ final int length = suggestionSpans .length ;
9976+ int [] suggestionSpansStarts = new int [length ];
9977+ int [] suggestionSpansEnds = new int [length ];
9978+ int [] suggestionSpansFlags = new int [length ];
9979+ for (int i = 0 ; i < length ; i ++) {
9980+ final SuggestionSpan suggestionSpan = suggestionSpans [i ];
9981+ suggestionSpansStarts [i ] = editable .getSpanStart (suggestionSpan );
9982+ suggestionSpansEnds [i ] = editable .getSpanEnd (suggestionSpan );
9983+ suggestionSpansFlags [i ] = editable .getSpanFlags (suggestionSpan );
9984+ }
9985+
9986+ final int suggestionStart = suggestionInfo .suggestionStart ;
9987+ final int suggestionEnd = suggestionInfo .suggestionEnd ;
9988+ final String suggestion = textView .getText ().subSequence (
9989+ suggestionStart , suggestionEnd ).toString ();
9990+ editable .replace (spanStart , spanEnd , suggestion );
9991+
9992+ suggestionInfo .removeMisspelledFlag ();
9993+
9994+ // Notify source IME of the suggestion pick. Do this before swaping texts.
9995+ if (!TextUtils .isEmpty (
9996+ suggestionInfo .suggestionSpan .getNotificationTargetClassName ())) {
9997+ InputMethodManager imm = InputMethodManager .peekInstance ();
9998+ imm .notifySuggestionPicked (suggestionInfo .suggestionSpan , originalText ,
9999+ suggestionInfo .suggestionIndex );
10000+ }
10001+
10002+ // Swap text content between actual text and Suggestion span
10003+ String [] suggestions = suggestionInfo .suggestionSpan .getSuggestions ();
10004+ suggestions [suggestionInfo .suggestionIndex ] = originalText ;
10005+
10006+ // Restore previous SuggestionSpans
10007+ final int lengthDifference = suggestion .length () - (spanEnd - spanStart );
10008+ for (int i = 0 ; i < length ; i ++) {
10009+ // Only spans that include the modified region make sense after replacement
10010+ // Spans partially included in the replaced region are removed, there is no
10011+ // way to assign them a valid range after replacement
10012+ if (suggestionSpansStarts [i ] <= spanStart &&
10013+ suggestionSpansEnds [i ] >= spanEnd ) {
10014+ editable .setSpan (suggestionSpans [i ], suggestionSpansStarts [i ],
10015+ suggestionSpansEnds [i ] + lengthDifference , suggestionSpansFlags [i ]);
998310016 }
9984-
9985- // Move cursor at the end of the replacement word
9986- Selection .setSelection (editable , spanEnd + lengthDifference );
998710017 }
10018+
10019+ // Move cursor at the end of the replacement word
10020+ Selection .setSelection (editable , spanEnd + lengthDifference );
998810021 }
10022+
10023+ hide ();
998910024 }
999010025 }
999110026
0 commit comments