4747import android .text .Spanned ;
4848import android .text .StaticLayout ;
4949import android .text .TextUtils ;
50- import android .text .TextWatcher ;
5150import android .text .method .KeyListener ;
5251import android .text .method .MetaKeyKeyListener ;
5352import android .text .method .MovementMethod ;
@@ -184,8 +183,6 @@ public class Editor {
184183
185184 Editor (TextView textView ) {
186185 mTextView = textView ;
187- mEasyEditSpanController = new EasyEditSpanController ();
188- mTextView .addTextChangedListener (mEasyEditSpanController );
189186 }
190187
191188 void onAttachedToWindow () {
@@ -1121,7 +1118,7 @@ boolean reportExtractedText() {
11211118 if (contentChanged || ims .mSelectionModeChanged ) {
11221119 ims .mContentChanged = false ;
11231120 ims .mSelectionModeChanged = false ;
1124- final ExtractedTextRequest req = ims .mExtracting ;
1121+ final ExtractedTextRequest req = ims .mExtractedTextRequest ;
11251122 if (req != null ) {
11261123 InputMethodManager imm = InputMethodManager .peekInstance ();
11271124 if (imm != null ) {
@@ -1133,13 +1130,14 @@ boolean reportExtractedText() {
11331130 ims .mChangedStart = EXTRACT_NOTHING ;
11341131 }
11351132 if (extractTextInternal (req , ims .mChangedStart , ims .mChangedEnd ,
1136- ims .mChangedDelta , ims .mTmpExtracted )) {
1133+ ims .mChangedDelta , ims .mExtractedText )) {
11371134 if (TextView .DEBUG_EXTRACT ) Log .v (TextView .LOG_TAG ,
11381135 "Reporting extracted start=" +
1139- ims .mTmpExtracted .partialStartOffset +
1140- " end=" + ims .mTmpExtracted .partialEndOffset +
1141- ": " + ims .mTmpExtracted .text );
1142- imm .updateExtractedText (mTextView , req .token , ims .mTmpExtracted );
1136+ ims .mExtractedText .partialStartOffset +
1137+ " end=" + ims .mExtractedText .partialEndOffset +
1138+ ": " + ims .mExtractedText .text );
1139+
1140+ imm .updateExtractedText (mTextView , req .token , ims .mExtractedText );
11431141 ims .mChangedStart = EXTRACT_UNKNOWN ;
11441142 ims .mChangedEnd = EXTRACT_UNKNOWN ;
11451143 ims .mChangedDelta = 0 ;
@@ -1775,138 +1773,92 @@ void onDrop(DragEvent event) {
17751773 }
17761774 }
17771775
1776+ public void addSpanWatchers (Spannable text ) {
1777+ final int textLength = text .length ();
1778+
1779+ if (mKeyListener != null ) {
1780+ text .setSpan (mKeyListener , 0 , textLength , Spanned .SPAN_INCLUSIVE_INCLUSIVE );
1781+ }
1782+
1783+ if (mEasyEditSpanController == null ) {
1784+ mEasyEditSpanController = new EasyEditSpanController ();
1785+ }
1786+ text .setSpan (mEasyEditSpanController , 0 , textLength , Spanned .SPAN_INCLUSIVE_INCLUSIVE );
1787+ }
1788+
17781789 /**
17791790 * Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
17801791 * pop-up should be displayed.
17811792 */
1782- class EasyEditSpanController implements TextWatcher {
1793+ class EasyEditSpanController implements SpanWatcher {
17831794
17841795 private static final int DISPLAY_TIMEOUT_MS = 3000 ; // 3 secs
17851796
17861797 private EasyEditPopupWindow mPopupWindow ;
17871798
1788- private EasyEditSpan mEasyEditSpan ;
1789-
17901799 private Runnable mHidePopup ;
17911800
1792- public void hide () {
1793- if (mPopupWindow != null ) {
1794- mPopupWindow .hide ();
1795- mTextView .removeCallbacks (mHidePopup );
1796- }
1797- removeSpans (mTextView .getText ());
1798- mEasyEditSpan = null ;
1799- }
1800-
1801- public void beforeTextChanged (CharSequence s , int start , int count , int after ) {
1802- // Intentionally empty
1803- }
1804-
1805- public void afterTextChanged (Editable s ) {
1806- // Intentionally empty
1807- }
1801+ @ Override
1802+ public void onSpanAdded (Spannable text , Object span , int start , int end ) {
1803+ if (span instanceof EasyEditSpan ) {
1804+ if (mPopupWindow == null ) {
1805+ mPopupWindow = new EasyEditPopupWindow ();
1806+ mHidePopup = new Runnable () {
1807+ @ Override
1808+ public void run () {
1809+ hide ();
1810+ }
1811+ };
1812+ }
18081813
1809- /**
1810- * Monitors the changes in the text.
1811- *
1812- * <p>{@link SpanWatcher#onSpanAdded(Spannable, Object, int, int)} cannot be used,
1813- * as the notifications are not sent when a spannable (with spans) is inserted.
1814- */
1815- public void onTextChanged (CharSequence buffer , int start , int before , int after ) {
1816- adjustSpans (buffer , start , after );
1814+ // Make sure there is only at most one EasyEditSpan in the text
1815+ if (mPopupWindow .mEasyEditSpan != null ) {
1816+ text .removeSpan (mPopupWindow .mEasyEditSpan );
1817+ }
18171818
1818- if (mTextView .getWindowVisibility () != View .VISIBLE ) {
1819- // The window is not visible yet, ignore the text change.
1820- return ;
1821- }
1819+ mPopupWindow .setEasyEditSpan ((EasyEditSpan ) span );
18221820
1823- if (mTextView .getLayout () == null ) {
1824- // The view has not been layout yet, ignore the text change
1825- return ;
1826- }
1827-
1828- InputMethodManager imm = InputMethodManager .peekInstance ();
1829- if (!(mTextView instanceof ExtractEditText ) && imm != null && imm .isFullscreenMode ()) {
1830- // The input is in extract mode. We do not have to handle the easy edit in the
1831- // original TextView, as the ExtractEditText will do
1832- return ;
1833- }
1821+ if (mTextView .getWindowVisibility () != View .VISIBLE ) {
1822+ // The window is not visible yet, ignore the text change.
1823+ return ;
1824+ }
18341825
1835- // Remove the current easy edit span, as the text changed, and remove the pop-up
1836- // (if any)
1837- if (mEasyEditSpan != null ) {
1838- if (buffer instanceof Spannable ) {
1839- ((Spannable ) buffer ).removeSpan (mEasyEditSpan );
1826+ if (mTextView .getLayout () == null ) {
1827+ // The view has not been laid out yet, ignore the text change
1828+ return ;
18401829 }
1841- mEasyEditSpan = null ;
1842- }
1843- if (mPopupWindow != null && mPopupWindow .isShowing ()) {
1844- mPopupWindow .hide ();
1845- }
18461830
1847- // Display the new easy edit span (if any).
1848- if (buffer instanceof Spanned ) {
1849- mEasyEditSpan = getSpan ((Spanned ) buffer );
1850- if (mEasyEditSpan != null ) {
1851- if (mPopupWindow == null ) {
1852- mPopupWindow = new EasyEditPopupWindow ();
1853- mHidePopup = new Runnable () {
1854- @ Override
1855- public void run () {
1856- hide ();
1857- }
1858- };
1859- }
1860- mPopupWindow .show (mEasyEditSpan );
1861- mTextView .removeCallbacks (mHidePopup );
1862- mTextView .postDelayed (mHidePopup , DISPLAY_TIMEOUT_MS );
1831+ if (extractedTextModeWillBeStarted ()) {
1832+ // The input is in extract mode. Do not handle the easy edit in
1833+ // the original TextView, as the ExtractEditText will do
1834+ return ;
18631835 }
1836+
1837+ mPopupWindow .show ();
1838+ mTextView .removeCallbacks (mHidePopup );
1839+ mTextView .postDelayed (mHidePopup , DISPLAY_TIMEOUT_MS );
18641840 }
18651841 }
18661842
1867- /**
1868- * Adjusts the spans by removing all of them except the last one.
1869- */
1870- private void adjustSpans (CharSequence buffer , int start , int after ) {
1871- // This method enforces that only one easy edit span is attached to the text.
1872- // A better way to enforce this would be to listen for onSpanAdded, but this method
1873- // cannot be used in this scenario as no notification is triggered when a text with
1874- // spans is inserted into a text.
1875- if (buffer instanceof Spannable ) {
1876- Spannable spannable = (Spannable ) buffer ;
1877- EasyEditSpan [] spans = spannable .getSpans (start , start + after , EasyEditSpan .class );
1878- if (spans .length > 0 ) {
1879- // Assuming there was only one EasyEditSpan before, we only need check to
1880- // check for a duplicate if a new one is found in the modified interval
1881- spans = spannable .getSpans (0 , spannable .length (), EasyEditSpan .class );
1882- for (int i = 1 ; i < spans .length ; i ++) {
1883- spannable .removeSpan (spans [i ]);
1884- }
1885- }
1843+ @ Override
1844+ public void onSpanRemoved (Spannable text , Object span , int start , int end ) {
1845+ if (mPopupWindow != null && span == mPopupWindow .mEasyEditSpan ) {
1846+ hide ();
18861847 }
18871848 }
18881849
1889- /**
1890- * Removes all the {@link EasyEditSpan} currently attached.
1891- */
1892- private void removeSpans (CharSequence buffer ) {
1893- if (buffer instanceof Spannable ) {
1894- Spannable spannable = (Spannable ) buffer ;
1895- EasyEditSpan [] spans = spannable .getSpans (0 , spannable .length (),
1896- EasyEditSpan .class );
1897- for (int i = 0 ; i < spans .length ; i ++) {
1898- spannable .removeSpan (spans [i ]);
1899- }
1850+ @ Override
1851+ public void onSpanChanged (Spannable text , Object span , int previousStart , int previousEnd ,
1852+ int newStart , int newEnd ) {
1853+ if (mPopupWindow != null && span == mPopupWindow .mEasyEditSpan ) {
1854+ text .removeSpan (mPopupWindow .mEasyEditSpan );
19001855 }
19011856 }
19021857
1903- private EasyEditSpan getSpan (Spanned spanned ) {
1904- EasyEditSpan [] easyEditSpans = spanned .getSpans (0 , spanned .length (),
1905- EasyEditSpan .class );
1906- if (easyEditSpans .length == 0 ) {
1907- return null ;
1908- } else {
1909- return easyEditSpans [0 ];
1858+ public void hide () {
1859+ if (mPopupWindow != null ) {
1860+ mPopupWindow .hide ();
1861+ mTextView .removeCallbacks (mHidePopup );
19101862 }
19111863 }
19121864 }
@@ -1951,9 +1903,8 @@ protected void initContentView() {
19511903 mContentView .addView (mDeleteTextView );
19521904 }
19531905
1954- public void show (EasyEditSpan easyEditSpan ) {
1906+ public void setEasyEditSpan (EasyEditSpan easyEditSpan ) {
19551907 mEasyEditSpan = easyEditSpan ;
1956- super .show ();
19571908 }
19581909
19591910 @ Override
@@ -3780,8 +3731,8 @@ static class InputMethodState {
37803731 Rect mCursorRectInWindow = new Rect ();
37813732 RectF mTmpRectF = new RectF ();
37823733 float [] mTmpOffset = new float [2 ];
3783- ExtractedTextRequest mExtracting ;
3784- final ExtractedText mTmpExtracted = new ExtractedText ();
3734+ ExtractedTextRequest mExtractedTextRequest ;
3735+ final ExtractedText mExtractedText = new ExtractedText ();
37853736 int mBatchEditNesting ;
37863737 boolean mCursorChanged ;
37873738 boolean mSelectionModeChanged ;
0 commit comments