@@ -9613,6 +9613,8 @@ public boolean isShowing() {
96139613
96149614 private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
96159615 private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan .SUGGESTIONS_MAX_SIZE ;
9616+ private static final int ADD_TO_DICTIONARY = -1 ;
9617+ private static final int DELETE_TEXT = -2 ;
96169618 private SuggestionInfo [] mSuggestionInfos ;
96179619 private int mNumberOfSuggestions ;
96189620 private boolean mCursorWasVisibleBeforeSuggestions ;
@@ -9664,9 +9666,9 @@ protected void initContentView() {
96649666 listView .setOnItemClickListener (this );
96659667 mContentView = listView ;
96669668
9667- // Inflate the suggestion items once and for all. +1 for add to dictionary
9668- mSuggestionInfos = new SuggestionInfo [MAX_NUMBER_SUGGESTIONS + 1 ];
9669- for (int i = 0 ; i < MAX_NUMBER_SUGGESTIONS + 1 ; i ++) {
9669+ // Inflate the suggestion items once and for all. + 2 for add to dictionary and delete
9670+ mSuggestionInfos = new SuggestionInfo [MAX_NUMBER_SUGGESTIONS + 2 ];
9671+ for (int i = 0 ; i < mSuggestionInfos . length ; i ++) {
96709672 mSuggestionInfos [i ] = new SuggestionInfo ();
96719673 }
96729674 }
@@ -9717,7 +9719,19 @@ public View getView(int position, View convertView, ViewGroup parent) {
97179719 false );
97189720 }
97199721
9720- textView .setText (mSuggestionInfos [position ].text );
9722+ final SuggestionInfo suggestionInfo = mSuggestionInfos [position ];
9723+ textView .setText (suggestionInfo .text );
9724+
9725+ if (suggestionInfo .suggestionIndex == ADD_TO_DICTIONARY ) {
9726+ textView .setCompoundDrawablesWithIntrinsicBounds (
9727+ com .android .internal .R .drawable .ic_suggestions_add , 0 , 0 , 0 );
9728+ } else if (suggestionInfo .suggestionIndex == DELETE_TEXT ) {
9729+ textView .setCompoundDrawablesWithIntrinsicBounds (
9730+ com .android .internal .R .drawable .ic_suggestions_delete , 0 , 0 , 0 );
9731+ } else {
9732+ textView .setCompoundDrawables (null , null , null , null );
9733+ }
9734+
97219735 return textView ;
97229736 }
97239737 }
@@ -9768,11 +9782,10 @@ private SuggestionSpan[] getSuggestionSpans() {
97689782 public void show () {
97699783 if (!(mText instanceof Editable )) return ;
97709784
9771- if (updateSuggestions ()) {
9772- mCursorWasVisibleBeforeSuggestions = mCursorVisible ;
9773- setCursorVisible (false );
9774- super .show ();
9775- }
9785+ updateSuggestions ();
9786+ mCursorWasVisibleBeforeSuggestions = mCursorVisible ;
9787+ setCursorVisible (false );
9788+ super .show ();
97769789 }
97779790
97789791 @ Override
@@ -9828,7 +9841,7 @@ public void hide() {
98289841 super .hide ();
98299842 }
98309843
9831- private boolean updateSuggestions () {
9844+ private void updateSuggestions () {
98329845 Spannable spannable = (Spannable ) TextView .this .mText ;
98339846 SuggestionSpan [] suggestionSpans = getSuggestionSpans ();
98349847
@@ -9877,21 +9890,28 @@ private boolean updateSuggestions() {
98779890 highlightTextDifferences (mSuggestionInfos [i ], spanUnionStart , spanUnionEnd );
98789891 }
98799892
9893+ // Add to dictionary item is there a span with the misspelled flag
98809894 if (misspelledSpan != null ) {
98819895 final int misspelledStart = spannable .getSpanStart (misspelledSpan );
98829896 final int misspelledEnd = spannable .getSpanEnd (misspelledSpan );
98839897 if (misspelledStart >= 0 && misspelledEnd > misspelledStart ) {
98849898 SuggestionInfo suggestionInfo = mSuggestionInfos [mNumberOfSuggestions ];
98859899 suggestionInfo .suggestionSpan = misspelledSpan ;
9886- suggestionInfo .suggestionIndex = - 1 ;
9900+ suggestionInfo .suggestionIndex = ADD_TO_DICTIONARY ;
98879901 suggestionInfo .text .replace (0 , suggestionInfo .text .length (),
98889902 getContext ().getString (com .android .internal .R .string .addToDictionary ));
98899903
98909904 mNumberOfSuggestions ++;
98919905 }
98929906 }
98939907
9894- if (mNumberOfSuggestions == 0 ) return false ;
9908+ // Delete item
9909+ SuggestionInfo suggestionInfo = mSuggestionInfos [mNumberOfSuggestions ];
9910+ suggestionInfo .suggestionSpan = null ;
9911+ suggestionInfo .suggestionIndex = DELETE_TEXT ;
9912+ suggestionInfo .text .replace (0 , suggestionInfo .text .length (),
9913+ getContext ().getString (com .android .internal .R .string .deleteText ));
9914+ mNumberOfSuggestions ++;
98959915
98969916 if (mSuggestionRangeSpan == null ) mSuggestionRangeSpan = new SuggestionRangeSpan ();
98979917 if (underlineColor == 0 ) {
@@ -9907,8 +9927,6 @@ private boolean updateSuggestions() {
99079927 Spanned .SPAN_EXCLUSIVE_EXCLUSIVE );
99089928
99099929 mSuggestionsAdapter .notifyDataSetChanged ();
9910-
9911- return true ;
99129930 }
99139931
99149932 private void highlightTextDifferences (SuggestionInfo suggestionInfo , int unionStart ,
@@ -9933,77 +9951,94 @@ private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionSt
99339951
99349952 @ Override
99359953 public void onItemClick (AdapterView <?> parent , View view , int position , long id ) {
9936- hide ();
9937-
9938- if (view instanceof TextView ) {
9939- TextView textView = (TextView ) view ;
9940- Editable editable = (Editable ) mText ;
9941-
9942- SuggestionInfo suggestionInfo = mSuggestionInfos [position ];
9943- final int spanStart = editable .getSpanStart (suggestionInfo .suggestionSpan );
9944- final int spanEnd = editable .getSpanEnd (suggestionInfo .suggestionSpan );
9945- if (spanStart < 0 || spanEnd < 0 ) return ; // Span has been removed
9946- final String originalText = mText .subSequence (spanStart , spanEnd ).toString ();
9947-
9948- if (suggestionInfo .suggestionIndex < 0 ) {
9949- Intent intent = new Intent (Settings .ACTION_USER_DICTIONARY_INSERT );
9950- intent .putExtra ("word" , originalText );
9951- intent .setFlags (intent .getFlags () | Intent .FLAG_ACTIVITY_NEW_TASK );
9952- getContext ().startActivity (intent );
9953- suggestionInfo .removeMisspelledFlag ();
9954- } else {
9955- // SuggestionSpans are removed by replace: save them before
9956- SuggestionSpan [] suggestionSpans = editable .getSpans (spanStart , spanEnd ,
9957- SuggestionSpan .class );
9958- final int length = suggestionSpans .length ;
9959- int [] suggestionSpansStarts = new int [length ];
9960- int [] suggestionSpansEnds = new int [length ];
9961- int [] suggestionSpansFlags = new int [length ];
9962- for (int i = 0 ; i < length ; i ++) {
9963- final SuggestionSpan suggestionSpan = suggestionSpans [i ];
9964- suggestionSpansStarts [i ] = editable .getSpanStart (suggestionSpan );
9965- suggestionSpansEnds [i ] = editable .getSpanEnd (suggestionSpan );
9966- suggestionSpansFlags [i ] = editable .getSpanFlags (suggestionSpan );
9967- }
9954+ TextView textView = (TextView ) view ;
9955+ Editable editable = (Editable ) mText ;
99689956
9969- final int suggestionStart = suggestionInfo .suggestionStart ;
9970- final int suggestionEnd = suggestionInfo .suggestionEnd ;
9971- final String suggestion = textView .getText ().subSequence (
9972- suggestionStart , suggestionEnd ).toString ();
9973- editable .replace (spanStart , spanEnd , suggestion );
9957+ SuggestionInfo suggestionInfo = mSuggestionInfos [position ];
99749958
9975- suggestionInfo .removeMisspelledFlag ();
9959+ if (suggestionInfo .suggestionIndex == DELETE_TEXT ) {
9960+ final int spanUnionStart = editable .getSpanStart (mSuggestionRangeSpan );
9961+ int spanUnionEnd = editable .getSpanEnd (mSuggestionRangeSpan );
9962+ // Do not leave two adjacent spaces after deletion, or one at beginning of text
9963+ if (spanUnionEnd < editable .length () &&
9964+ Character .isSpaceChar (editable .charAt (spanUnionEnd )) &&
9965+ (spanUnionStart == 0 ||
9966+ Character .isSpaceChar (editable .charAt (spanUnionStart - 1 )))) {
9967+ spanUnionEnd = spanUnionEnd + 1 ;
9968+ }
9969+ editable .replace (spanUnionStart , spanUnionEnd , "" );
9970+ hide ();
9971+ return ;
9972+ }
99769973
9977- // Notify source IME of the suggestion pick. Do this before swaping texts.
9978- if (!TextUtils .isEmpty (
9979- suggestionInfo .suggestionSpan .getNotificationTargetClassName ())) {
9980- InputMethodManager imm = InputMethodManager .peekInstance ();
9981- imm .notifySuggestionPicked (suggestionInfo .suggestionSpan , originalText ,
9982- suggestionInfo .suggestionIndex );
9983- }
9974+ final int spanStart = editable .getSpanStart (suggestionInfo .suggestionSpan );
9975+ final int spanEnd = editable .getSpanEnd (suggestionInfo .suggestionSpan );
9976+ if (spanStart < 0 || spanEnd < 0 ) {
9977+ // Span has been removed
9978+ hide ();
9979+ return ;
9980+ }
9981+ final String originalText = mText .subSequence (spanStart , spanEnd ).toString ();
99849982
9985- // Swap text content between actual text and Suggestion span
9986- String [] suggestions = suggestionInfo .suggestionSpan .getSuggestions ();
9987- suggestions [suggestionInfo .suggestionIndex ] = originalText ;
9988-
9989- // Restore previous SuggestionSpans
9990- final int lengthDifference = suggestion .length () - (spanEnd - spanStart );
9991- for (int i = 0 ; i < length ; i ++) {
9992- // Only spans that include the modified region make sense after replacement
9993- // Spans partially included in the replaced region are removed, there is no
9994- // way to assign them a valid range after replacement
9995- if (suggestionSpansStarts [i ] <= spanStart &&
9996- suggestionSpansEnds [i ] >= spanEnd ) {
9997- editable .setSpan (suggestionSpans [i ], suggestionSpansStarts [i ],
9998- suggestionSpansEnds [i ] + lengthDifference ,
9999- suggestionSpansFlags [i ]);
10000- }
9983+ if (suggestionInfo .suggestionIndex == ADD_TO_DICTIONARY ) {
9984+ Intent intent = new Intent (Settings .ACTION_USER_DICTIONARY_INSERT );
9985+ intent .putExtra ("word" , originalText );
9986+ intent .setFlags (intent .getFlags () | Intent .FLAG_ACTIVITY_NEW_TASK );
9987+ getContext ().startActivity (intent );
9988+ suggestionInfo .removeMisspelledFlag ();
9989+ } else {
9990+ // SuggestionSpans are removed by replace: save them before
9991+ SuggestionSpan [] suggestionSpans = editable .getSpans (spanStart , spanEnd ,
9992+ SuggestionSpan .class );
9993+ final int length = suggestionSpans .length ;
9994+ int [] suggestionSpansStarts = new int [length ];
9995+ int [] suggestionSpansEnds = new int [length ];
9996+ int [] suggestionSpansFlags = new int [length ];
9997+ for (int i = 0 ; i < length ; i ++) {
9998+ final SuggestionSpan suggestionSpan = suggestionSpans [i ];
9999+ suggestionSpansStarts [i ] = editable .getSpanStart (suggestionSpan );
10000+ suggestionSpansEnds [i ] = editable .getSpanEnd (suggestionSpan );
10001+ suggestionSpansFlags [i ] = editable .getSpanFlags (suggestionSpan );
10002+ }
10003+
10004+ final int suggestionStart = suggestionInfo .suggestionStart ;
10005+ final int suggestionEnd = suggestionInfo .suggestionEnd ;
10006+ final String suggestion = textView .getText ().subSequence (
10007+ suggestionStart , suggestionEnd ).toString ();
10008+ editable .replace (spanStart , spanEnd , suggestion );
10009+
10010+ suggestionInfo .removeMisspelledFlag ();
10011+
10012+ // Notify source IME of the suggestion pick. Do this before swaping texts.
10013+ if (!TextUtils .isEmpty (
10014+ suggestionInfo .suggestionSpan .getNotificationTargetClassName ())) {
10015+ InputMethodManager imm = InputMethodManager .peekInstance ();
10016+ imm .notifySuggestionPicked (suggestionInfo .suggestionSpan , originalText ,
10017+ suggestionInfo .suggestionIndex );
10018+ }
10019+
10020+ // Swap text content between actual text and Suggestion span
10021+ String [] suggestions = suggestionInfo .suggestionSpan .getSuggestions ();
10022+ suggestions [suggestionInfo .suggestionIndex ] = originalText ;
10023+
10024+ // Restore previous SuggestionSpans
10025+ final int lengthDifference = suggestion .length () - (spanEnd - spanStart );
10026+ for (int i = 0 ; i < length ; i ++) {
10027+ // Only spans that include the modified region make sense after replacement
10028+ // Spans partially included in the replaced region are removed, there is no
10029+ // way to assign them a valid range after replacement
10030+ if (suggestionSpansStarts [i ] <= spanStart &&
10031+ suggestionSpansEnds [i ] >= spanEnd ) {
10032+ editable .setSpan (suggestionSpans [i ], suggestionSpansStarts [i ],
10033+ suggestionSpansEnds [i ] + lengthDifference , suggestionSpansFlags [i ]);
1000110034 }
10002-
10003- // Move cursor at the end of the replacement word
10004- Selection .setSelection (editable , spanEnd + lengthDifference );
1000510035 }
10036+
10037+ // Move cursor at the end of the replacement word
10038+ Selection .setSelection (editable , spanEnd + lengthDifference );
1000610039 }
10040+
10041+ hide ();
1000710042 }
1000810043 }
1000910044
0 commit comments