1 /*
2  * Copyright (C) 2008 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 android.widget.cts;
18 
19 import com.android.cts.widget.R;
20 
21 import org.xmlpull.v1.XmlPullParserException;
22 
23 import android.app.Activity;
24 import android.app.Instrumentation;
25 import android.app.Instrumentation.ActivityMonitor;
26 import android.content.Intent;
27 import android.content.res.ColorStateList;
28 import android.content.res.Resources.NotFoundException;
29 import android.cts.util.PollingCheck;
30 import android.cts.util.WidgetTestUtils;
31 import android.graphics.Bitmap;
32 import android.graphics.Color;
33 import android.graphics.Paint;
34 import android.graphics.Path;
35 import android.graphics.PorterDuff;
36 import android.graphics.Rect;
37 import android.graphics.RectF;
38 import android.graphics.Typeface;
39 import android.graphics.drawable.BitmapDrawable;
40 import android.graphics.drawable.Drawable;
41 import android.net.Uri;
42 import android.os.Bundle;
43 import android.os.Parcelable;
44 import android.test.ActivityInstrumentationTestCase2;
45 import android.test.MoreAsserts;
46 import android.test.TouchUtils;
47 import android.test.UiThreadTest;
48 import android.text.Editable;
49 import android.text.InputFilter;
50 import android.text.InputType;
51 import android.text.Layout;
52 import android.text.Selection;
53 import android.text.Spannable;
54 import android.text.SpannableString;
55 import android.text.TextPaint;
56 import android.text.TextUtils;
57 import android.text.TextUtils.TruncateAt;
58 import android.text.TextWatcher;
59 import android.text.method.ArrowKeyMovementMethod;
60 import android.text.method.DateKeyListener;
61 import android.text.method.DateTimeKeyListener;
62 import android.text.method.DialerKeyListener;
63 import android.text.method.DigitsKeyListener;
64 import android.text.method.KeyListener;
65 import android.text.method.LinkMovementMethod;
66 import android.text.method.MovementMethod;
67 import android.text.method.PasswordTransformationMethod;
68 import android.text.method.QwertyKeyListener;
69 import android.text.method.SingleLineTransformationMethod;
70 import android.text.method.TextKeyListener;
71 import android.text.method.TextKeyListener.Capitalize;
72 import android.text.method.TimeKeyListener;
73 import android.text.method.TransformationMethod;
74 import android.text.style.URLSpan;
75 import android.text.util.Linkify;
76 import android.util.DisplayMetrics;
77 import android.util.TypedValue;
78 import android.view.ContextMenu;
79 import android.view.ContextMenu.ContextMenuInfo;
80 import android.view.ActionMode;
81 import android.view.Gravity;
82 import android.view.KeyEvent;
83 import android.view.Menu;
84 import android.view.MenuItem;
85 import android.view.View;
86 import android.view.View.OnCreateContextMenuListener;
87 import android.view.View.OnLongClickListener;
88 import android.view.ViewGroup;
89 import android.view.accessibility.AccessibilityNodeInfo;
90 import android.view.inputmethod.BaseInputConnection;
91 import android.view.inputmethod.EditorInfo;
92 import android.view.inputmethod.ExtractedText;
93 import android.view.inputmethod.ExtractedTextRequest;
94 import android.view.inputmethod.InputConnection;
95 import android.widget.EditText;
96 import android.widget.FrameLayout;
97 import android.widget.LinearLayout;
98 import android.widget.Scroller;
99 import android.widget.TextView;
100 import android.widget.TextView.BufferType;
101 import android.widget.TextView.OnEditorActionListener;
102 
103 import java.io.IOException;
104 import java.util.Locale;
105 
106 /**
107  * Test {@link TextView}.
108  */
109 public class TextViewTest extends ActivityInstrumentationTestCase2<TextViewCtsActivity> {
110 
111     private TextView mTextView;
112     private Activity mActivity;
113     private Instrumentation mInstrumentation;
114     private static final String LONG_TEXT = "This is a really long string which exceeds "
115             + "the width of the view. New devices have a much larger screen which "
116             + "actually enables long strings to be displayed with no fading. "
117             + "I have made this string longer to fix this case. If you are correcting "
118             + "this text, I would love to see the kind of devices you guys now use!";
119     private static final long TIMEOUT = 5000;
120     private CharSequence mTransformedText;
121 
TextViewTest()122     public TextViewTest() {
123         super("com.android.cts.widget", TextViewCtsActivity.class);
124     }
125 
126     @Override
setUp()127     protected void setUp() throws Exception {
128         super.setUp();
129         mActivity = getActivity();
130         new PollingCheck() {
131             @Override
132                 protected boolean check() {
133                 return mActivity.hasWindowFocus();
134             }
135         }.run();
136         mInstrumentation = getInstrumentation();
137     }
138 
139     /**
140      * Promotes the TextView to editable and places focus in it to allow simulated typing.
141      */
initTextViewForTyping()142     private void initTextViewForTyping() {
143         mActivity.runOnUiThread(new Runnable() {
144             public void run() {
145                 mTextView = findTextView(R.id.textview_text);
146                 mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
147                 mTextView.setText("", BufferType.EDITABLE);
148                 mTextView.requestFocus();
149             }
150         });
151         mInstrumentation.waitForIdleSync();
152     }
153 
testConstructor()154     public void testConstructor() {
155         new TextView(mActivity);
156 
157         new TextView(mActivity, null);
158 
159         new TextView(mActivity, null, 0);
160     }
161 
162     @UiThreadTest
testAccessText()163     public void testAccessText() {
164         TextView tv = findTextView(R.id.textview_text);
165 
166         String expected = mActivity.getResources().getString(R.string.text_view_hello);
167         tv.setText(expected);
168         assertEquals(expected, tv.getText().toString());
169 
170         tv.setText(null);
171         assertEquals("", tv.getText().toString());
172     }
173 
testGetLineHeight()174     public void testGetLineHeight() {
175         mTextView = new TextView(mActivity);
176         assertTrue(mTextView.getLineHeight() > 0);
177 
178         mTextView.setLineSpacing(1.2f, 1.5f);
179         assertTrue(mTextView.getLineHeight() > 0);
180     }
181 
testGetLayout()182     public void testGetLayout() {
183         mActivity.runOnUiThread(new Runnable() {
184             public void run() {
185                 mTextView = findTextView(R.id.textview_text);
186                 mTextView.setGravity(Gravity.CENTER);
187             }
188         });
189         mInstrumentation.waitForIdleSync();
190         assertNotNull(mTextView.getLayout());
191 
192         TestLayoutRunnable runnable = new TestLayoutRunnable(mTextView) {
193             public void run() {
194                 // change the text of TextView.
195                 mTextView.setText("Hello, Android!");
196                 saveLayout();
197             }
198         };
199         mActivity.runOnUiThread(runnable);
200         mInstrumentation.waitForIdleSync();
201         assertNull(runnable.getLayout());
202         assertNotNull(mTextView.getLayout());
203     }
204 
testAccessKeyListener()205     public void testAccessKeyListener() {
206         mActivity.runOnUiThread(new Runnable() {
207             public void run() {
208                 mTextView = findTextView(R.id.textview_text);
209             }
210         });
211         mInstrumentation.waitForIdleSync();
212 
213         assertNull(mTextView.getKeyListener());
214 
215         final KeyListener digitsKeyListener = DigitsKeyListener.getInstance();
216 
217         mActivity.runOnUiThread(new Runnable() {
218             public void run() {
219                 mTextView.setKeyListener(digitsKeyListener);
220             }
221         });
222         mInstrumentation.waitForIdleSync();
223         assertSame(digitsKeyListener, mTextView.getKeyListener());
224 
225         final QwertyKeyListener qwertyKeyListener
226                 = QwertyKeyListener.getInstance(false, Capitalize.NONE);
227         mActivity.runOnUiThread(new Runnable() {
228             public void run() {
229                 mTextView.setKeyListener(qwertyKeyListener);
230             }
231         });
232         mInstrumentation.waitForIdleSync();
233         assertSame(qwertyKeyListener, mTextView.getKeyListener());
234     }
235 
testAccessMovementMethod()236     public void testAccessMovementMethod() {
237         final CharSequence LONG_TEXT = "Scrolls the specified widget to the specified "
238                 + "coordinates, except constrains the X scrolling position to the horizontal "
239                 + "regions of the text that will be visible after scrolling to "
240                 + "the specified Y position.";
241         final int selectionStart = 10;
242         final int selectionEnd = LONG_TEXT.length();
243         final MovementMethod movementMethod = ArrowKeyMovementMethod.getInstance();
244         mActivity.runOnUiThread(new Runnable() {
245             public void run() {
246                 mTextView = findTextView(R.id.textview_text);
247                 mTextView.setMovementMethod(movementMethod);
248                 mTextView.setText(LONG_TEXT, BufferType.EDITABLE);
249                 Selection.setSelection((Editable) mTextView.getText(),
250                         selectionStart, selectionEnd);
251                 mTextView.requestFocus();
252             }
253         });
254         mInstrumentation.waitForIdleSync();
255 
256         assertSame(movementMethod, mTextView.getMovementMethod());
257         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
258         assertEquals(selectionEnd, Selection.getSelectionEnd(mTextView.getText()));
259         sendKeys(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_ALT_LEFT,
260                 KeyEvent.KEYCODE_DPAD_UP);
261         // the selection has been removed.
262         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
263         assertEquals(selectionStart, Selection.getSelectionEnd(mTextView.getText()));
264 
265         mActivity.runOnUiThread(new Runnable() {
266             public void run() {
267                 mTextView.setMovementMethod(null);
268                 Selection.setSelection((Editable) mTextView.getText(),
269                         selectionStart, selectionEnd);
270                 mTextView.requestFocus();
271             }
272         });
273         mInstrumentation.waitForIdleSync();
274 
275         assertNull(mTextView.getMovementMethod());
276         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
277         assertEquals(selectionEnd, Selection.getSelectionEnd(mTextView.getText()));
278         sendKeys(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_ALT_LEFT,
279                 KeyEvent.KEYCODE_DPAD_UP);
280         // the selection will not be changed.
281         assertEquals(selectionStart, Selection.getSelectionStart(mTextView.getText()));
282         assertEquals(selectionEnd, Selection.getSelectionEnd(mTextView.getText()));
283     }
284 
285     @UiThreadTest
testLength()286     public void testLength() {
287         mTextView = findTextView(R.id.textview_text);
288 
289         String content = "This is content";
290         mTextView.setText(content);
291         assertEquals(content.length(), mTextView.length());
292 
293         mTextView.setText("");
294         assertEquals(0, mTextView.length());
295 
296         mTextView.setText(null);
297         assertEquals(0, mTextView.length());
298     }
299 
300     @UiThreadTest
testAccessGravity()301     public void testAccessGravity() {
302         mActivity.setContentView(R.layout.textview_gravity);
303 
304         mTextView = findTextView(R.id.gravity_default);
305         assertEquals(Gravity.TOP | Gravity.START, mTextView.getGravity());
306 
307         mTextView = findTextView(R.id.gravity_bottom);
308         assertEquals(Gravity.BOTTOM | Gravity.START, mTextView.getGravity());
309 
310         mTextView = findTextView(R.id.gravity_right);
311         assertEquals(Gravity.TOP | Gravity.RIGHT, mTextView.getGravity());
312 
313         mTextView = findTextView(R.id.gravity_center);
314         assertEquals(Gravity.CENTER, mTextView.getGravity());
315 
316         mTextView = findTextView(R.id.gravity_fill);
317         assertEquals(Gravity.FILL, mTextView.getGravity());
318 
319         mTextView = findTextView(R.id.gravity_center_vertical_right);
320         assertEquals(Gravity.CENTER_VERTICAL | Gravity.RIGHT, mTextView.getGravity());
321 
322         mTextView.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
323         assertEquals(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, mTextView.getGravity());
324         mTextView.setGravity(Gravity.FILL);
325         assertEquals(Gravity.FILL, mTextView.getGravity());
326         mTextView.setGravity(Gravity.CENTER);
327         assertEquals(Gravity.CENTER, mTextView.getGravity());
328 
329         mTextView.setGravity(Gravity.NO_GRAVITY);
330         assertEquals(Gravity.TOP | Gravity.START, mTextView.getGravity());
331 
332         mTextView.setGravity(Gravity.RIGHT);
333         assertEquals(Gravity.TOP | Gravity.RIGHT, mTextView.getGravity());
334 
335         mTextView.setGravity(Gravity.FILL_VERTICAL);
336         assertEquals(Gravity.FILL_VERTICAL | Gravity.START, mTextView.getGravity());
337 
338         //test negative input value.
339         mTextView.setGravity(-1);
340         assertEquals(-1, mTextView.getGravity());
341     }
342 
testAccessAutoLinkMask()343     public void testAccessAutoLinkMask() {
344         mTextView = findTextView(R.id.textview_text);
345         final CharSequence text1 =
346                 new SpannableString("URL: http://www.google.com. mailto: account@gmail.com");
347         mActivity.runOnUiThread(new Runnable() {
348             public void run() {
349                 mTextView.setAutoLinkMask(Linkify.ALL);
350                 mTextView.setText(text1, BufferType.EDITABLE);
351             }
352         });
353         mInstrumentation.waitForIdleSync();
354         assertEquals(Linkify.ALL, mTextView.getAutoLinkMask());
355 
356         Spannable spanString = (Spannable) mTextView.getText();
357         URLSpan[] spans = spanString.getSpans(0, spanString.length(), URLSpan.class);
358         assertNotNull(spans);
359         assertEquals(2, spans.length);
360         assertEquals("http://www.google.com", spans[0].getURL());
361         assertEquals("mailto:account@gmail.com", spans[1].getURL());
362 
363         final CharSequence text2 =
364             new SpannableString("name: Jack. tel: +41 44 800 8999");
365         mActivity.runOnUiThread(new Runnable() {
366             public void run() {
367                 mTextView.setAutoLinkMask(Linkify.PHONE_NUMBERS);
368                 mTextView.setText(text2, BufferType.EDITABLE);
369             }
370         });
371         mInstrumentation.waitForIdleSync();
372         assertEquals(Linkify.PHONE_NUMBERS, mTextView.getAutoLinkMask());
373 
374         spanString = (Spannable) mTextView.getText();
375         spans = spanString.getSpans(0, spanString.length(), URLSpan.class);
376         assertNotNull(spans);
377         assertEquals(1, spans.length);
378         assertEquals("tel:+41448008999", spans[0].getURL());
379 
380         layout(R.layout.textview_autolink);
381         // 1 for web, 2 for email, 4 for phone, 7 for all(web|email|phone)
382         assertEquals(0, getAutoLinkMask(R.id.autolink_default));
383         assertEquals(Linkify.WEB_URLS, getAutoLinkMask(R.id.autolink_web));
384         assertEquals(Linkify.EMAIL_ADDRESSES, getAutoLinkMask(R.id.autolink_email));
385         assertEquals(Linkify.PHONE_NUMBERS, getAutoLinkMask(R.id.autolink_phone));
386         assertEquals(Linkify.ALL, getAutoLinkMask(R.id.autolink_all));
387         assertEquals(Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES,
388                 getAutoLinkMask(R.id.autolink_compound1));
389         assertEquals(Linkify.WEB_URLS | Linkify.PHONE_NUMBERS,
390                 getAutoLinkMask(R.id.autolink_compound2));
391         assertEquals(Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS,
392                 getAutoLinkMask(R.id.autolink_compound3));
393         assertEquals(Linkify.PHONE_NUMBERS | Linkify.ALL,
394                 getAutoLinkMask(R.id.autolink_compound4));
395     }
396 
testAccessTextSize()397     public void testAccessTextSize() {
398         DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
399 
400         mTextView = new TextView(mActivity);
401         mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, 20f);
402         assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, 20f, metrics),
403                 mTextView.getTextSize(), 0.01f);
404 
405         mTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20f);
406         assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20f, metrics),
407                 mTextView.getTextSize(), 0.01f);
408 
409         mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20f);
410         assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20f, metrics),
411                 mTextView.getTextSize(), 0.01f);
412 
413         // setTextSize by default unit "sp"
414         mTextView.setTextSize(20f);
415         assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20f, metrics),
416                 mTextView.getTextSize(), 0.01f);
417 
418         mTextView.setTextSize(200f);
419         assertEquals(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 200f, metrics),
420                 mTextView.getTextSize(), 0.01f);
421     }
422 
testAccessTextColor()423     public void testAccessTextColor() {
424         mTextView = new TextView(mActivity);
425 
426         mTextView.setTextColor(Color.GREEN);
427         assertEquals(Color.GREEN, mTextView.getCurrentTextColor());
428         assertSame(ColorStateList.valueOf(Color.GREEN), mTextView.getTextColors());
429 
430         mTextView.setTextColor(Color.BLACK);
431         assertEquals(Color.BLACK, mTextView.getCurrentTextColor());
432         assertSame(ColorStateList.valueOf(Color.BLACK), mTextView.getTextColors());
433 
434         mTextView.setTextColor(Color.RED);
435         assertEquals(Color.RED, mTextView.getCurrentTextColor());
436         assertSame(ColorStateList.valueOf(Color.RED), mTextView.getTextColors());
437 
438         // using ColorStateList
439         // normal
440         ColorStateList colors = new ColorStateList(new int[][] {
441                 new int[] { android.R.attr.state_focused}, new int[0] },
442                 new int[] { Color.rgb(0, 255, 0), Color.BLACK });
443         mTextView.setTextColor(colors);
444         assertSame(colors, mTextView.getTextColors());
445         assertEquals(Color.BLACK, mTextView.getCurrentTextColor());
446 
447         // exceptional
448         try {
449             mTextView.setTextColor(null);
450             fail("Should thrown exception if the colors is null");
451         } catch (NullPointerException e){
452         }
453     }
454 
testGetTextColor()455     public void testGetTextColor() {
456         // TODO: How to get a suitable TypedArray to test this method.
457 
458         try {
459             TextView.getTextColor(mActivity, null, -1);
460             fail("There should be a NullPointerException thrown out.");
461         } catch (NullPointerException e) {
462         }
463     }
464 
testSetHighlightColor()465     public void testSetHighlightColor() {
466         mTextView = new TextView(mActivity);
467 
468         mTextView.setHighlightColor(0x00ff00ff);
469     }
470 
testSetShadowLayer()471     public void testSetShadowLayer() {
472         MockTextView textView = new MockTextView(mActivity);
473 
474         // shadow is placed to the left and below the text
475         textView.setShadowLayer(1.0f, 0.3f, 0.3f, Color.CYAN);
476         assertTrue(textView.isPaddingOffsetRequired());
477         assertEquals(0, textView.getLeftPaddingOffset());
478         assertEquals(0, textView.getTopPaddingOffset());
479         assertEquals(1, textView.getRightPaddingOffset());
480         assertEquals(1, textView.getBottomPaddingOffset());
481 
482         // shadow is placed to the right and above the text
483         textView.setShadowLayer(1.0f, -0.8f, -0.8f, Color.CYAN);
484         assertTrue(textView.isPaddingOffsetRequired());
485         assertEquals(-1, textView.getLeftPaddingOffset());
486         assertEquals(-1, textView.getTopPaddingOffset());
487         assertEquals(0, textView.getRightPaddingOffset());
488         assertEquals(0, textView.getBottomPaddingOffset());
489 
490         // no shadow
491         textView.setShadowLayer(0.0f, 0.0f, 0.0f, Color.CYAN);
492         assertFalse(textView.isPaddingOffsetRequired());
493         assertEquals(0, textView.getLeftPaddingOffset());
494         assertEquals(0, textView.getTopPaddingOffset());
495         assertEquals(0, textView.getRightPaddingOffset());
496         assertEquals(0, textView.getBottomPaddingOffset());
497     }
498 
499     @UiThreadTest
testSetSelectAllOnFocus()500     public void testSetSelectAllOnFocus() {
501         mActivity.setContentView(R.layout.textview_selectallonfocus);
502         String content = "This is the content";
503         String blank = "";
504         mTextView = findTextView(R.id.selectAllOnFocus_default);
505         mTextView.setText(blank, BufferType.SPANNABLE);
506         // change the focus
507         findTextView(R.id.selectAllOnFocus_dummy).requestFocus();
508         assertFalse(mTextView.isFocused());
509         mTextView.requestFocus();
510         assertTrue(mTextView.isFocused());
511 
512         assertEquals(-1, mTextView.getSelectionStart());
513         assertEquals(-1, mTextView.getSelectionEnd());
514 
515         mTextView.setText(content, BufferType.SPANNABLE);
516         mTextView.setSelectAllOnFocus(true);
517         // change the focus
518         findTextView(R.id.selectAllOnFocus_dummy).requestFocus();
519         assertFalse(mTextView.isFocused());
520         mTextView.requestFocus();
521         assertTrue(mTextView.isFocused());
522 
523         assertEquals(0, mTextView.getSelectionStart());
524         assertEquals(content.length(), mTextView.getSelectionEnd());
525 
526         Selection.setSelection((Spannable) mTextView.getText(), 0);
527         mTextView.setSelectAllOnFocus(false);
528         // change the focus
529         findTextView(R.id.selectAllOnFocus_dummy).requestFocus();
530         assertFalse(mTextView.isFocused());
531         mTextView.requestFocus();
532         assertTrue(mTextView.isFocused());
533 
534         assertEquals(0, mTextView.getSelectionStart());
535         assertEquals(0, mTextView.getSelectionEnd());
536 
537         mTextView.setText(blank, BufferType.SPANNABLE);
538         mTextView.setSelectAllOnFocus(true);
539         // change the focus
540         findTextView(R.id.selectAllOnFocus_dummy).requestFocus();
541         assertFalse(mTextView.isFocused());
542         mTextView.requestFocus();
543         assertTrue(mTextView.isFocused());
544 
545         assertEquals(0, mTextView.getSelectionStart());
546         assertEquals(blank.length(), mTextView.getSelectionEnd());
547 
548         Selection.setSelection((Spannable) mTextView.getText(), 0);
549         mTextView.setSelectAllOnFocus(false);
550         // change the focus
551         findTextView(R.id.selectAllOnFocus_dummy).requestFocus();
552         assertFalse(mTextView.isFocused());
553         mTextView.requestFocus();
554         assertTrue(mTextView.isFocused());
555 
556         assertEquals(0, mTextView.getSelectionStart());
557         assertEquals(0, mTextView.getSelectionEnd());
558     }
559 
testGetPaint()560     public void testGetPaint() {
561         mTextView = new TextView(mActivity);
562         TextPaint tp = mTextView.getPaint();
563         assertNotNull(tp);
564 
565         assertEquals(mTextView.getPaintFlags(), tp.getFlags());
566     }
567 
568     @UiThreadTest
testAccessLinksClickable()569     public void testAccessLinksClickable() {
570         mActivity.setContentView(R.layout.textview_hint_linksclickable_freezestext);
571 
572         mTextView = findTextView(R.id.hint_linksClickable_freezesText_default);
573         assertTrue(mTextView.getLinksClickable());
574 
575         mTextView = findTextView(R.id.linksClickable_true);
576         assertTrue(mTextView.getLinksClickable());
577 
578         mTextView = findTextView(R.id.linksClickable_false);
579         assertFalse(mTextView.getLinksClickable());
580 
581         mTextView.setLinksClickable(false);
582         assertFalse(mTextView.getLinksClickable());
583 
584         mTextView.setLinksClickable(true);
585         assertTrue(mTextView.getLinksClickable());
586 
587         assertNull(mTextView.getMovementMethod());
588 
589         final CharSequence text = new SpannableString("name: Jack. tel: +41 44 800 8999");
590 
591         mTextView.setAutoLinkMask(Linkify.PHONE_NUMBERS);
592         mTextView.setText(text, BufferType.EDITABLE);
593 
594         // Movement method will be automatically set to LinkMovementMethod
595         assertTrue(mTextView.getMovementMethod() instanceof LinkMovementMethod);
596     }
597 
testAccessHintTextColor()598     public void testAccessHintTextColor() {
599         mTextView = new TextView(mActivity);
600         // using int values
601         // normal
602         mTextView.setHintTextColor(Color.GREEN);
603         assertEquals(Color.GREEN, mTextView.getCurrentHintTextColor());
604         assertSame(ColorStateList.valueOf(Color.GREEN), mTextView.getHintTextColors());
605 
606         mTextView.setHintTextColor(Color.BLUE);
607         assertSame(ColorStateList.valueOf(Color.BLUE), mTextView.getHintTextColors());
608         assertEquals(Color.BLUE, mTextView.getCurrentHintTextColor());
609 
610         mTextView.setHintTextColor(Color.RED);
611         assertSame(ColorStateList.valueOf(Color.RED), mTextView.getHintTextColors());
612         assertEquals(Color.RED, mTextView.getCurrentHintTextColor());
613 
614         // using ColorStateList
615         // normal
616         ColorStateList colors = new ColorStateList(new int[][] {
617                 new int[] { android.R.attr.state_focused}, new int[0] },
618                 new int[] { Color.rgb(0, 255, 0), Color.BLACK });
619         mTextView.setHintTextColor(colors);
620         assertSame(colors, mTextView.getHintTextColors());
621         assertEquals(Color.BLACK, mTextView.getCurrentHintTextColor());
622 
623         // exceptional
624         mTextView.setHintTextColor(null);
625         assertNull(mTextView.getHintTextColors());
626         assertEquals(mTextView.getCurrentTextColor(), mTextView.getCurrentHintTextColor());
627     }
628 
testAccessLinkTextColor()629     public void testAccessLinkTextColor() {
630         mTextView = new TextView(mActivity);
631         // normal
632         mTextView.setLinkTextColor(Color.GRAY);
633         assertSame(ColorStateList.valueOf(Color.GRAY), mTextView.getLinkTextColors());
634         assertEquals(Color.GRAY, mTextView.getPaint().linkColor);
635 
636         mTextView.setLinkTextColor(Color.YELLOW);
637         assertSame(ColorStateList.valueOf(Color.YELLOW), mTextView.getLinkTextColors());
638         assertEquals(Color.YELLOW, mTextView.getPaint().linkColor);
639 
640         mTextView.setLinkTextColor(Color.WHITE);
641         assertSame(ColorStateList.valueOf(Color.WHITE), mTextView.getLinkTextColors());
642         assertEquals(Color.WHITE, mTextView.getPaint().linkColor);
643 
644         ColorStateList colors = new ColorStateList(new int[][] {
645                 new int[] { android.R.attr.state_expanded}, new int[0] },
646                 new int[] { Color.rgb(0, 255, 0), Color.BLACK });
647         mTextView.setLinkTextColor(colors);
648         assertSame(colors, mTextView.getLinkTextColors());
649         assertEquals(Color.BLACK, mTextView.getPaint().linkColor);
650 
651         mTextView.setLinkTextColor(null);
652         assertNull(mTextView.getLinkTextColors());
653         assertEquals(Color.BLACK, mTextView.getPaint().linkColor);
654     }
655 
testAccessPaintFlags()656     public void testAccessPaintFlags() {
657         mTextView = new TextView(mActivity);
658         assertEquals(Paint.DEV_KERN_TEXT_FLAG | Paint.EMBEDDED_BITMAP_TEXT_FLAG
659                 | Paint.ANTI_ALIAS_FLAG, mTextView.getPaintFlags());
660 
661         mTextView.setPaintFlags(Paint.UNDERLINE_TEXT_FLAG | Paint.FAKE_BOLD_TEXT_FLAG);
662         assertEquals(Paint.UNDERLINE_TEXT_FLAG | Paint.FAKE_BOLD_TEXT_FLAG,
663                 mTextView.getPaintFlags());
664 
665         mTextView.setPaintFlags(Paint.STRIKE_THRU_TEXT_FLAG | Paint.LINEAR_TEXT_FLAG);
666         assertEquals(Paint.STRIKE_THRU_TEXT_FLAG | Paint.LINEAR_TEXT_FLAG,
667                 mTextView.getPaintFlags());
668     }
669 
testHeightAndWidth()670     public void testHeightAndWidth() {
671         mTextView = findTextView(R.id.textview_text);
672         int originalWidth = mTextView.getWidth();
673         setWidth(mTextView.getWidth() >> 3);
674         int originalHeight = mTextView.getHeight();
675 
676         setMaxHeight(originalHeight + 1);
677         assertEquals(originalHeight, mTextView.getHeight());
678 
679         setMaxHeight(originalHeight - 1);
680         assertEquals(originalHeight - 1, mTextView.getHeight());
681 
682         setMaxHeight(-1);
683         assertEquals(0, mTextView.getHeight());
684 
685         setMaxHeight(Integer.MAX_VALUE);
686         assertEquals(originalHeight, mTextView.getHeight());
687 
688         setMinHeight(originalHeight + 1);
689         assertEquals(originalHeight + 1, mTextView.getHeight());
690 
691         setMinHeight(originalHeight - 1);
692         assertEquals(originalHeight, mTextView.getHeight());
693 
694         setMinHeight(-1);
695         assertEquals(originalHeight, mTextView.getHeight());
696 
697         setMinHeight(0);
698         setMaxHeight(Integer.MAX_VALUE);
699 
700         setHeight(originalHeight + 1);
701         assertEquals(originalHeight + 1, mTextView.getHeight());
702 
703         setHeight(originalHeight - 1);
704         assertEquals(originalHeight - 1, mTextView.getHeight());
705 
706         setHeight(-1);
707         assertEquals(0, mTextView.getHeight());
708 
709         setHeight(originalHeight);
710         assertEquals(originalHeight, mTextView.getHeight());
711 
712         assertEquals(originalWidth >> 3, mTextView.getWidth());
713 
714         // Min Width
715         setMinWidth(originalWidth + 1);
716         assertEquals(1, mTextView.getLineCount());
717         assertEquals(originalWidth + 1, mTextView.getWidth());
718 
719         setMinWidth(originalWidth - 1);
720         assertEquals(2, mTextView.getLineCount());
721         assertEquals(originalWidth - 1, mTextView.getWidth());
722 
723         // Width
724         setWidth(originalWidth + 1);
725         assertEquals(1, mTextView.getLineCount());
726         assertEquals(originalWidth + 1, mTextView.getWidth());
727 
728         setWidth(originalWidth - 1);
729         assertEquals(2, mTextView.getLineCount());
730         assertEquals(originalWidth - 1, mTextView.getWidth());
731     }
732 
testSetMinEms()733     public void testSetMinEms() {
734         mTextView = findTextView(R.id.textview_text);
735         assertEquals(1, mTextView.getLineCount());
736 
737         int originalWidth = mTextView.getWidth();
738         int originalEms = originalWidth / mTextView.getLineHeight();
739 
740         setMinEms(originalEms + 1);
741         assertEquals((originalEms + 1) * mTextView.getLineHeight(), mTextView.getWidth());
742 
743         setMinEms(originalEms - 1);
744         assertEquals(originalWidth, mTextView.getWidth());
745     }
746 
testSetMaxEms()747     public void testSetMaxEms() {
748         mTextView = findTextView(R.id.textview_text);
749         assertEquals(1, mTextView.getLineCount());
750         int originalWidth = mTextView.getWidth();
751         int originalEms = originalWidth / mTextView.getLineHeight();
752 
753         setMaxEms(originalEms + 1);
754         assertEquals(1, mTextView.getLineCount());
755         assertEquals(originalWidth, mTextView.getWidth());
756 
757         setMaxEms(originalEms - 1);
758         assertTrue(1 < mTextView.getLineCount());
759         assertEquals((originalEms - 1) * mTextView.getLineHeight(),
760                 mTextView.getWidth());
761     }
762 
testSetEms()763     public void testSetEms() {
764         mTextView = findTextView(R.id.textview_text);
765         assertEquals("check height", 1, mTextView.getLineCount());
766         int originalWidth = mTextView.getWidth();
767         int originalEms = originalWidth / mTextView.getLineHeight();
768 
769         setEms(originalEms + 1);
770         assertEquals(1, mTextView.getLineCount());
771         assertEquals((originalEms + 1) * mTextView.getLineHeight(),
772                 mTextView.getWidth());
773 
774         setEms(originalEms - 1);
775         assertTrue((1 < mTextView.getLineCount()));
776         assertEquals((originalEms - 1) * mTextView.getLineHeight(),
777                 mTextView.getWidth());
778     }
779 
testSetLineSpacing()780     public void testSetLineSpacing() {
781         mTextView = new TextView(mActivity);
782         int originalLineHeight = mTextView.getLineHeight();
783 
784         // normal
785         float add = 1.2f;
786         float mult = 1.4f;
787         setLineSpacing(add, mult);
788         assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
789         add = 0.0f;
790         mult = 1.4f;
791         setLineSpacing(add, mult);
792         assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
793 
794         // abnormal
795         add = -1.2f;
796         mult = 1.4f;
797         setLineSpacing(add, mult);
798         assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
799         add = -1.2f;
800         mult = -1.4f;
801         setLineSpacing(add, mult);
802         assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
803         add = 1.2f;
804         mult = 0.0f;
805         setLineSpacing(add, mult);
806         assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
807 
808         // edge
809         add = Float.MIN_VALUE;
810         mult = Float.MIN_VALUE;
811         setLineSpacing(add, mult);
812         assertEquals(Math.round(originalLineHeight * mult + add), mTextView.getLineHeight());
813 
814         // edge case where the behavior of Math.round() deviates from
815         // FastMath.round(), requiring us to use an explicit 0 value
816         add = Float.MAX_VALUE;
817         mult = Float.MAX_VALUE;
818         setLineSpacing(add, mult);
819         assertEquals(0, mTextView.getLineHeight());
820     }
821 
testInstanceState()822     public void testInstanceState() {
823         // Do not test. Implementation details.
824     }
825 
testAccessFreezesText()826     public void testAccessFreezesText() throws Throwable {
827         layout(R.layout.textview_hint_linksclickable_freezestext);
828 
829         mTextView = findTextView(R.id.hint_linksClickable_freezesText_default);
830         assertFalse(mTextView.getFreezesText());
831 
832         mTextView = findTextView(R.id.freezesText_true);
833         assertTrue(mTextView.getFreezesText());
834 
835         mTextView = findTextView(R.id.freezesText_false);
836         assertFalse(mTextView.getFreezesText());
837 
838         mTextView.setFreezesText(false);
839         assertFalse(mTextView.getFreezesText());
840 
841         final CharSequence text = "Hello, TextView.";
842         mActivity.runOnUiThread(new Runnable() {
843             public void run() {
844                 mTextView.setText(text);
845             }
846         });
847         mInstrumentation.waitForIdleSync();
848 
849         final URLSpan urlSpan = new URLSpan("ctstest://TextView/test");
850         // TODO: How to simulate the TextView in frozen icicles.
851         Instrumentation instrumentation = getInstrumentation();
852         ActivityMonitor am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
853                 null, false);
854 
855         mActivity.runOnUiThread(new Runnable() {
856             public void run() {
857                 Uri uri = Uri.parse(urlSpan.getURL());
858                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
859                 mActivity.startActivity(intent);
860             }
861         });
862 
863         Activity newActivity = am.waitForActivityWithTimeout(TIMEOUT);
864         assertNotNull(newActivity);
865         newActivity.finish();
866         instrumentation.removeMonitor(am);
867         // the text of TextView is removed.
868         mTextView = findTextView(R.id.freezesText_false);
869 
870         assertEquals(text.toString(), mTextView.getText().toString());
871 
872         mTextView.setFreezesText(true);
873         assertTrue(mTextView.getFreezesText());
874 
875         mActivity.runOnUiThread(new Runnable() {
876             public void run() {
877                 mTextView.setText(text);
878             }
879         });
880         mInstrumentation.waitForIdleSync();
881         // TODO: How to simulate the TextView in frozen icicles.
882         am = instrumentation.addMonitor(MockURLSpanTestActivity.class.getName(),
883                 null, false);
884 
885         mActivity.runOnUiThread(new Runnable() {
886             public void run() {
887                 Uri uri = Uri.parse(urlSpan.getURL());
888                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
889                 mActivity.startActivity(intent);
890             }
891         });
892 
893         Activity oldActivity = newActivity;
894         while (true) {
895             newActivity = am.waitForActivityWithTimeout(TIMEOUT);
896             assertNotNull(newActivity);
897             if (newActivity != oldActivity) {
898                 break;
899             }
900         }
901         newActivity.finish();
902         instrumentation.removeMonitor(am);
903         // the text of TextView is still there.
904         mTextView = findTextView(R.id.freezesText_false);
905         assertEquals(text.toString(), mTextView.getText().toString());
906     }
907 
testSetEditableFactory()908     public void testSetEditableFactory() {
909         mTextView = new TextView(mActivity);
910         String text = "sample";
911         MockEditableFactory factory = new MockEditableFactory();
912         mTextView.setEditableFactory(factory);
913 
914         factory.reset();
915         mTextView.setText(text);
916         assertFalse(factory.hasCalledNewEditable());
917 
918         factory.reset();
919         mTextView.setText(text, BufferType.SPANNABLE);
920         assertFalse(factory.hasCalledNewEditable());
921 
922         factory.reset();
923         mTextView.setText(text, BufferType.NORMAL);
924         assertFalse(factory.hasCalledNewEditable());
925 
926         factory.reset();
927         mTextView.setText(text, BufferType.EDITABLE);
928         assertTrue(factory.hasCalledNewEditable());
929         assertEquals(text, factory.getSource());
930 
931         mTextView.setKeyListener(DigitsKeyListener.getInstance());
932         factory.reset();
933         mTextView.setText(text, BufferType.EDITABLE);
934         assertTrue(factory.hasCalledNewEditable());
935         assertEquals(text, factory.getSource());
936 
937         try {
938             mTextView.setEditableFactory(null);
939             fail("The factory can not set to null!");
940         } catch (NullPointerException e) {
941         }
942     }
943 
testSetSpannableFactory()944     public void testSetSpannableFactory() {
945         mTextView = new TextView(mActivity);
946         String text = "sample";
947         MockSpannableFactory factory = new MockSpannableFactory();
948         mTextView.setSpannableFactory(factory);
949 
950         factory.reset();
951         mTextView.setText(text);
952         assertFalse(factory.hasCalledNewSpannable());
953 
954         factory.reset();
955         mTextView.setText(text, BufferType.EDITABLE);
956         assertFalse(factory.hasCalledNewSpannable());
957 
958         factory.reset();
959         mTextView.setText(text, BufferType.NORMAL);
960         assertFalse(factory.hasCalledNewSpannable());
961 
962         factory.reset();
963         mTextView.setText(text, BufferType.SPANNABLE);
964         assertTrue(factory.hasCalledNewSpannable());
965         assertEquals(text, factory.getSource());
966 
967         mTextView.setMovementMethod(LinkMovementMethod.getInstance());
968         factory.reset();
969         mTextView.setText(text, BufferType.NORMAL);
970         assertTrue(factory.hasCalledNewSpannable());
971         assertEquals(text, factory.getSource());
972 
973         try {
974             mTextView.setSpannableFactory(null);
975             fail("The factory can not set to null!");
976         } catch (NullPointerException e) {
977         }
978     }
979 
testTextChangedListener()980     public void testTextChangedListener() {
981         mTextView = new TextView(mActivity);
982         MockTextWatcher watcher0 = new MockTextWatcher();
983         MockTextWatcher watcher1 = new MockTextWatcher();
984 
985         mTextView.addTextChangedListener(watcher0);
986         mTextView.addTextChangedListener(watcher1);
987 
988         watcher0.reset();
989         watcher1.reset();
990         mTextView.setText("Changed");
991         assertTrue(watcher0.hasCalledBeforeTextChanged());
992         assertTrue(watcher0.hasCalledOnTextChanged());
993         assertTrue(watcher0.hasCalledAfterTextChanged());
994         assertTrue(watcher1.hasCalledBeforeTextChanged());
995         assertTrue(watcher1.hasCalledOnTextChanged());
996         assertTrue(watcher1.hasCalledAfterTextChanged());
997 
998         watcher0.reset();
999         watcher1.reset();
1000         // BeforeTextChanged and OnTextChanged are called though the strings are same
1001         mTextView.setText("Changed");
1002         assertTrue(watcher0.hasCalledBeforeTextChanged());
1003         assertTrue(watcher0.hasCalledOnTextChanged());
1004         assertTrue(watcher0.hasCalledAfterTextChanged());
1005         assertTrue(watcher1.hasCalledBeforeTextChanged());
1006         assertTrue(watcher1.hasCalledOnTextChanged());
1007         assertTrue(watcher1.hasCalledAfterTextChanged());
1008 
1009         watcher0.reset();
1010         watcher1.reset();
1011         // BeforeTextChanged and OnTextChanged are called twice (The text is not
1012         // Editable, so in Append() it calls setText() first)
1013         mTextView.append("and appended");
1014         assertTrue(watcher0.hasCalledBeforeTextChanged());
1015         assertTrue(watcher0.hasCalledOnTextChanged());
1016         assertTrue(watcher0.hasCalledAfterTextChanged());
1017         assertTrue(watcher1.hasCalledBeforeTextChanged());
1018         assertTrue(watcher1.hasCalledOnTextChanged());
1019         assertTrue(watcher1.hasCalledAfterTextChanged());
1020 
1021         watcher0.reset();
1022         watcher1.reset();
1023         // Methods are not called if the string does not change
1024         mTextView.append("");
1025         assertFalse(watcher0.hasCalledBeforeTextChanged());
1026         assertFalse(watcher0.hasCalledOnTextChanged());
1027         assertFalse(watcher0.hasCalledAfterTextChanged());
1028         assertFalse(watcher1.hasCalledBeforeTextChanged());
1029         assertFalse(watcher1.hasCalledOnTextChanged());
1030         assertFalse(watcher1.hasCalledAfterTextChanged());
1031 
1032         watcher0.reset();
1033         watcher1.reset();
1034         mTextView.removeTextChangedListener(watcher1);
1035         mTextView.setText(null);
1036         assertTrue(watcher0.hasCalledBeforeTextChanged());
1037         assertTrue(watcher0.hasCalledOnTextChanged());
1038         assertTrue(watcher0.hasCalledAfterTextChanged());
1039         assertFalse(watcher1.hasCalledBeforeTextChanged());
1040         assertFalse(watcher1.hasCalledOnTextChanged());
1041         assertFalse(watcher1.hasCalledAfterTextChanged());
1042     }
1043 
testSetTextKeepState1()1044     public void testSetTextKeepState1() {
1045         mTextView = new TextView(mActivity);
1046 
1047         String longString = "very long content";
1048         String shortString = "short";
1049 
1050         // selection is at the exact place which is inside the short string
1051         mTextView.setText(longString, BufferType.SPANNABLE);
1052         Selection.setSelection((Spannable) mTextView.getText(), 3);
1053         mTextView.setTextKeepState(shortString);
1054         assertEquals(shortString, mTextView.getText().toString());
1055         assertEquals(3, mTextView.getSelectionStart());
1056         assertEquals(3, mTextView.getSelectionEnd());
1057 
1058         // selection is at the exact place which is outside the short string
1059         mTextView.setText(longString);
1060         Selection.setSelection((Spannable) mTextView.getText(), shortString.length() + 1);
1061         mTextView.setTextKeepState(shortString);
1062         assertEquals(shortString, mTextView.getText().toString());
1063         assertEquals(shortString.length(), mTextView.getSelectionStart());
1064         assertEquals(shortString.length(), mTextView.getSelectionEnd());
1065 
1066         // select the sub string which is inside the short string
1067         mTextView.setText(longString);
1068         Selection.setSelection((Spannable) mTextView.getText(), 1, 4);
1069         mTextView.setTextKeepState(shortString);
1070         assertEquals(shortString, mTextView.getText().toString());
1071         assertEquals(1, mTextView.getSelectionStart());
1072         assertEquals(4, mTextView.getSelectionEnd());
1073 
1074         // select the sub string which ends outside the short string
1075         mTextView.setText(longString);
1076         Selection.setSelection((Spannable) mTextView.getText(), 2, shortString.length() + 1);
1077         mTextView.setTextKeepState(shortString);
1078         assertEquals(shortString, mTextView.getText().toString());
1079         assertEquals(2, mTextView.getSelectionStart());
1080         assertEquals(shortString.length(), mTextView.getSelectionEnd());
1081 
1082         // select the sub string which is outside the short string
1083         mTextView.setText(longString);
1084         Selection.setSelection((Spannable) mTextView.getText(),
1085                 shortString.length() + 1, shortString.length() + 3);
1086         mTextView.setTextKeepState(shortString);
1087         assertEquals(shortString, mTextView.getText().toString());
1088         assertEquals(shortString.length(), mTextView.getSelectionStart());
1089         assertEquals(shortString.length(), mTextView.getSelectionEnd());
1090     }
1091 
1092     @UiThreadTest
testGetEditableText()1093     public void testGetEditableText() {
1094         TextView tv = findTextView(R.id.textview_text);
1095 
1096         String text = "Hello";
1097         tv.setText(text, BufferType.EDITABLE);
1098         assertEquals(text, tv.getText().toString());
1099         assertTrue(tv.getText() instanceof Editable);
1100         assertEquals(text, tv.getEditableText().toString());
1101 
1102         tv.setText(text, BufferType.SPANNABLE);
1103         assertEquals(text, tv.getText().toString());
1104         assertTrue(tv.getText() instanceof Spannable);
1105         assertNull(tv.getEditableText());
1106 
1107         tv.setText(null, BufferType.EDITABLE);
1108         assertEquals("", tv.getText().toString());
1109         assertTrue(tv.getText() instanceof Editable);
1110         assertEquals("", tv.getEditableText().toString());
1111 
1112         tv.setText(null, BufferType.SPANNABLE);
1113         assertEquals("", tv.getText().toString());
1114         assertTrue(tv.getText() instanceof Spannable);
1115         assertNull(tv.getEditableText());
1116     }
1117 
1118     @UiThreadTest
testSetText2()1119     public void testSetText2() {
1120         String string = "This is a test for setting text content by char array";
1121         char[] input = string.toCharArray();
1122         TextView tv = findTextView(R.id.textview_text);
1123 
1124         tv.setText(input, 0, input.length);
1125         assertEquals(string, tv.getText().toString());
1126 
1127         tv.setText(input, 0, 5);
1128         assertEquals(string.substring(0, 5), tv.getText().toString());
1129 
1130         try {
1131             tv.setText(input, -1, input.length);
1132             fail("Should throw exception if the start position is negative!");
1133         } catch (IndexOutOfBoundsException exception) {
1134         }
1135 
1136         try {
1137             tv.setText(input, 0, -1);
1138             fail("Should throw exception if the length is negative!");
1139         } catch (IndexOutOfBoundsException exception) {
1140         }
1141 
1142         try {
1143             tv.setText(input, 1, input.length);
1144             fail("Should throw exception if the end position is out of index!");
1145         } catch (IndexOutOfBoundsException exception) {
1146         }
1147 
1148         tv.setText(input, 1, 0);
1149         assertEquals("", tv.getText().toString());
1150     }
1151 
1152     @UiThreadTest
testSetText1()1153     public void testSetText1() {
1154         mTextView = findTextView(R.id.textview_text);
1155 
1156         String longString = "very long content";
1157         String shortString = "short";
1158 
1159         // selection is at the exact place which is inside the short string
1160         mTextView.setText(longString, BufferType.SPANNABLE);
1161         Selection.setSelection((Spannable) mTextView.getText(), 3);
1162         mTextView.setTextKeepState(shortString, BufferType.EDITABLE);
1163         assertTrue(mTextView.getText() instanceof Editable);
1164         assertEquals(shortString, mTextView.getText().toString());
1165         assertEquals(shortString, mTextView.getEditableText().toString());
1166         assertEquals(3, mTextView.getSelectionStart());
1167         assertEquals(3, mTextView.getSelectionEnd());
1168 
1169         mTextView.setText(shortString, BufferType.EDITABLE);
1170         assertTrue(mTextView.getText() instanceof Editable);
1171         assertEquals(shortString, mTextView.getText().toString());
1172         assertEquals(shortString, mTextView.getEditableText().toString());
1173         // there is no selection.
1174         assertEquals(-1, mTextView.getSelectionStart());
1175         assertEquals(-1, mTextView.getSelectionEnd());
1176 
1177         // selection is at the exact place which is outside the short string
1178         mTextView.setText(longString);
1179         Selection.setSelection((Spannable) mTextView.getText(), longString.length());
1180         mTextView.setTextKeepState(shortString, BufferType.EDITABLE);
1181         assertTrue(mTextView.getText() instanceof Editable);
1182         assertEquals(shortString, mTextView.getText().toString());
1183         assertEquals(shortString, mTextView.getEditableText().toString());
1184         assertEquals(shortString.length(), mTextView.getSelectionStart());
1185         assertEquals(shortString.length(), mTextView.getSelectionEnd());
1186 
1187         mTextView.setText(shortString, BufferType.EDITABLE);
1188         assertTrue(mTextView.getText() instanceof Editable);
1189         assertEquals(shortString, mTextView.getText().toString());
1190         assertEquals(shortString, mTextView.getEditableText().toString());
1191         // there is no selection.
1192         assertEquals(-1, mTextView.getSelectionStart());
1193         assertEquals(-1, mTextView.getSelectionEnd());
1194 
1195         // select the sub string which is inside the short string
1196         mTextView.setText(longString);
1197         Selection.setSelection((Spannable) mTextView.getText(), 1, shortString.length() - 1);
1198         mTextView.setTextKeepState(shortString, BufferType.EDITABLE);
1199         assertTrue(mTextView.getText() instanceof Editable);
1200         assertEquals(shortString, mTextView.getText().toString());
1201         assertEquals(shortString, mTextView.getEditableText().toString());
1202         assertEquals(1, mTextView.getSelectionStart());
1203         assertEquals(shortString.length() - 1, mTextView.getSelectionEnd());
1204 
1205         mTextView.setText(shortString, BufferType.EDITABLE);
1206         assertTrue(mTextView.getText() instanceof Editable);
1207         assertEquals(shortString, mTextView.getText().toString());
1208         assertEquals(shortString, mTextView.getEditableText().toString());
1209         // there is no selection.
1210         assertEquals(-1, mTextView.getSelectionStart());
1211         assertEquals(-1, mTextView.getSelectionEnd());
1212 
1213         // select the sub string which ends outside the short string
1214         mTextView.setText(longString);
1215         Selection.setSelection((Spannable) mTextView.getText(), 2, longString.length());
1216         mTextView.setTextKeepState(shortString, BufferType.EDITABLE);
1217         assertTrue(mTextView.getText() instanceof Editable);
1218         assertEquals(shortString, mTextView.getText().toString());
1219         assertEquals(shortString, mTextView.getEditableText().toString());
1220         assertEquals(2, mTextView.getSelectionStart());
1221         assertEquals(shortString.length(), mTextView.getSelectionEnd());
1222 
1223         mTextView.setText(shortString, BufferType.EDITABLE);
1224         assertTrue(mTextView.getText() instanceof Editable);
1225         assertEquals(shortString, mTextView.getText().toString());
1226         assertEquals(shortString, mTextView.getEditableText().toString());
1227         // there is no selection.
1228         assertEquals(-1, mTextView.getSelectionStart());
1229         assertEquals(-1, mTextView.getSelectionEnd());
1230 
1231         // select the sub string which is outside the short string
1232         mTextView.setText(longString);
1233         Selection.setSelection((Spannable) mTextView.getText(),
1234                 shortString.length() + 1, shortString.length() + 3);
1235         mTextView.setTextKeepState(shortString, BufferType.EDITABLE);
1236         assertTrue(mTextView.getText() instanceof Editable);
1237         assertEquals(shortString, mTextView.getText().toString());
1238         assertEquals(shortString, mTextView.getEditableText().toString());
1239         assertEquals(shortString.length(), mTextView.getSelectionStart());
1240         assertEquals(shortString.length(), mTextView.getSelectionEnd());
1241 
1242         mTextView.setText(shortString, BufferType.EDITABLE);
1243         assertTrue(mTextView.getText() instanceof Editable);
1244         assertEquals(shortString, mTextView.getText().toString());
1245         assertEquals(shortString, mTextView.getEditableText().toString());
1246         // there is no selection.
1247         assertEquals(-1, mTextView.getSelectionStart());
1248         assertEquals(-1, mTextView.getSelectionEnd());
1249     }
1250 
1251     @UiThreadTest
testSetText3()1252     public void testSetText3() {
1253         TextView tv = findTextView(R.id.textview_text);
1254 
1255         int resId = R.string.text_view_hint;
1256         String result = mActivity.getResources().getString(resId);
1257 
1258         tv.setText(resId);
1259         assertEquals(result, tv.getText().toString());
1260 
1261         try {
1262             tv.setText(-1);
1263             fail("Should throw exception with illegal id");
1264         } catch (NotFoundException e) {
1265         }
1266     }
1267 
testUndo_insert()1268     public void testUndo_insert() {
1269         initTextViewForTyping();
1270 
1271         // Type some text.
1272         mInstrumentation.sendStringSync("abc");
1273         mActivity.runOnUiThread(new Runnable() {
1274             public void run() {
1275                 // Precondition: The cursor is at the end of the text.
1276                 assertEquals(3, mTextView.getSelectionStart());
1277 
1278                 // Undo removes the typed string in one step.
1279                 mTextView.onTextContextMenuItem(android.R.id.undo);
1280                 assertEquals("", mTextView.getText().toString());
1281                 assertEquals(0, mTextView.getSelectionStart());
1282 
1283                 // Redo restores the text and cursor position.
1284                 mTextView.onTextContextMenuItem(android.R.id.redo);
1285                 assertEquals("abc", mTextView.getText().toString());
1286                 assertEquals(3, mTextView.getSelectionStart());
1287 
1288                 // Undoing the redo clears the text again.
1289                 mTextView.onTextContextMenuItem(android.R.id.undo);
1290                 assertEquals("", mTextView.getText().toString());
1291 
1292                 // Undo when the undo stack is empty does nothing.
1293                 mTextView.onTextContextMenuItem(android.R.id.undo);
1294                 assertEquals("", mTextView.getText().toString());
1295             }
1296         });
1297         mInstrumentation.waitForIdleSync();
1298     }
1299 
testUndo_delete()1300     public void testUndo_delete() {
1301         initTextViewForTyping();
1302 
1303         // Simulate deleting text and undoing it.
1304         mInstrumentation.sendStringSync("xyz");
1305         sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
1306         mActivity.runOnUiThread(new Runnable() {
1307             public void run() {
1308                 // Precondition: The text was actually deleted.
1309                 assertEquals("", mTextView.getText().toString());
1310                 assertEquals(0, mTextView.getSelectionStart());
1311 
1312                 // Undo restores the typed string and cursor position in one step.
1313                 mTextView.onTextContextMenuItem(android.R.id.undo);
1314                 assertEquals("xyz", mTextView.getText().toString());
1315                 assertEquals(3, mTextView.getSelectionStart());
1316 
1317                 // Redo removes the text in one step.
1318                 mTextView.onTextContextMenuItem(android.R.id.redo);
1319                 assertEquals("", mTextView.getText().toString());
1320                 assertEquals(0, mTextView.getSelectionStart());
1321 
1322                 // Undoing the redo restores the text again.
1323                 mTextView.onTextContextMenuItem(android.R.id.undo);
1324                 assertEquals("xyz", mTextView.getText().toString());
1325                 assertEquals(3, mTextView.getSelectionStart());
1326 
1327                 // Undoing again undoes the original typing.
1328                 mTextView.onTextContextMenuItem(android.R.id.undo);
1329                 assertEquals("", mTextView.getText().toString());
1330                 assertEquals(0, mTextView.getSelectionStart());
1331             }
1332         });
1333         mInstrumentation.waitForIdleSync();
1334     }
1335 
1336     // Initialize the text view for simulated IME typing. Must be called on UI thread.
initTextViewForSimulatedIme()1337     private InputConnection initTextViewForSimulatedIme() {
1338         mTextView = findTextView(R.id.textview_text);
1339         mTextView.setKeyListener(QwertyKeyListener.getInstance(false, Capitalize.NONE));
1340         mTextView.setText("", BufferType.EDITABLE);
1341         return mTextView.onCreateInputConnection(new EditorInfo());
1342     }
1343 
1344     // Simulates IME composing text behavior.
setComposingTextInBatch(InputConnection input, CharSequence text)1345     private void setComposingTextInBatch(InputConnection input, CharSequence text) {
1346         input.beginBatchEdit();
1347         input.setComposingText(text, 1);  // Leave cursor at end.
1348         input.endBatchEdit();
1349     }
1350 
1351     @UiThreadTest
testUndo_imeInsertLatin()1352     public void testUndo_imeInsertLatin() {
1353         InputConnection input = initTextViewForSimulatedIme();
1354 
1355         // Simulate IME text entry behavior. The Latin IME enters text by replacing partial words,
1356         // such as "c" -> "ca" -> "cat" -> "cat ".
1357         setComposingTextInBatch(input, "c");
1358         setComposingTextInBatch(input, "ca");
1359 
1360         // The completion and space are added in the same batch.
1361         input.beginBatchEdit();
1362         input.commitText("cat", 1);
1363         input.commitText(" ", 1);
1364         input.endBatchEdit();
1365 
1366         // The repeated replacements undo in a single step.
1367         mTextView.onTextContextMenuItem(android.R.id.undo);
1368         assertEquals("", mTextView.getText().toString());
1369     }
1370 
1371     @UiThreadTest
testUndo_imeInsertJapanese()1372     public void testUndo_imeInsertJapanese() {
1373         InputConnection input = initTextViewForSimulatedIme();
1374 
1375         // The Japanese IME does repeated replacements of Latin characters to hiragana to kanji.
1376         final String HA = "\u306F";  // HIRAGANA LETTER HA
1377         final String NA = "\u306A";  // HIRAGANA LETTER NA
1378         setComposingTextInBatch(input, "h");
1379         setComposingTextInBatch(input, HA);
1380         setComposingTextInBatch(input, HA + "n");
1381         setComposingTextInBatch(input, HA + NA);
1382 
1383         // The result may be a surrogate pair. The composition ends in the same batch.
1384         input.beginBatchEdit();
1385         input.commitText("\uD83C\uDF37", 1);  // U+1F337 TULIP
1386         input.setComposingText("", 1);
1387         input.endBatchEdit();
1388 
1389         // The repeated replacements are a single undo step.
1390         mTextView.onTextContextMenuItem(android.R.id.undo);
1391         assertEquals("", mTextView.getText().toString());
1392     }
1393 
1394     @UiThreadTest
testUndo_imeCancel()1395     public void testUndo_imeCancel() {
1396         InputConnection input = initTextViewForSimulatedIme();
1397         mTextView.setText("flower");
1398 
1399         // Start typing a composition.
1400         final String HA = "\u306F";  // HIRAGANA LETTER HA
1401         setComposingTextInBatch(input, "h");
1402         setComposingTextInBatch(input, HA);
1403         setComposingTextInBatch(input, HA + "n");
1404 
1405         // Cancel the composition.
1406         setComposingTextInBatch(input, "");
1407 
1408         // Undo and redo do nothing.
1409         mTextView.onTextContextMenuItem(android.R.id.undo);
1410         assertEquals("flower", mTextView.getText().toString());
1411         mTextView.onTextContextMenuItem(android.R.id.redo);
1412         assertEquals("flower", mTextView.getText().toString());
1413     }
1414 
1415     @UiThreadTest
testUndo_imeEmptyBatch()1416     public void testUndo_imeEmptyBatch() {
1417         InputConnection input = initTextViewForSimulatedIme();
1418         mTextView.setText("flower");
1419 
1420         // Send an empty batch edit. This happens if the IME is hidden and shown.
1421         input.beginBatchEdit();
1422         input.endBatchEdit();
1423 
1424         // Undo and redo do nothing.
1425         mTextView.onTextContextMenuItem(android.R.id.undo);
1426         assertEquals("flower", mTextView.getText().toString());
1427         mTextView.onTextContextMenuItem(android.R.id.redo);
1428         assertEquals("flower", mTextView.getText().toString());
1429     }
1430 
testUndo_setText()1431     public void testUndo_setText() {
1432         initTextViewForTyping();
1433 
1434         // Create two undo operations, an insert and a delete.
1435         mInstrumentation.sendStringSync("xyz");
1436         sendKeys(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL);
1437         mActivity.runOnUiThread(new Runnable() {
1438             public void run() {
1439                 // Calling setText() clears both undo operations, so undo doesn't happen.
1440                 mTextView.setText("Hello", BufferType.EDITABLE);
1441                 mTextView.onTextContextMenuItem(android.R.id.undo);
1442                 assertEquals("Hello", mTextView.getText().toString());
1443 
1444                 // Clearing text programmatically does not undo either.
1445                 mTextView.setText("", BufferType.EDITABLE);
1446                 mTextView.onTextContextMenuItem(android.R.id.undo);
1447                 assertEquals("", mTextView.getText().toString());
1448             }
1449         });
1450         mInstrumentation.waitForIdleSync();
1451     }
1452 
testRedo_setText()1453     public void testRedo_setText() {
1454         initTextViewForTyping();
1455 
1456         // Type some text. This creates an undo entry.
1457         mInstrumentation.sendStringSync("abc");
1458         mActivity.runOnUiThread(new Runnable() {
1459             public void run() {
1460                 // Undo the typing to create a redo entry.
1461                 mTextView.onTextContextMenuItem(android.R.id.undo);
1462 
1463                 // Calling setText() clears the redo stack, so redo doesn't happen.
1464                 mTextView.setText("Hello", BufferType.EDITABLE);
1465                 mTextView.onTextContextMenuItem(android.R.id.redo);
1466                 assertEquals("Hello", mTextView.getText().toString());
1467             }
1468         });
1469         mInstrumentation.waitForIdleSync();
1470     }
1471 
testUndo_directAppend()1472     public void testUndo_directAppend() {
1473         initTextViewForTyping();
1474 
1475         // Type some text.
1476         mInstrumentation.sendStringSync("abc");
1477         mActivity.runOnUiThread(new Runnable() {
1478             public void run() {
1479                 // Programmatically append some text.
1480                 mTextView.append("def");
1481                 assertEquals("abcdef", mTextView.getText().toString());
1482 
1483                 // Undo removes the append as a separate step.
1484                 mTextView.onTextContextMenuItem(android.R.id.undo);
1485                 assertEquals("abc", mTextView.getText().toString());
1486 
1487                 // Another undo removes the original typing.
1488                 mTextView.onTextContextMenuItem(android.R.id.undo);
1489                 assertEquals("", mTextView.getText().toString());
1490             }
1491         });
1492         mInstrumentation.waitForIdleSync();
1493     }
1494 
testUndo_directInsert()1495     public void testUndo_directInsert() {
1496         initTextViewForTyping();
1497 
1498         // Type some text.
1499         mInstrumentation.sendStringSync("abc");
1500         mActivity.runOnUiThread(new Runnable() {
1501             public void run() {
1502                 // Directly modify the underlying Editable to insert some text.
1503                 // NOTE: This is a violation of the API of getText() which specifies that the
1504                 // returned object should not be modified. However, some apps do this anyway and
1505                 // the framework needs to handle it.
1506                 Editable text = (Editable) mTextView.getText();
1507                 text.insert(0, "def");
1508                 assertEquals("defabc", mTextView.getText().toString());
1509 
1510                 // Undo removes the insert as a separate step.
1511                 mTextView.onTextContextMenuItem(android.R.id.undo);
1512                 assertEquals("abc", mTextView.getText().toString());
1513 
1514                 // Another undo removes the original typing.
1515                 mTextView.onTextContextMenuItem(android.R.id.undo);
1516                 assertEquals("", mTextView.getText().toString());
1517             }
1518         });
1519         mInstrumentation.waitForIdleSync();
1520     }
1521 
testUndo_noCursor()1522     public void testUndo_noCursor() {
1523         initTextViewForTyping();
1524 
1525         mActivity.runOnUiThread(new Runnable() {
1526             public void run() {
1527                 // Append some text to create an undo operation. There is no cursor present.
1528                 mTextView.append("cat");
1529 
1530                 // Place the cursor at the end of the text so the undo will have to change it.
1531                 Selection.setSelection((Spannable) mTextView.getText(), 3);
1532 
1533                 // Undo the append. This should not crash, despite not having a valid cursor
1534                 // position in the undo operation.
1535                 mTextView.onTextContextMenuItem(android.R.id.undo);
1536             }
1537         });
1538         mInstrumentation.waitForIdleSync();
1539     }
1540 
testUndo_textWatcher()1541     public void testUndo_textWatcher() {
1542         initTextViewForTyping();
1543 
1544         // Add a TextWatcher that converts the text to spaces on each change.
1545         mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
1546 
1547         // Type some text.
1548         mInstrumentation.sendStringSync("abc");
1549         mActivity.runOnUiThread(new Runnable() {
1550             public void run() {
1551                 // TextWatcher altered the text.
1552                 assertEquals("   ", mTextView.getText().toString());
1553 
1554                 // Undo reverses both changes in one step.
1555                 mTextView.onTextContextMenuItem(android.R.id.undo);
1556                 assertEquals("", mTextView.getText().toString());
1557             }
1558         });
1559         mInstrumentation.waitForIdleSync();
1560     }
1561 
testUndo_textWatcherDirectAppend()1562     public void testUndo_textWatcherDirectAppend() {
1563         initTextViewForTyping();
1564 
1565         // Add a TextWatcher that converts the text to spaces on each change.
1566         mTextView.addTextChangedListener(new ConvertToSpacesTextWatcher());
1567 
1568         mActivity.runOnUiThread(new Runnable() {
1569             public void run() {
1570                 // Programmatically append some text. The TextWatcher changes it to spaces.
1571                 mTextView.append("abc");
1572                 assertEquals("   ", mTextView.getText().toString());
1573 
1574                 // Undo reverses both changes in one step.
1575                 mTextView.onTextContextMenuItem(android.R.id.undo);
1576                 assertEquals("", mTextView.getText().toString());
1577             }
1578         });
1579         mInstrumentation.waitForIdleSync();
1580     }
1581 
testUndo_shortcuts()1582     public void testUndo_shortcuts() {
1583         initTextViewForTyping();
1584 
1585         // Type some text.
1586         mInstrumentation.sendStringSync("abc");
1587         mActivity.runOnUiThread(new Runnable() {
1588             public void run() {
1589                 // Pressing Control-Z triggers undo.
1590                 KeyEvent control = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z, 0,
1591                         KeyEvent.META_CTRL_LEFT_ON);
1592                 assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, control));
1593                 assertEquals("", mTextView.getText().toString());
1594 
1595                 // Pressing Control-Shift-Z triggers redo.
1596                 KeyEvent controlShift = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_Z,
1597                         0, KeyEvent.META_CTRL_LEFT_ON | KeyEvent.META_SHIFT_LEFT_ON);
1598                 assertTrue(mTextView.onKeyShortcut(KeyEvent.KEYCODE_Z, controlShift));
1599                 assertEquals("abc", mTextView.getText().toString());
1600             }
1601         });
1602         mInstrumentation.waitForIdleSync();
1603     }
1604 
testUndo_saveInstanceState()1605     public void testUndo_saveInstanceState() {
1606         initTextViewForTyping();
1607 
1608         // Type some text to create an undo operation.
1609         mInstrumentation.sendStringSync("abc");
1610         mActivity.runOnUiThread(new Runnable() {
1611             public void run() {
1612                 // Parcel and unparcel the TextView.
1613                 Parcelable state = mTextView.onSaveInstanceState();
1614                 mTextView.onRestoreInstanceState(state);
1615             }
1616         });
1617         mInstrumentation.waitForIdleSync();
1618 
1619         // Delete a character to create a new undo operation.
1620         sendKeys(KeyEvent.KEYCODE_DEL);
1621         mActivity.runOnUiThread(new Runnable() {
1622             public void run() {
1623                 assertEquals("ab", mTextView.getText().toString());
1624 
1625                 // Undo the delete.
1626                 mTextView.onTextContextMenuItem(android.R.id.undo);
1627                 assertEquals("abc", mTextView.getText().toString());
1628 
1629                 // Undo the typing, which verifies that the original undo operation was parceled
1630                 // correctly.
1631                 mTextView.onTextContextMenuItem(android.R.id.undo);
1632                 assertEquals("", mTextView.getText().toString());
1633 
1634                 // Parcel and unparcel the undo stack (which is empty but has been used and may
1635                 // contain other state).
1636                 Parcelable state = mTextView.onSaveInstanceState();
1637                 mTextView.onRestoreInstanceState(state);
1638             }
1639         });
1640         mInstrumentation.waitForIdleSync();
1641     }
1642 
testUndo_saveInstanceStateEmpty()1643     public void testUndo_saveInstanceStateEmpty() {
1644         initTextViewForTyping();
1645 
1646         // Type and delete to create two new undo operations.
1647         mInstrumentation.sendStringSync("a");
1648         sendKeys(KeyEvent.KEYCODE_DEL);
1649         mActivity.runOnUiThread(new Runnable() {
1650             public void run() {
1651                 // Empty the undo stack then parcel and unparcel the TextView. While the undo
1652                 // stack contains no operations it may contain other state.
1653                 mTextView.onTextContextMenuItem(android.R.id.undo);
1654                 mTextView.onTextContextMenuItem(android.R.id.undo);
1655                 Parcelable state = mTextView.onSaveInstanceState();
1656                 mTextView.onRestoreInstanceState(state);
1657             }
1658         });
1659         mInstrumentation.waitForIdleSync();
1660 
1661         // Create two more undo operations.
1662         mInstrumentation.sendStringSync("b");
1663         sendKeys(KeyEvent.KEYCODE_DEL);
1664         mActivity.runOnUiThread(new Runnable() {
1665             public void run() {
1666                 // Verify undo still works.
1667                 mTextView.onTextContextMenuItem(android.R.id.undo);
1668                 assertEquals("b", mTextView.getText().toString());
1669                 mTextView.onTextContextMenuItem(android.R.id.undo);
1670                 assertEquals("", mTextView.getText().toString());
1671             }
1672         });
1673         mInstrumentation.waitForIdleSync();
1674     }
1675 
testCopyAndPaste()1676     public void testCopyAndPaste() {
1677         initTextViewForTyping();
1678         mActivity.runOnUiThread(new Runnable() {
1679             public void run() {
1680                 mTextView.setText("abcd", BufferType.EDITABLE);
1681                 mTextView.setSelected(true);
1682 
1683                 // Copy "bc".
1684                 Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
1685                 mTextView.onTextContextMenuItem(android.R.id.copy);
1686 
1687                 // Paste "bc" between "b" and "c".
1688                 Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
1689                 mTextView.onTextContextMenuItem(android.R.id.paste);
1690                 assertEquals("abbccd", mTextView.getText().toString());
1691 
1692                 // Select entire text and paste "bc".
1693                 Selection.selectAll((Spannable) mTextView.getText());
1694                 mTextView.onTextContextMenuItem(android.R.id.paste);
1695                 assertEquals("bc", mTextView.getText().toString());
1696             }
1697         });
1698         mInstrumentation.waitForIdleSync();
1699     }
1700 
testCutAndPaste()1701     public void testCutAndPaste() {
1702         initTextViewForTyping();
1703         mActivity.runOnUiThread(new Runnable() {
1704             public void run() {
1705                 mTextView.setText("abcd", BufferType.EDITABLE);
1706                 mTextView.setSelected(true);
1707 
1708                 // Cut "bc".
1709                 Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
1710                 mTextView.onTextContextMenuItem(android.R.id.cut);
1711                 assertEquals("ad", mTextView.getText().toString());
1712 
1713                 // Cut "ad".
1714                 Selection.setSelection((Spannable) mTextView.getText(), 0, 2);
1715                 mTextView.onTextContextMenuItem(android.R.id.cut);
1716                 assertEquals("", mTextView.getText().toString());
1717 
1718                 // Paste "ad".
1719                 mTextView.onTextContextMenuItem(android.R.id.paste);
1720                 assertEquals("ad", mTextView.getText().toString());
1721             }
1722         });
1723         mInstrumentation.waitForIdleSync();
1724     }
1725 
hasSpansAtMiddleOfText(final TextView textView, final Class<?> type)1726     private static boolean hasSpansAtMiddleOfText(final TextView textView, final Class<?> type) {
1727         final Spannable spannable = (Spannable)textView.getText();
1728         final int at = spannable.length() / 2;
1729         return spannable.getSpans(at, at, type).length > 0;
1730     }
1731 
testCutAndPaste_withAndWithoutStyle()1732     public void testCutAndPaste_withAndWithoutStyle() {
1733         initTextViewForTyping();
1734         mActivity.runOnUiThread(new Runnable() {
1735             public void run() {
1736                 mTextView.setText("example", BufferType.EDITABLE);
1737                 mTextView.setSelected(true);
1738 
1739                 // Set URLSpan.
1740                 final Spannable spannable = (Spannable) mTextView.getText();
1741                 spannable.setSpan(new URLSpan("http://example.com"), 0, spannable.length(), 0);
1742                 assertTrue(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
1743 
1744                 // Cut entire text.
1745                 Selection.selectAll((Spannable) mTextView.getText());
1746                 mTextView.onTextContextMenuItem(android.R.id.cut);
1747                 assertEquals("", mTextView.getText().toString());
1748 
1749                 // Paste without style.
1750                 mTextView.onTextContextMenuItem(android.R.id.pasteAsPlainText);
1751                 assertEquals("example", mTextView.getText().toString());
1752                 // Check that the text doesn't have URLSpan.
1753                 assertFalse(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
1754 
1755                 // Paste with style.
1756                 Selection.selectAll((Spannable) mTextView.getText());
1757                 mTextView.onTextContextMenuItem(android.R.id.paste);
1758                 assertEquals("example", mTextView.getText().toString());
1759                 // Check that the text has URLSpan.
1760                 assertTrue(hasSpansAtMiddleOfText(mTextView, URLSpan.class));
1761             }
1762         });
1763         mInstrumentation.waitForIdleSync();
1764     }
1765 
1766     @UiThreadTest
testSaveInstanceState()1767     public void testSaveInstanceState() {
1768         TextView originalTextView = new TextView(mActivity);
1769         final String text = "This is a string";
1770         originalTextView.setText(text);
1771         originalTextView.setFreezesText(true);  // needed to actually save state
1772         Parcelable state = originalTextView.onSaveInstanceState();
1773 
1774         TextView restoredTextView = new TextView(mActivity);
1775         restoredTextView.onRestoreInstanceState(state);
1776         assertEquals(text, restoredTextView.getText().toString());
1777     }
1778 
1779     @UiThreadTest
testSaveInstanceStateSelection()1780     public void testSaveInstanceStateSelection() {
1781         TextView originalTextView = new TextView(mActivity);
1782         final String text = "This is a string";
1783         final Spannable spannable = new SpannableString(text);
1784         originalTextView.setText(spannable);
1785         originalTextView.setTextIsSelectable(true);
1786         Selection.setSelection((Spannable) originalTextView.getText(), 5, 7);
1787         originalTextView.setFreezesText(true);  // needed to actually save state
1788         Parcelable state = originalTextView.onSaveInstanceState();
1789 
1790         TextView restoredTextView = new TextView(mActivity);
1791         // Setting a selection only has an effect on a TextView when it is selectable.
1792         restoredTextView.setTextIsSelectable(true);
1793         restoredTextView.onRestoreInstanceState(state);
1794         assertEquals(text, restoredTextView.getText().toString());
1795         assertEquals(5, restoredTextView.getSelectionStart());
1796         assertEquals(7, restoredTextView.getSelectionEnd());
1797     }
1798 
1799     @UiThreadTest
testSetText()1800     public void testSetText() {
1801         TextView tv = findTextView(R.id.textview_text);
1802 
1803         int resId = R.string.text_view_hint;
1804         String result = mActivity.getResources().getString(resId);
1805 
1806         tv.setText(resId, BufferType.EDITABLE);
1807         assertEquals(result, tv.getText().toString());
1808         assertTrue(tv.getText() instanceof Editable);
1809 
1810         tv.setText(resId, BufferType.SPANNABLE);
1811         assertEquals(result, tv.getText().toString());
1812         assertTrue(tv.getText() instanceof Spannable);
1813 
1814         try {
1815             tv.setText(-1, BufferType.EDITABLE);
1816             fail("Should throw exception with illegal id");
1817         } catch (NotFoundException e) {
1818         }
1819     }
1820 
1821     @UiThreadTest
testAccessHint()1822     public void testAccessHint() {
1823         mActivity.setContentView(R.layout.textview_hint_linksclickable_freezestext);
1824 
1825         mTextView = findTextView(R.id.hint_linksClickable_freezesText_default);
1826         assertNull(mTextView.getHint());
1827 
1828         mTextView = findTextView(R.id.hint_blank);
1829         assertEquals("", mTextView.getHint());
1830 
1831         mTextView = findTextView(R.id.hint_string);
1832         assertEquals(mActivity.getResources().getString(R.string.text_view_simple_hint),
1833                 mTextView.getHint());
1834 
1835         mTextView = findTextView(R.id.hint_resid);
1836         assertEquals(mActivity.getResources().getString(R.string.text_view_hint),
1837                 mTextView.getHint());
1838 
1839         mTextView.setHint("This is hint");
1840         assertEquals("This is hint", mTextView.getHint().toString());
1841 
1842         mTextView.setHint(R.string.text_view_hello);
1843         assertEquals(mActivity.getResources().getString(R.string.text_view_hello),
1844                 mTextView.getHint().toString());
1845 
1846         // Non-exist resid
1847         try {
1848             mTextView.setHint(-1);
1849             fail("Should throw exception if id is illegal");
1850         } catch (NotFoundException e) {
1851         }
1852     }
1853 
testAccessError()1854     public void testAccessError() {
1855         mTextView = findTextView(R.id.textview_text);
1856         assertNull(mTextView.getError());
1857 
1858         final String errorText = "Oops! There is an error";
1859 
1860         mActivity.runOnUiThread(new Runnable() {
1861             public void run() {
1862                 mTextView.setError(null);
1863             }
1864         });
1865         mInstrumentation.waitForIdleSync();
1866         assertNull(mTextView.getError());
1867 
1868         final Drawable icon = getDrawable(R.drawable.failed);
1869         mActivity.runOnUiThread(new Runnable() {
1870             public void run() {
1871                 mTextView.setError(errorText, icon);
1872             }
1873         });
1874         mInstrumentation.waitForIdleSync();
1875         assertEquals(errorText, mTextView.getError().toString());
1876         // can not check whether the drawable is set correctly
1877 
1878         mActivity.runOnUiThread(new Runnable() {
1879             public void run() {
1880                 mTextView.setError(null, null);
1881             }
1882         });
1883         mInstrumentation.waitForIdleSync();
1884         assertNull(mTextView.getError());
1885 
1886         mActivity.runOnUiThread(new Runnable() {
1887             public void run() {
1888                 mTextView.setKeyListener(DigitsKeyListener.getInstance(""));
1889                 mTextView.setText("", BufferType.EDITABLE);
1890                 mTextView.setError(errorText);
1891                 mTextView.requestFocus();
1892             }
1893         });
1894         mInstrumentation.waitForIdleSync();
1895 
1896         assertEquals(errorText, mTextView.getError().toString());
1897 
1898         mInstrumentation.sendStringSync("a");
1899         // a key event that will not change the TextView's text
1900         assertEquals("", mTextView.getText().toString());
1901         // The icon and error message will not be reset to null
1902         assertEquals(errorText, mTextView.getError().toString());
1903 
1904         mActivity.runOnUiThread(new Runnable() {
1905             public void run() {
1906                 mTextView.setKeyListener(DigitsKeyListener.getInstance());
1907                 mTextView.setText("", BufferType.EDITABLE);
1908                 mTextView.setError(errorText);
1909                 mTextView.requestFocus();
1910             }
1911         });
1912         mInstrumentation.waitForIdleSync();
1913 
1914         mInstrumentation.sendStringSync("1");
1915         // a key event cause changes to the TextView's text
1916         assertEquals("1", mTextView.getText().toString());
1917         // the error message and icon will be cleared.
1918         assertNull(mTextView.getError());
1919     }
1920 
testAccessFilters()1921     public void testAccessFilters() {
1922         final InputFilter[] expected = { new InputFilter.AllCaps(),
1923                 new InputFilter.LengthFilter(2) };
1924 
1925         final QwertyKeyListener qwertyKeyListener
1926                 = QwertyKeyListener.getInstance(false, Capitalize.NONE);
1927         mActivity.runOnUiThread(new Runnable() {
1928             public void run() {
1929                 mTextView = findTextView(R.id.textview_text);
1930                 mTextView.setKeyListener(qwertyKeyListener);
1931                 mTextView.setText("", BufferType.EDITABLE);
1932                 mTextView.setFilters(expected);
1933                 mTextView.requestFocus();
1934             }
1935         });
1936         mInstrumentation.waitForIdleSync();
1937 
1938         assertSame(expected, mTextView.getFilters());
1939 
1940         mInstrumentation.sendStringSync("a");
1941         // the text is capitalized by InputFilter.AllCaps
1942         assertEquals("A", mTextView.getText().toString());
1943         mInstrumentation.sendStringSync("b");
1944         // the text is capitalized by InputFilter.AllCaps
1945         assertEquals("AB", mTextView.getText().toString());
1946         mInstrumentation.sendStringSync("c");
1947         // 'C' could not be accepted, because there is a length filter.
1948         assertEquals("AB", mTextView.getText().toString());
1949 
1950         try {
1951             mTextView.setFilters(null);
1952             fail("Should throw IllegalArgumentException!");
1953         } catch (IllegalArgumentException e) {
1954         }
1955     }
1956 
testGetFocusedRect()1957     public void testGetFocusedRect() {
1958         Rect rc = new Rect();
1959 
1960         // Basic
1961         mTextView = new TextView(mActivity);
1962         mTextView.getFocusedRect(rc);
1963         assertEquals(mTextView.getScrollX(), rc.left);
1964         assertEquals(mTextView.getScrollX() + mTextView.getWidth(), rc.right);
1965         assertEquals(mTextView.getScrollY(), rc.top);
1966         assertEquals(mTextView.getScrollY() + mTextView.getHeight(), rc.bottom);
1967 
1968         // Single line
1969         mTextView = findTextView(R.id.textview_text);
1970         mTextView.getFocusedRect(rc);
1971         assertEquals(mTextView.getScrollX(), rc.left);
1972         assertEquals(mTextView.getScrollX() + mTextView.getWidth(), rc.right);
1973         assertEquals(mTextView.getScrollY(), rc.top);
1974         assertEquals(mTextView.getScrollY() + mTextView.getHeight(), rc.bottom);
1975 
1976         mActivity.runOnUiThread(new Runnable() {
1977             public void run() {
1978                 mTextView.setSelected(true);
1979                 SpannableString text = new SpannableString(mTextView.getText());
1980                 Selection.setSelection(text, 3, 13);
1981                 mTextView.setText(text);
1982             }
1983         });
1984         mInstrumentation.waitForIdleSync();
1985         mTextView.getFocusedRect(rc);
1986         assertNotNull(mTextView.getLayout());
1987         /* Cursor coordinates from getPrimaryHorizontal() may have a fractional
1988          * component, while the result of getFocusedRect is in int coordinates.
1989          * It's not practical for these to match exactly, so we compare that the
1990          * integer components match - there can be a fractional pixel
1991          * discrepancy, which should be okay for all practical applications. */
1992         assertEquals((int) mTextView.getLayout().getPrimaryHorizontal(3), rc.left);
1993         assertEquals((int) mTextView.getLayout().getPrimaryHorizontal(13), rc.right);
1994         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
1995         assertEquals(mTextView.getLayout().getLineBottom(0), rc.bottom);
1996 
1997         mActivity.runOnUiThread(new Runnable() {
1998             public void run() {
1999                 mTextView.setSelected(true);
2000                 SpannableString text = new SpannableString(mTextView.getText());
2001                 Selection.setSelection(text, 13, 3);
2002                 mTextView.setText(text);
2003             }
2004         });
2005         mInstrumentation.waitForIdleSync();
2006         mTextView.getFocusedRect(rc);
2007         assertNotNull(mTextView.getLayout());
2008         assertEquals((int) mTextView.getLayout().getPrimaryHorizontal(3) - 2, rc.left);
2009         assertEquals((int) mTextView.getLayout().getPrimaryHorizontal(3) + 2, rc.right);
2010         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
2011         assertEquals(mTextView.getLayout().getLineBottom(0), rc.bottom);
2012 
2013         // Multi lines
2014         mTextView = findTextView(R.id.textview_text_two_lines);
2015         mTextView.getFocusedRect(rc);
2016         assertEquals(mTextView.getScrollX(), rc.left);
2017         assertEquals(mTextView.getScrollX() + mTextView.getWidth(), rc.right);
2018         assertEquals(mTextView.getScrollY(), rc.top);
2019         assertEquals(mTextView.getScrollY() + mTextView.getHeight(), rc.bottom);
2020 
2021         mActivity.runOnUiThread(new Runnable() {
2022             public void run() {
2023                 mTextView.setSelected(true);
2024                 SpannableString text = new SpannableString(mTextView.getText());
2025                 Selection.setSelection(text, 2, 4);
2026                 mTextView.setText(text);
2027             }
2028         });
2029         mInstrumentation.waitForIdleSync();
2030         mTextView.getFocusedRect(rc);
2031         assertNotNull(mTextView.getLayout());
2032         assertEquals((int) mTextView.getLayout().getPrimaryHorizontal(2), rc.left);
2033         assertEquals((int) mTextView.getLayout().getPrimaryHorizontal(4), rc.right);
2034         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
2035         assertEquals(mTextView.getLayout().getLineBottom(0), rc.bottom);
2036 
2037         mActivity.runOnUiThread(new Runnable() {
2038             public void run() {
2039                 mTextView.setSelected(true);
2040                 SpannableString text = new SpannableString(mTextView.getText());
2041                 Selection.setSelection(text, 2, 10); // cross the "\n" and two lines
2042                 mTextView.setText(text);
2043             }
2044         });
2045         mInstrumentation.waitForIdleSync();
2046         mTextView.getFocusedRect(rc);
2047         Path path = new Path();
2048         mTextView.getLayout().getSelectionPath(2, 10, path);
2049         RectF rcf = new RectF();
2050         path.computeBounds(rcf, true);
2051         assertNotNull(mTextView.getLayout());
2052         assertEquals(rcf.left - 1, (float) rc.left);
2053         assertEquals(rcf.right + 1, (float) rc.right);
2054         assertEquals(mTextView.getLayout().getLineTop(0), rc.top);
2055         assertEquals(mTextView.getLayout().getLineBottom(1), rc.bottom);
2056 
2057         // Exception
2058         try {
2059             mTextView.getFocusedRect(null);
2060             fail("Should throw NullPointerException!");
2061         } catch (NullPointerException e) {
2062         }
2063     }
2064 
testGetLineCount()2065     public void testGetLineCount() {
2066         mTextView = findTextView(R.id.textview_text);
2067         // this is an one line text with default setting.
2068         assertEquals(1, mTextView.getLineCount());
2069 
2070         // make it multi-lines
2071         setMaxWidth(mTextView.getWidth() / 3);
2072         assertTrue(1 < mTextView.getLineCount());
2073 
2074         // make it to an one line
2075         setMaxWidth(Integer.MAX_VALUE);
2076         assertEquals(1, mTextView.getLineCount());
2077 
2078         // set min lines don't effect the lines count for actual text.
2079         setMinLines(12);
2080         assertEquals(1, mTextView.getLineCount());
2081 
2082         mTextView = new TextView(mActivity);
2083         // the internal Layout has not been built.
2084         assertNull(mTextView.getLayout());
2085         assertEquals(0, mTextView.getLineCount());
2086     }
2087 
testGetLineBounds()2088     public void testGetLineBounds() {
2089         Rect rc = new Rect();
2090         mTextView = new TextView(mActivity);
2091         assertEquals(0, mTextView.getLineBounds(0, null));
2092 
2093         assertEquals(0, mTextView.getLineBounds(0, rc));
2094         assertEquals(0, rc.left);
2095         assertEquals(0, rc.right);
2096         assertEquals(0, rc.top);
2097         assertEquals(0, rc.bottom);
2098 
2099         mTextView = findTextView(R.id.textview_text);
2100         assertEquals(mTextView.getBaseline(), mTextView.getLineBounds(0, null));
2101 
2102         assertEquals(mTextView.getBaseline(), mTextView.getLineBounds(0, rc));
2103         assertEquals(0, rc.left);
2104         assertEquals(mTextView.getWidth(), rc.right);
2105         assertEquals(0, rc.top);
2106         assertEquals(mTextView.getHeight(), rc.bottom);
2107 
2108         mActivity.runOnUiThread(new Runnable() {
2109             public void run() {
2110                 mTextView.setPadding(1, 2, 3, 4);
2111                 mTextView.setGravity(Gravity.BOTTOM);
2112             }
2113         });
2114         mInstrumentation.waitForIdleSync();
2115         assertEquals(mTextView.getBaseline(), mTextView.getLineBounds(0, rc));
2116         assertEquals(mTextView.getTotalPaddingLeft(), rc.left);
2117         assertEquals(mTextView.getWidth() - mTextView.getTotalPaddingRight(), rc.right);
2118         assertEquals(mTextView.getTotalPaddingTop(), rc.top);
2119         assertEquals(mTextView.getHeight() - mTextView.getTotalPaddingBottom(), rc.bottom);
2120     }
2121 
testGetBaseLine()2122     public void testGetBaseLine() {
2123         mTextView = new TextView(mActivity);
2124         assertEquals(-1, mTextView.getBaseline());
2125 
2126         mTextView = findTextView(R.id.textview_text);
2127         assertEquals(mTextView.getLayout().getLineBaseline(0), mTextView.getBaseline());
2128 
2129         mActivity.runOnUiThread(new Runnable() {
2130             public void run() {
2131                 mTextView.setPadding(1, 2, 3, 4);
2132                 mTextView.setGravity(Gravity.BOTTOM);
2133             }
2134         });
2135         mInstrumentation.waitForIdleSync();
2136         int expected = mTextView.getTotalPaddingTop() + mTextView.getLayout().getLineBaseline(0);
2137         assertEquals(expected, mTextView.getBaseline());
2138     }
2139 
testPressKey()2140     public void testPressKey() {
2141         initTextViewForTyping();
2142 
2143         mInstrumentation.sendStringSync("a");
2144         assertEquals("a", mTextView.getText().toString());
2145         mInstrumentation.sendStringSync("b");
2146         assertEquals("ab", mTextView.getText().toString());
2147         sendKeys(KeyEvent.KEYCODE_DEL);
2148         assertEquals("a", mTextView.getText().toString());
2149     }
2150 
testSetIncludeFontPadding()2151     public void testSetIncludeFontPadding() {
2152         mTextView = findTextView(R.id.textview_text);
2153         mActivity.runOnUiThread(new Runnable() {
2154             public void run() {
2155                 mTextView.setWidth(mTextView.getWidth() / 3);
2156                 mTextView.setPadding(1, 2, 3, 4);
2157                 mTextView.setGravity(Gravity.BOTTOM);
2158             }
2159         });
2160         mInstrumentation.waitForIdleSync();
2161 
2162         int oldHeight = mTextView.getHeight();
2163         mActivity.runOnUiThread(new Runnable() {
2164             public void run() {
2165                 mTextView.setIncludeFontPadding(false);
2166             }
2167         });
2168         mInstrumentation.waitForIdleSync();
2169 
2170         assertTrue(mTextView.getHeight() < oldHeight);
2171     }
2172 
2173     public void testScroll() {
2174         mTextView = new TextView(mActivity);
2175 
2176         assertEquals(0, mTextView.getScrollX());
2177         assertEquals(0, mTextView.getScrollY());
2178 
2179         //don't set the Scroller, nothing changed.
2180         mTextView.computeScroll();
2181         assertEquals(0, mTextView.getScrollX());
2182         assertEquals(0, mTextView.getScrollY());
2183 
2184         //set the Scroller
2185         Scroller s = new Scroller(mActivity);
2186         assertNotNull(s);
2187         s.startScroll(0, 0, 320, 480, 0);
2188         s.abortAnimation();
2189         s.forceFinished(false);
2190         mTextView.setScroller(s);
2191 
2192         mTextView.computeScroll();
2193         assertEquals(320, mTextView.getScrollX());
2194         assertEquals(480, mTextView.getScrollY());
2195     }
2196 
2197     public void testDebug() {
2198         mTextView = new TextView(mActivity);
2199         mTextView.debug(0);
2200 
2201         mTextView.setText("Hello!");
2202         layout(mTextView);
2203         mTextView.debug(1);
2204     }
2205 
2206     public void testSelection() {
2207         mTextView = new TextView(mActivity);
2208         String text = "This is the content";
2209         mTextView.setText(text, BufferType.SPANNABLE);
2210         assertFalse(mTextView.hasSelection());
2211 
2212         Selection.selectAll((Spannable) mTextView.getText());
2213         assertEquals(0, mTextView.getSelectionStart());
2214         assertEquals(text.length(), mTextView.getSelectionEnd());
2215         assertTrue(mTextView.hasSelection());
2216 
2217         int selectionStart = 5;
2218         int selectionEnd = 7;
2219         Selection.setSelection((Spannable) mTextView.getText(), selectionStart);
2220         assertEquals(selectionStart, mTextView.getSelectionStart());
2221         assertEquals(selectionStart, mTextView.getSelectionEnd());
2222         assertFalse(mTextView.hasSelection());
2223 
2224         Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
2225         assertEquals(selectionStart, mTextView.getSelectionStart());
2226         assertEquals(selectionEnd, mTextView.getSelectionEnd());
2227         assertTrue(mTextView.hasSelection());
2228     }
2229 
2230     @UiThreadTest
2231     public void testAccessEllipsize() {
2232         mActivity.setContentView(R.layout.textview_ellipsize);
2233 
2234         mTextView = findTextView(R.id.ellipsize_default);
2235         assertNull(mTextView.getEllipsize());
2236 
2237         mTextView = findTextView(R.id.ellipsize_none);
2238         assertNull(mTextView.getEllipsize());
2239 
2240         mTextView = findTextView(R.id.ellipsize_start);
2241         assertSame(TruncateAt.START, mTextView.getEllipsize());
2242 
2243         mTextView = findTextView(R.id.ellipsize_middle);
2244         assertSame(TruncateAt.MIDDLE, mTextView.getEllipsize());
2245 
2246         mTextView = findTextView(R.id.ellipsize_end);
2247         assertSame(TruncateAt.END, mTextView.getEllipsize());
2248 
2249         mTextView.setEllipsize(TextUtils.TruncateAt.START);
2250         assertSame(TextUtils.TruncateAt.START, mTextView.getEllipsize());
2251 
2252         mTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
2253         assertSame(TextUtils.TruncateAt.MIDDLE, mTextView.getEllipsize());
2254 
2255         mTextView.setEllipsize(TextUtils.TruncateAt.END);
2256         assertSame(TextUtils.TruncateAt.END, mTextView.getEllipsize());
2257 
2258         mTextView.setEllipsize(null);
2259         assertNull(mTextView.getEllipsize());
2260 
2261         mTextView.setWidth(10);
2262         mTextView.setEllipsize(TextUtils.TruncateAt.START);
2263         mTextView.setText("ThisIsAVeryLongVeryLongVeryLongVeryLongVeryLongWord");
2264         mTextView.invalidate();
2265 
2266         assertSame(TextUtils.TruncateAt.START, mTextView.getEllipsize());
2267         // there is no method to check if '...yLongVeryLongWord' is painted in the screen.
2268     }
2269 
2270     public void testSetCursorVisible() {
2271         mTextView = new TextView(mActivity);
2272 
2273         mTextView.setCursorVisible(true);
2274         mTextView.setCursorVisible(false);
2275     }
2276 
2277     public void testOnWindowFocusChanged() {
2278         // Do not test. Implementation details.
2279     }
2280 
2281     public void testOnTouchEvent() {
2282         // Do not test. Implementation details.
2283     }
2284 
2285     public void testOnTrackballEvent() {
2286         // Do not test. Implementation details.
2287     }
2288 
2289     public void testGetTextColors() {
2290         // TODO: How to get a suitable TypedArray to test this method.
2291     }
2292 
2293     public void testOnKeyShortcut() {
2294         // Do not test. Implementation details.
2295     }
2296 
2297     @UiThreadTest
2298     public void testPerformLongClick() {
2299         mTextView = findTextView(R.id.textview_text);
2300         mTextView.setText("This is content");
2301         MockOnLongClickListener onLongClickListener = new MockOnLongClickListener(true);
2302         MockOnCreateContextMenuListener onCreateContextMenuListener
2303                 = new MockOnCreateContextMenuListener(false);
2304         mTextView.setOnLongClickListener(onLongClickListener);
2305         mTextView.setOnCreateContextMenuListener(onCreateContextMenuListener);
2306         assertTrue(mTextView.performLongClick());
2307         assertTrue(onLongClickListener.hasLongClicked());
2308         assertFalse(onCreateContextMenuListener.hasCreatedContextMenu());
2309 
2310         onLongClickListener = new MockOnLongClickListener(false);
2311         mTextView.setOnLongClickListener(onLongClickListener);
2312         mTextView.setOnCreateContextMenuListener(onCreateContextMenuListener);
2313         assertTrue(mTextView.performLongClick());
2314         assertTrue(onLongClickListener.hasLongClicked());
2315         assertTrue(onCreateContextMenuListener.hasCreatedContextMenu());
2316 
2317         mTextView.setOnLongClickListener(null);
2318         onCreateContextMenuListener = new MockOnCreateContextMenuListener(true);
2319         mTextView.setOnCreateContextMenuListener(onCreateContextMenuListener);
2320         assertFalse(mTextView.performLongClick());
2321         assertTrue(onCreateContextMenuListener.hasCreatedContextMenu());
2322     }
2323 
2324     @UiThreadTest
2325     public void testTextAttr() {
2326         mTextView = findTextView(R.id.textview_textAttr);
2327         // getText
2328         assertEquals(mActivity.getString(R.string.text_view_hello), mTextView.getText().toString());
2329 
2330         // getCurrentTextColor
2331         assertEquals(mActivity.getResources().getColor(R.drawable.black),
2332                 mTextView.getCurrentTextColor());
2333         assertEquals(mActivity.getResources().getColor(R.drawable.red),
2334                 mTextView.getCurrentHintTextColor());
2335         assertEquals(mActivity.getResources().getColor(R.drawable.red),
2336                 mTextView.getHintTextColors().getDefaultColor());
2337         assertEquals(mActivity.getResources().getColor(R.drawable.blue),
2338                 mTextView.getLinkTextColors().getDefaultColor());
2339 
2340         // getTextScaleX
2341         assertEquals(1.2f, mTextView.getTextScaleX(), 0.01f);
2342 
2343         // setTextScaleX
2344         mTextView.setTextScaleX(2.4f);
2345         assertEquals(2.4f, mTextView.getTextScaleX(), 0.01f);
2346 
2347         mTextView.setTextScaleX(0f);
2348         assertEquals(0f, mTextView.getTextScaleX(), 0.01f);
2349 
2350         mTextView.setTextScaleX(- 2.4f);
2351         assertEquals(- 2.4f, mTextView.getTextScaleX(), 0.01f);
2352 
2353         // getTextSize
2354         assertEquals(20f, mTextView.getTextSize(), 0.01f);
2355 
2356         // getTypeface
2357         // getTypeface will be null if android:typeface is set to normal,
2358         // and android:style is not set or is set to normal, and
2359         // android:fontFamily is not set
2360         assertNull(mTextView.getTypeface());
2361 
2362         mTextView.setTypeface(Typeface.DEFAULT);
2363         assertSame(Typeface.DEFAULT, mTextView.getTypeface());
2364         // null type face
2365         mTextView.setTypeface(null);
2366         assertNull(mTextView.getTypeface());
2367 
2368         // default type face, bold style, note: the type face will be changed
2369         // after call set method
2370         mTextView.setTypeface(Typeface.DEFAULT, Typeface.BOLD);
2371         assertSame(Typeface.BOLD, mTextView.getTypeface().getStyle());
2372 
2373         // null type face, BOLD style
2374         mTextView.setTypeface(null, Typeface.BOLD);
2375         assertSame(Typeface.BOLD, mTextView.getTypeface().getStyle());
2376 
2377         // old type face, null style
2378         mTextView.setTypeface(Typeface.DEFAULT, 0);
2379         assertEquals(Typeface.NORMAL, mTextView.getTypeface().getStyle());
2380     }
2381 
2382     @UiThreadTest
2383     public void testAppend() {
2384         mTextView = new TextView(mActivity);
2385 
2386         // 1: check the original length, should be blank as initialised.
2387         assertEquals(0, mTextView.getText().length());
2388 
2389         // 2: append a string use append(CharSquence) into the original blank
2390         // buffer, check the content. And upgrading it to BufferType.EDITABLE if it was
2391         // not already editable.
2392         assertFalse(mTextView.getText() instanceof Editable);
2393         mTextView.append("Append.");
2394         assertEquals("Append.", mTextView.getText().toString());
2395         assertTrue(mTextView.getText() instanceof Editable);
2396 
2397         // 3: append a string from 0~3.
2398         mTextView.append("Append", 0, 3);
2399         assertEquals("Append.App", mTextView.getText().toString());
2400         assertTrue(mTextView.getText() instanceof Editable);
2401 
2402         // 4: append a string from 0~0, nothing will be append as expected.
2403         mTextView.append("Append", 0, 0);
2404         assertEquals("Append.App", mTextView.getText().toString());
2405         assertTrue(mTextView.getText() instanceof Editable);
2406 
2407         // 5: append a string from -3~3. check the wrong left edge.
2408         try {
2409             mTextView.append("Append", -3, 3);
2410             fail("Should throw StringIndexOutOfBoundsException");
2411         } catch (StringIndexOutOfBoundsException e) {
2412         }
2413 
2414         // 6: append a string from 3~10. check the wrong right edge.
2415         try {
2416             mTextView.append("Append", 3, 10);
2417             fail("Should throw StringIndexOutOfBoundsException");
2418         } catch (StringIndexOutOfBoundsException e) {
2419         }
2420 
2421         // 7: append a null string.
2422         try {
2423             mTextView.append(null);
2424             fail("Should throw NullPointerException");
2425         } catch (NullPointerException e) {
2426         }
2427     }
2428 
2429     public void testAccessTransformationMethod() {
2430         // check the password attribute in xml
2431         mTextView = findTextView(R.id.textview_password);
2432         assertNotNull(mTextView);
2433         assertSame(PasswordTransformationMethod.getInstance(),
2434                 mTextView.getTransformationMethod());
2435 
2436         // check the singleLine attribute in xml
2437         mTextView = findTextView(R.id.textview_singleLine);
2438         assertNotNull(mTextView);
2439         assertSame(SingleLineTransformationMethod.getInstance(),
2440                 mTextView.getTransformationMethod());
2441 
2442         final QwertyKeyListener qwertyKeyListener = QwertyKeyListener.getInstance(false,
2443                 Capitalize.NONE);
2444         final TransformationMethod method = PasswordTransformationMethod.getInstance();
2445         // change transformation method by function
2446         mActivity.runOnUiThread(new Runnable() {
2447             public void run() {
2448                 mTextView.setKeyListener(qwertyKeyListener);
2449                 mTextView.setTransformationMethod(method);
2450                 mTransformedText = method.getTransformation(mTextView.getText(), mTextView);
2451 
2452                 mTextView.requestFocus();
2453             }
2454         });
2455         mInstrumentation.waitForIdleSync();
2456         assertSame(PasswordTransformationMethod.getInstance(),
2457                 mTextView.getTransformationMethod());
2458 
2459         sendKeys("H E 2*L O");
2460         mActivity.runOnUiThread(new Runnable() {
2461             public void run() {
2462                 mTextView.append(" ");
2463             }
2464         });
2465         mInstrumentation.waitForIdleSync();
2466 
2467         // it will get transformed after a while
2468         new PollingCheck(TIMEOUT) {
2469             @Override
2470             protected boolean check() {
2471                 // "******"
2472                 return mTransformedText.toString()
2473                         .equals("\u2022\u2022\u2022\u2022\u2022\u2022");
2474             }
2475         }.run();
2476 
2477         // set null
2478         mActivity.runOnUiThread(new Runnable() {
2479             public void run() {
2480                 mTextView.setTransformationMethod(null);
2481             }
2482         });
2483         mInstrumentation.waitForIdleSync();
2484         assertNull(mTextView.getTransformationMethod());
2485     }
2486 
2487     @UiThreadTest
2488     public void testCompound() {
2489         mTextView = new TextView(mActivity);
2490         int padding = 3;
2491         Drawable[] drawables = mTextView.getCompoundDrawables();
2492         assertNull(drawables[0]);
2493         assertNull(drawables[1]);
2494         assertNull(drawables[2]);
2495         assertNull(drawables[3]);
2496 
2497         // test setCompoundDrawablePadding and getCompoundDrawablePadding
2498         mTextView.setCompoundDrawablePadding(padding);
2499         assertEquals(padding, mTextView.getCompoundDrawablePadding());
2500 
2501         // using resid, 0 represents null
2502         mTextView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.start, R.drawable.pass,
2503                 R.drawable.failed, 0);
2504         drawables = mTextView.getCompoundDrawables();
2505 
2506         // drawableLeft
2507         WidgetTestUtils.assertEquals(getBitmap(R.drawable.start),
2508                 ((BitmapDrawable) drawables[0]).getBitmap());
2509         // drawableTop
2510         WidgetTestUtils.assertEquals(getBitmap(R.drawable.pass),
2511                 ((BitmapDrawable) drawables[1]).getBitmap());
2512         // drawableRight
2513         WidgetTestUtils.assertEquals(getBitmap(R.drawable.failed),
2514                 ((BitmapDrawable) drawables[2]).getBitmap());
2515         // drawableBottom
2516         assertNull(drawables[3]);
2517 
2518         Drawable left = getDrawable(R.drawable.blue);
2519         Drawable right = getDrawable(R.drawable.yellow);
2520         Drawable top = getDrawable(R.drawable.red);
2521 
2522         // using drawables directly
2523         mTextView.setCompoundDrawablesWithIntrinsicBounds(left, top, right, null);
2524         drawables = mTextView.getCompoundDrawables();
2525 
2526         // drawableLeft
2527         assertSame(left, drawables[0]);
2528         // drawableTop
2529         assertSame(top, drawables[1]);
2530         // drawableRight
2531         assertSame(right, drawables[2]);
2532         // drawableBottom
2533         assertNull(drawables[3]);
2534 
2535         // check compound padding
2536         assertEquals(mTextView.getPaddingLeft() + padding + left.getIntrinsicWidth(),
2537                 mTextView.getCompoundPaddingLeft());
2538         assertEquals(mTextView.getPaddingTop() + padding + top.getIntrinsicHeight(),
2539                 mTextView.getCompoundPaddingTop());
2540         assertEquals(mTextView.getPaddingRight() + padding + right.getIntrinsicWidth(),
2541                 mTextView.getCompoundPaddingRight());
2542         assertEquals(mTextView.getPaddingBottom(), mTextView.getCompoundPaddingBottom());
2543 
2544         // set bounds to drawables and set them again.
2545         left.setBounds(0, 0, 1, 2);
2546         right.setBounds(0, 0, 3, 4);
2547         top.setBounds(0, 0, 5, 6);
2548         // usinf drawables
2549         mTextView.setCompoundDrawables(left, top, right, null);
2550         drawables = mTextView.getCompoundDrawables();
2551 
2552         // drawableLeft
2553         assertSame(left, drawables[0]);
2554         // drawableTop
2555         assertSame(top, drawables[1]);
2556         // drawableRight
2557         assertSame(right, drawables[2]);
2558         // drawableBottom
2559         assertNull(drawables[3]);
2560 
2561         // check compound padding
2562         assertEquals(mTextView.getPaddingLeft() + padding + left.getBounds().width(),
2563                 mTextView.getCompoundPaddingLeft());
2564         assertEquals(mTextView.getPaddingTop() + padding + top.getBounds().height(),
2565                 mTextView.getCompoundPaddingTop());
2566         assertEquals(mTextView.getPaddingRight() + padding + right.getBounds().width(),
2567                 mTextView.getCompoundPaddingRight());
2568         assertEquals(mTextView.getPaddingBottom(), mTextView.getCompoundPaddingBottom());
2569     }
2570 
2571     public void testSingleLine() {
2572         final TextView textView = new TextView(mActivity);
2573         setSpannableText(textView, "This is a really long sentence"
2574                 + " which can not be placed in one line on the screen.");
2575 
2576         // Narrow layout assures that the text will get wrapped.
2577         FrameLayout innerLayout = new FrameLayout(mActivity);
2578         innerLayout.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
2579         innerLayout.addView(textView);
2580 
2581         final FrameLayout layout = new FrameLayout(mActivity);
2582         layout.addView(innerLayout);
2583 
2584         mActivity.runOnUiThread(new Runnable() {
2585             public void run() {
2586                 mActivity.setContentView(layout);
2587                 textView.setSingleLine(true);
2588             }
2589         });
2590         mInstrumentation.waitForIdleSync();
2591 
2592         assertEquals(SingleLineTransformationMethod.getInstance(),
2593                 textView.getTransformationMethod());
2594 
2595         int singleLineWidth = 0;
2596         int singleLineHeight = 0;
2597 
2598         if (textView.getLayout() != null) {
2599             singleLineWidth = textView.getLayout().getWidth();
2600             singleLineHeight = textView.getLayout().getHeight();
2601         }
2602 
2603         mActivity.runOnUiThread(new Runnable() {
2604             public void run() {
2605                 textView.setSingleLine(false);
2606             }
2607         });
2608         mInstrumentation.waitForIdleSync();
2609         assertEquals(null, textView.getTransformationMethod());
2610 
2611         if (textView.getLayout() != null) {
2612             assertTrue(textView.getLayout().getHeight() > singleLineHeight);
2613             assertTrue(textView.getLayout().getWidth() < singleLineWidth);
2614         }
2615 
2616         // same behaviours as setSingLine(true)
2617         mActivity.runOnUiThread(new Runnable() {
2618             public void run() {
2619                 textView.setSingleLine();
2620             }
2621         });
2622         mInstrumentation.waitForIdleSync();
2623         assertEquals(SingleLineTransformationMethod.getInstance(),
2624                 textView.getTransformationMethod());
2625 
2626         if (textView.getLayout() != null) {
2627             assertEquals(singleLineHeight, textView.getLayout().getHeight());
2628             assertEquals(singleLineWidth, textView.getLayout().getWidth());
2629         }
2630     }
2631 
2632     @UiThreadTest
2633     public void testSetMaxLines() {
2634         mTextView = findTextView(R.id.textview_text);
2635 
2636         float[] widths = new float[LONG_TEXT.length()];
2637         mTextView.getPaint().getTextWidths(LONG_TEXT, widths);
2638         float totalWidth = 0.0f;
2639         for (float f : widths) {
2640             totalWidth += f;
2641         }
2642         final int stringWidth = (int) totalWidth;
2643         mTextView.setWidth(stringWidth >> 2);
2644         mTextView.setText(LONG_TEXT);
2645 
2646         final int maxLines = 2;
2647         assertTrue(mTextView.getLineCount() > maxLines);
2648 
2649         mTextView.setMaxLines(maxLines);
2650         mTextView.requestLayout();
2651 
2652         assertTrue(mTextView.getHeight() <= maxLines * mTextView.getLineHeight());
2653     }
2654 
calculateTextWidth(String text)2655     public int calculateTextWidth(String text) {
2656         mTextView = findTextView(R.id.textview_text);
2657 
2658         // Set the TextView width as the half of the whole text.
2659         float[] widths = new float[text.length()];
2660         mTextView.getPaint().getTextWidths(text, widths);
2661         float textfieldWidth = 0.0f;
2662         for (int i = 0; i < text.length(); ++i) {
2663             textfieldWidth += widths[i];
2664         }
2665         return (int)textfieldWidth;
2666 
2667     }
2668 
2669     @UiThreadTest
testHyphenationNotHappen_frequencyNone()2670     public void testHyphenationNotHappen_frequencyNone() {
2671         final int[] BREAK_STRATEGIES = {
2672             Layout.BREAK_STRATEGY_SIMPLE, Layout.BREAK_STRATEGY_HIGH_QUALITY,
2673             Layout.BREAK_STRATEGY_BALANCED };
2674 
2675         mTextView = findTextView(R.id.textview_text);
2676 
2677         for (int breakStrategy : BREAK_STRATEGIES) {
2678             for (int charWidth = 10; charWidth < 120; charWidth += 5) {
2679                 // Change the text view's width to charWidth width.
2680                 mTextView.setWidth(calculateTextWidth(LONG_TEXT.substring(0, charWidth)));
2681 
2682                 mTextView.setText(LONG_TEXT);
2683                 mTextView.setBreakStrategy(breakStrategy);
2684 
2685                 mTextView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
2686 
2687                 mTextView.requestLayout();
2688                 mTextView.onPreDraw();  // For freezing the layout.
2689                 Layout layout = mTextView.getLayout();
2690 
2691                 final int lineCount = layout.getLineCount();
2692                 for (int line = 0; line < lineCount; ++line) {
2693                     final int lineEnd = layout.getLineEnd(line);
2694                     // In any width, any break strategy, hyphenation should not happen if
2695                     // HYPHENATION_FREQUENCY_NONE is specified.
2696                     assertTrue(lineEnd == LONG_TEXT.length() ||
2697                             Character.isWhitespace(LONG_TEXT.charAt(lineEnd - 1)));
2698                 }
2699             }
2700         }
2701     }
2702 
2703     @UiThreadTest
testHyphenationNotHappen_breakStrategySimple()2704     public void testHyphenationNotHappen_breakStrategySimple() {
2705         final int[] HYPHENATION_FREQUENCIES = {
2706             Layout.HYPHENATION_FREQUENCY_NORMAL, Layout.HYPHENATION_FREQUENCY_FULL,
2707             Layout.HYPHENATION_FREQUENCY_NONE };
2708 
2709         mTextView = findTextView(R.id.textview_text);
2710 
2711         for (int hyphenationFrequency: HYPHENATION_FREQUENCIES) {
2712             for (int charWidth = 10; charWidth < 120; charWidth += 5) {
2713                 // Change the text view's width to charWidth width.
2714                 mTextView.setWidth(calculateTextWidth(LONG_TEXT.substring(0, charWidth)));
2715 
2716                 mTextView.setText(LONG_TEXT);
2717                 mTextView.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
2718 
2719                 mTextView.setHyphenationFrequency(hyphenationFrequency);
2720 
2721                 mTextView.requestLayout();
2722                 mTextView.onPreDraw();  // For freezing the layout.
2723                 Layout layout = mTextView.getLayout();
2724 
2725                 final int lineCount = layout.getLineCount();
2726                 for (int line = 0; line < lineCount; ++line) {
2727                     final int lineEnd = layout.getLineEnd(line);
2728                     // In any width, any hyphenation frequency, hyphenation should not happen if
2729                     // BREAK_STRATEGY_SIMPLE is specified.
2730                     assertTrue(lineEnd == LONG_TEXT.length() ||
2731                             Character.isWhitespace(LONG_TEXT.charAt(lineEnd - 1)));
2732                 }
2733             }
2734         }
2735     }
2736 
2737     @UiThreadTest
testSetMaxLinesException()2738     public void testSetMaxLinesException() {
2739         mTextView = new TextView(mActivity);
2740         mActivity.setContentView(mTextView);
2741         mTextView.setWidth(mTextView.getWidth() >> 3);
2742         mTextView.setMaxLines(-1);
2743     }
2744 
testSetMinLines()2745     public void testSetMinLines() {
2746         mTextView = findTextView(R.id.textview_text);
2747         setWidth(mTextView.getWidth() >> 3);
2748         int originalHeight = mTextView.getHeight();
2749         int originalLines = mTextView.getLineCount();
2750 
2751         setMinLines(originalLines - 1);
2752         assertTrue((originalLines - 1) * mTextView.getLineHeight() <= mTextView.getHeight());
2753 
2754         setMinLines(originalLines + 1);
2755         assertTrue((originalLines + 1) * mTextView.getLineHeight() <= mTextView.getHeight());
2756     }
2757 
testSetLines()2758     public void testSetLines() {
2759         mTextView = findTextView(R.id.textview_text);
2760         // make it multiple lines
2761         setWidth(mTextView.getWidth() >> 3);
2762         int originalLines = mTextView.getLineCount();
2763 
2764         setLines(originalLines - 1);
2765         assertTrue((originalLines - 1) * mTextView.getLineHeight() <= mTextView.getHeight());
2766 
2767         setLines(originalLines + 1);
2768         assertTrue((originalLines + 1) * mTextView.getLineHeight() <= mTextView.getHeight());
2769     }
2770 
2771     @UiThreadTest
testSetLinesException()2772     public void testSetLinesException() {
2773         mTextView = new TextView(mActivity);
2774         mActivity.setContentView(mTextView);
2775         mTextView.setWidth(mTextView.getWidth() >> 3);
2776         mTextView.setLines(-1);
2777     }
2778 
2779     @UiThreadTest
testGetExtendedPaddingTop()2780     public void testGetExtendedPaddingTop() {
2781         mTextView = findTextView(R.id.textview_text);
2782         // Initialized value
2783         assertEquals(0, mTextView.getExtendedPaddingTop());
2784 
2785         // After Set a Drawable
2786         final Drawable top = getDrawable(R.drawable.red);
2787         top.setBounds(0, 0, 100, 10);
2788         mTextView.setCompoundDrawables(null, top, null, null);
2789         assertEquals(mTextView.getCompoundPaddingTop(), mTextView.getExtendedPaddingTop());
2790 
2791         // Change line count
2792         mTextView.setLines(mTextView.getLineCount() - 1);
2793         mTextView.setGravity(Gravity.BOTTOM);
2794 
2795         assertTrue(mTextView.getExtendedPaddingTop() > 0);
2796     }
2797 
2798     @UiThreadTest
testGetExtendedPaddingBottom()2799     public void testGetExtendedPaddingBottom() {
2800         mTextView = findTextView(R.id.textview_text);
2801         // Initialized value
2802         assertEquals(0, mTextView.getExtendedPaddingBottom());
2803 
2804         // After Set a Drawable
2805         final Drawable bottom = getDrawable(R.drawable.red);
2806         bottom.setBounds(0, 0, 100, 10);
2807         mTextView.setCompoundDrawables(null, null, null, bottom);
2808         assertEquals(mTextView.getCompoundPaddingBottom(), mTextView.getExtendedPaddingBottom());
2809 
2810         // Change line count
2811         mTextView.setLines(mTextView.getLineCount() - 1);
2812         mTextView.setGravity(Gravity.CENTER_VERTICAL);
2813 
2814         assertTrue(mTextView.getExtendedPaddingBottom() > 0);
2815     }
2816 
testGetTotalPaddingTop()2817     public void testGetTotalPaddingTop() {
2818         mTextView = findTextView(R.id.textview_text);
2819         // Initialized value
2820         assertEquals(0, mTextView.getTotalPaddingTop());
2821 
2822         // After Set a Drawable
2823         final Drawable top = getDrawable(R.drawable.red);
2824         top.setBounds(0, 0, 100, 10);
2825         mActivity.runOnUiThread(new Runnable() {
2826             public void run() {
2827                 mTextView.setCompoundDrawables(null, top, null, null);
2828                 mTextView.setLines(mTextView.getLineCount() - 1);
2829                 mTextView.setGravity(Gravity.BOTTOM);
2830             }
2831         });
2832         mInstrumentation.waitForIdleSync();
2833         assertEquals(mTextView.getExtendedPaddingTop(), mTextView.getTotalPaddingTop());
2834 
2835         // Change line count
2836         setLines(mTextView.getLineCount() + 1);
2837         int expected = mTextView.getHeight()
2838                 - mTextView.getExtendedPaddingBottom()
2839                 - mTextView.getLayout().getLineTop(mTextView.getLineCount());
2840         assertEquals(expected, mTextView.getTotalPaddingTop());
2841     }
2842 
testGetTotalPaddingBottom()2843     public void testGetTotalPaddingBottom() {
2844         mTextView = findTextView(R.id.textview_text);
2845         // Initialized value
2846         assertEquals(0, mTextView.getTotalPaddingBottom());
2847 
2848         // After Set a Drawable
2849         final Drawable bottom = getDrawable(R.drawable.red);
2850         bottom.setBounds(0, 0, 100, 10);
2851         mActivity.runOnUiThread(new Runnable() {
2852             public void run() {
2853                 mTextView.setCompoundDrawables(null, null, null, bottom);
2854                 mTextView.setLines(mTextView.getLineCount() - 1);
2855                 mTextView.setGravity(Gravity.CENTER_VERTICAL);
2856             }
2857         });
2858         mInstrumentation.waitForIdleSync();
2859         assertEquals(mTextView.getExtendedPaddingBottom(), mTextView.getTotalPaddingBottom());
2860 
2861         // Change line count
2862         setLines(mTextView.getLineCount() + 1);
2863         int expected = ((mTextView.getHeight()
2864                 - mTextView.getExtendedPaddingBottom()
2865                 - mTextView.getExtendedPaddingTop()
2866                 - mTextView.getLayout().getLineBottom(mTextView.getLineCount())) >> 1)
2867                 + mTextView.getExtendedPaddingBottom();
2868         assertEquals(expected, mTextView.getTotalPaddingBottom());
2869     }
2870 
2871     @UiThreadTest
testGetTotalPaddingLeft()2872     public void testGetTotalPaddingLeft() {
2873         mTextView = findTextView(R.id.textview_text);
2874         // Initialized value
2875         assertEquals(0, mTextView.getTotalPaddingLeft());
2876 
2877         // After Set a Drawable
2878         Drawable left = getDrawable(R.drawable.red);
2879         left.setBounds(0, 0, 10, 100);
2880         mTextView.setCompoundDrawables(left, null, null, null);
2881         mTextView.setGravity(Gravity.RIGHT);
2882         assertEquals(mTextView.getCompoundPaddingLeft(), mTextView.getTotalPaddingLeft());
2883 
2884         // Change width
2885         mTextView.setWidth(Integer.MAX_VALUE);
2886         assertEquals(mTextView.getCompoundPaddingLeft(), mTextView.getTotalPaddingLeft());
2887     }
2888 
2889     @UiThreadTest
testGetTotalPaddingRight()2890     public void testGetTotalPaddingRight() {
2891         mTextView = findTextView(R.id.textview_text);
2892         // Initialized value
2893         assertEquals(0, mTextView.getTotalPaddingRight());
2894 
2895         // After Set a Drawable
2896         Drawable right = getDrawable(R.drawable.red);
2897         right.setBounds(0, 0, 10, 100);
2898         mTextView.setCompoundDrawables(null, null, right, null);
2899         mTextView.setGravity(Gravity.CENTER_HORIZONTAL);
2900         assertEquals(mTextView.getCompoundPaddingRight(), mTextView.getTotalPaddingRight());
2901 
2902         // Change width
2903         mTextView.setWidth(Integer.MAX_VALUE);
2904         assertEquals(mTextView.getCompoundPaddingRight(), mTextView.getTotalPaddingRight());
2905     }
2906 
testGetUrls()2907     public void testGetUrls() {
2908         mTextView = new TextView(mActivity);
2909 
2910         URLSpan[] spans = mTextView.getUrls();
2911         assertEquals(0, spans.length);
2912 
2913         String url = "http://www.google.com";
2914         String email = "name@gmail.com";
2915         String string = url + " mailto:" + email;
2916         SpannableString spannable = new SpannableString(string);
2917         spannable.setSpan(new URLSpan(url), 0, url.length(), 0);
2918         mTextView.setText(spannable, BufferType.SPANNABLE);
2919         spans = mTextView.getUrls();
2920         assertEquals(1, spans.length);
2921         assertEquals(url, spans[0].getURL());
2922 
2923         spannable.setSpan(new URLSpan(email), 0, email.length(), 0);
2924         mTextView.setText(spannable, BufferType.SPANNABLE);
2925 
2926         spans = mTextView.getUrls();
2927         assertEquals(2, spans.length);
2928         assertEquals(url, spans[0].getURL());
2929         assertEquals(email, spans[1].getURL());
2930 
2931         // test the situation that param what is not a URLSpan
2932         spannable.setSpan(new Object(), 0, 9, 0);
2933         mTextView.setText(spannable, BufferType.SPANNABLE);
2934         spans = mTextView.getUrls();
2935         assertEquals(2, spans.length);
2936     }
2937 
testSetPadding()2938     public void testSetPadding() {
2939         mTextView = new TextView(mActivity);
2940 
2941         mTextView.setPadding(0, 1, 2, 4);
2942         assertEquals(0, mTextView.getPaddingLeft());
2943         assertEquals(1, mTextView.getPaddingTop());
2944         assertEquals(2, mTextView.getPaddingRight());
2945         assertEquals(4, mTextView.getPaddingBottom());
2946 
2947         mTextView.setPadding(10, 20, 30, 40);
2948         assertEquals(10, mTextView.getPaddingLeft());
2949         assertEquals(20, mTextView.getPaddingTop());
2950         assertEquals(30, mTextView.getPaddingRight());
2951         assertEquals(40, mTextView.getPaddingBottom());
2952     }
2953 
testDeprecatedSetTextAppearance()2954     public void testDeprecatedSetTextAppearance() {
2955         mTextView = new TextView(mActivity);
2956 
2957         mTextView.setTextAppearance(mActivity, R.style.TextAppearance_All);
2958         assertEquals(mActivity.getResources().getColor(R.drawable.black),
2959                 mTextView.getCurrentTextColor());
2960         assertEquals(20f, mTextView.getTextSize(), 0.01f);
2961         assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
2962         assertEquals(mActivity.getResources().getColor(R.drawable.red),
2963                 mTextView.getCurrentHintTextColor());
2964         assertEquals(mActivity.getResources().getColor(R.drawable.blue),
2965                 mTextView.getLinkTextColors().getDefaultColor());
2966 
2967         mTextView.setTextAppearance(mActivity, R.style.TextAppearance_Colors);
2968         assertEquals(mActivity.getResources().getColor(R.drawable.black),
2969                 mTextView.getCurrentTextColor());
2970         assertEquals(mActivity.getResources().getColor(R.drawable.blue),
2971                 mTextView.getCurrentHintTextColor());
2972         assertEquals(mActivity.getResources().getColor(R.drawable.yellow),
2973                 mTextView.getLinkTextColors().getDefaultColor());
2974 
2975         mTextView.setTextAppearance(mActivity, R.style.TextAppearance_NotColors);
2976         assertEquals(17f, mTextView.getTextSize(), 0.01f);
2977         assertEquals(Typeface.NORMAL, mTextView.getTypeface().getStyle());
2978 
2979         mTextView.setTextAppearance(mActivity, R.style.TextAppearance_Style);
2980         assertEquals(null, mTextView.getTypeface());
2981     }
2982 
testSetTextAppearance()2983     public void testSetTextAppearance() {
2984         mTextView = new TextView(mActivity);
2985 
2986         mTextView.setTextAppearance(R.style.TextAppearance_All);
2987         assertEquals(mActivity.getResources().getColor(R.drawable.black),
2988                 mTextView.getCurrentTextColor());
2989         assertEquals(20f, mTextView.getTextSize(), 0.01f);
2990         assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
2991         assertEquals(mActivity.getResources().getColor(R.drawable.red),
2992                 mTextView.getCurrentHintTextColor());
2993         assertEquals(mActivity.getResources().getColor(R.drawable.blue),
2994                 mTextView.getLinkTextColors().getDefaultColor());
2995 
2996         mTextView.setTextAppearance(R.style.TextAppearance_Colors);
2997         assertEquals(mActivity.getResources().getColor(R.drawable.black),
2998                 mTextView.getCurrentTextColor());
2999         assertEquals(mActivity.getResources().getColor(R.drawable.blue),
3000                 mTextView.getCurrentHintTextColor());
3001         assertEquals(mActivity.getResources().getColor(R.drawable.yellow),
3002                 mTextView.getLinkTextColors().getDefaultColor());
3003 
3004         mTextView.setTextAppearance(R.style.TextAppearance_NotColors);
3005         assertEquals(17f, mTextView.getTextSize(), 0.01f);
3006         assertEquals(Typeface.NORMAL, mTextView.getTypeface().getStyle());
3007 
3008         mTextView.setTextAppearance(R.style.TextAppearance_Style);
3009         assertEquals(null, mTextView.getTypeface());
3010     }
3011 
testOnPreDraw()3012     public void testOnPreDraw() {
3013         // Do not test. Implementation details.
3014     }
3015 
testAccessCompoundDrawableTint()3016     public void testAccessCompoundDrawableTint() {
3017         mTextView = new TextView(mActivity);
3018 
3019         ColorStateList colors = ColorStateList.valueOf(Color.RED);
3020         mTextView.setCompoundDrawableTintList(colors);
3021         mTextView.setCompoundDrawableTintMode(PorterDuff.Mode.XOR);
3022         assertSame(colors, mTextView.getCompoundDrawableTintList());
3023         assertEquals(PorterDuff.Mode.XOR, mTextView.getCompoundDrawableTintMode());
3024     }
3025 
testSetHorizontallyScrolling()3026     public void testSetHorizontallyScrolling() {
3027         // make the text view has more than one line
3028         mTextView = findTextView(R.id.textview_text);
3029         setWidth(mTextView.getWidth() >> 1);
3030         assertTrue(mTextView.getLineCount() > 1);
3031 
3032         setHorizontallyScrolling(true);
3033         assertEquals(1, mTextView.getLineCount());
3034 
3035         setHorizontallyScrolling(false);
3036         assertTrue(mTextView.getLineCount() > 1);
3037     }
3038 
testComputeHorizontalScrollRange()3039     public void testComputeHorizontalScrollRange() {
3040         MockTextView textView = new MockTextView(mActivity);
3041         // test when layout is null
3042         assertNull(textView.getLayout());
3043         assertEquals(textView.getWidth(), textView.computeHorizontalScrollRange());
3044 
3045         textView.setFrame(0, 0, 40, 50);
3046         assertEquals(textView.getWidth(), textView.computeHorizontalScrollRange());
3047 
3048         // set the layout
3049         layout(textView);
3050         assertEquals(textView.getLayout().getWidth(), textView.computeHorizontalScrollRange());
3051     }
3052 
testComputeVerticalScrollRange()3053     public void testComputeVerticalScrollRange() {
3054         MockTextView textView = new MockTextView(mActivity);
3055         // test when layout is null
3056         assertNull(textView.getLayout());
3057         assertEquals(0, textView.computeVerticalScrollRange());
3058 
3059         textView.setFrame(0, 0, 40, 50);
3060         assertEquals(textView.getHeight(), textView.computeVerticalScrollRange());
3061 
3062         //set the layout
3063         layout(textView);
3064         assertEquals(textView.getLayout().getHeight(), textView.computeVerticalScrollRange());
3065     }
3066 
testDrawableStateChanged()3067     public void testDrawableStateChanged() {
3068         MockTextView textView = new MockTextView(mActivity);
3069 
3070         textView.reset();
3071         textView.refreshDrawableState();
3072         assertTrue(textView.hasCalledDrawableStateChanged());
3073     }
3074 
testGetDefaultEditable()3075     public void testGetDefaultEditable() {
3076         MockTextView textView = new MockTextView(mActivity);
3077 
3078         //the TextView#getDefaultEditable() does nothing, and always return false.
3079         assertFalse(textView.getDefaultEditable());
3080     }
3081 
testGetDefaultMovementMethod()3082     public void testGetDefaultMovementMethod() {
3083         MockTextView textView = new MockTextView(mActivity);
3084 
3085         //the TextView#getDefaultMovementMethod() does nothing, and always return null.
3086         assertNull(textView.getDefaultMovementMethod());
3087     }
3088 
testOnCreateContextMenu()3089     public void testOnCreateContextMenu() {
3090         // Do not test. Implementation details.
3091     }
3092 
testOnDetachedFromWindow()3093     public void testOnDetachedFromWindow() {
3094         // Do not test. Implementation details.
3095     }
3096 
testOnDraw()3097     public void testOnDraw() {
3098         // Do not test. Implementation details.
3099     }
3100 
testOnFocusChanged()3101     public void testOnFocusChanged() {
3102         // Do not test. Implementation details.
3103     }
3104 
testOnMeasure()3105     public void testOnMeasure() {
3106         // Do not test. Implementation details.
3107     }
3108 
testOnTextChanged()3109     public void testOnTextChanged() {
3110         // Do not test. Implementation details.
3111     }
3112 
testSetFrame()3113     public void testSetFrame() {
3114         MockTextView textView = new MockTextView(mActivity);
3115 
3116         //Assign a new size to this view
3117         assertTrue(textView.setFrame(0, 0, 320, 480));
3118         assertEquals(0, textView.getFrameLeft());
3119         assertEquals(0, textView.getFrameTop());
3120         assertEquals(320, textView.getFrameRight());
3121         assertEquals(480, textView.getFrameBottom());
3122 
3123         //Assign a same size to this view
3124         assertFalse(textView.setFrame(0, 0, 320, 480));
3125 
3126         //negative input
3127         assertTrue(textView.setFrame(-1, -1, -1, -1));
3128         assertEquals(-1, textView.getFrameLeft());
3129         assertEquals(-1, textView.getFrameTop());
3130         assertEquals(-1, textView.getFrameRight());
3131         assertEquals(-1, textView.getFrameBottom());
3132     }
3133 
testGetFadingEdgeStrength()3134     public void testGetFadingEdgeStrength() {
3135         final MockTextView textViewLeft = (MockTextView) mActivity.findViewById(
3136                 R.id.mock_textview_left);
3137         mActivity.runOnUiThread(new Runnable() {
3138             public void run() {
3139                 textViewLeft.setEllipsize(null);
3140             }
3141         });
3142         mInstrumentation.waitForIdleSync();
3143 
3144         // fading is shown on right side if the text aligns left
3145         assertEquals(0.0f, textViewLeft.getLeftFadingEdgeStrength(), 0.01f);
3146         assertEquals(1.0f, textViewLeft.getRightFadingEdgeStrength(), 0.01f);
3147 
3148         final MockTextView textViewRight = (MockTextView) mActivity.findViewById(
3149                 R.id.mock_textview_right);
3150         mActivity.runOnUiThread(new Runnable() {
3151             public void run() {
3152                 textViewRight.setEllipsize(null);
3153             }
3154         });
3155         mInstrumentation.waitForIdleSync();
3156         // fading is shown on left side if the text aligns right
3157         assertEquals(1.0f, textViewRight.getLeftFadingEdgeStrength(), 0.01f);
3158         assertEquals(0.0f, textViewRight.getRightFadingEdgeStrength(), 0.01f);
3159 
3160         final MockTextView textViewCenter = (MockTextView) mActivity.findViewById(
3161                 R.id.mock_textview_center);
3162         mActivity.runOnUiThread(new Runnable() {
3163             public void run() {
3164                 textViewCenter.setEllipsize(null);
3165             }
3166         });
3167         mInstrumentation.waitForIdleSync();
3168         // fading is shown on both sides if the text aligns center
3169         assertEquals(1.0f, textViewCenter.getLeftFadingEdgeStrength(), 0.01f);
3170         assertEquals(1.0f, textViewCenter.getRightFadingEdgeStrength(), 0.01f);
3171     }
3172 
3173 
testMarquee()3174     public void testMarquee() {
3175         final MockTextView textView = new MockTextView(mActivity);
3176         textView.setText(LONG_TEXT);
3177         textView.setSingleLine();
3178         textView.setEllipsize(TruncateAt.MARQUEE);
3179         textView.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
3180 
3181         final FrameLayout layout = new FrameLayout(mActivity);
3182         layout.addView(textView);
3183 
3184         // make the fading to be shown
3185         textView.setHorizontalFadingEdgeEnabled(true);
3186 
3187         mActivity.runOnUiThread(new Runnable() {
3188             public void run() {
3189                 mActivity.setContentView(layout);
3190             }
3191         });
3192         mInstrumentation.waitForIdleSync();
3193 
3194         TestSelectedRunnable runnable = new TestSelectedRunnable(textView) {
3195             public void run() {
3196                 textView.setMarqueeRepeatLimit(-1);
3197                 // force the marquee to start
3198                 saveIsSelected1();
3199                 textView.setSelected(true);
3200                 saveIsSelected2();
3201             }
3202         };
3203         mActivity.runOnUiThread(runnable);
3204 
3205         // wait for the marquee to run
3206         // fading is shown on both sides if the marquee runs for a while
3207         new PollingCheck(TIMEOUT) {
3208             @Override
3209             protected boolean check() {
3210                 return textView.getLeftFadingEdgeStrength() > 0.0f
3211                         && textView.getRightFadingEdgeStrength() > 0.0f;
3212             }
3213         }.run();
3214 
3215         final float leftFadingEdgeStrength = textView.getLeftFadingEdgeStrength();
3216         final float rightFadingEdgeStrength = textView.getRightFadingEdgeStrength();
3217 
3218         // wait for the marquee to continue
3219         // the left fading becomes thicker while the right fading becomes thiner
3220         // as the text moves towards left
3221         new PollingCheck(TIMEOUT) {
3222             @Override
3223             protected boolean check() {
3224                 return leftFadingEdgeStrength < textView.getLeftFadingEdgeStrength()
3225                         && rightFadingEdgeStrength > textView.getRightFadingEdgeStrength();
3226             }
3227         }.run();
3228         assertFalse(runnable.getIsSelected1());
3229         assertTrue(runnable.getIsSelected2());
3230 
3231         runnable = new TestSelectedRunnable(textView) {
3232             public void run() {
3233                 textView.setMarqueeRepeatLimit(0);
3234                 // force the marquee to stop
3235                 saveIsSelected1();
3236                 textView.setSelected(false);
3237                 saveIsSelected2();
3238                 textView.setGravity(Gravity.LEFT);
3239             }
3240         };
3241         // force the marquee to stop
3242         mActivity.runOnUiThread(runnable);
3243         mInstrumentation.waitForIdleSync();
3244         assertTrue(runnable.getIsSelected1());
3245         assertFalse(runnable.getIsSelected2());
3246         assertEquals(0.0f, textView.getLeftFadingEdgeStrength(), 0.01f);
3247         assertTrue(textView.getRightFadingEdgeStrength() > 0.0f);
3248 
3249         mActivity.runOnUiThread(new Runnable() {
3250             public void run() {
3251                 textView.setGravity(Gravity.RIGHT);
3252             }
3253         });
3254         mInstrumentation.waitForIdleSync();
3255         assertTrue(textView.getLeftFadingEdgeStrength() > 0.0f);
3256         assertEquals(0.0f, textView.getRightFadingEdgeStrength(), 0.01f);
3257 
3258         mActivity.runOnUiThread(new Runnable() {
3259             public void run() {
3260                 textView.setGravity(Gravity.CENTER_HORIZONTAL);
3261             }
3262         });
3263         mInstrumentation.waitForIdleSync();
3264         // there is no left fading (Is it correct?)
3265         assertEquals(0.0f, textView.getLeftFadingEdgeStrength(), 0.01f);
3266         assertTrue(textView.getRightFadingEdgeStrength() > 0.0f);
3267     }
3268 
testOnKeyMultiple()3269     public void testOnKeyMultiple() {
3270         // Do not test. Implementation details.
3271     }
3272 
testAccessInputExtras()3273     public void testAccessInputExtras() throws XmlPullParserException, IOException {
3274         TextView textView = new TextView(mActivity);
3275         textView.setText(null, BufferType.EDITABLE);
3276         textView.setInputType(InputType.TYPE_CLASS_TEXT);
3277 
3278         // do not create the extras
3279         assertNull(textView.getInputExtras(false));
3280 
3281         // create if it does not exist
3282         Bundle inputExtras = textView.getInputExtras(true);
3283         assertNotNull(inputExtras);
3284         assertTrue(inputExtras.isEmpty());
3285 
3286         // it is created already
3287         assertNotNull(textView.getInputExtras(false));
3288 
3289         try {
3290             textView.setInputExtras(R.xml.input_extras);
3291             fail("Should throw NullPointerException!");
3292         } catch (NullPointerException e) {
3293         }
3294     }
3295 
testAccessContentType()3296     public void testAccessContentType() {
3297         TextView textView = new TextView(mActivity);
3298         textView.setText(null, BufferType.EDITABLE);
3299         textView.setKeyListener(null);
3300         textView.setTransformationMethod(null);
3301 
3302         textView.setInputType(InputType.TYPE_CLASS_DATETIME
3303                 | InputType.TYPE_DATETIME_VARIATION_NORMAL);
3304         assertEquals(InputType.TYPE_CLASS_DATETIME
3305                 | InputType.TYPE_DATETIME_VARIATION_NORMAL, textView.getInputType());
3306         assertTrue(textView.getKeyListener() instanceof DateTimeKeyListener);
3307 
3308         textView.setInputType(InputType.TYPE_CLASS_DATETIME
3309                 | InputType.TYPE_DATETIME_VARIATION_DATE);
3310         assertEquals(InputType.TYPE_CLASS_DATETIME
3311                 | InputType.TYPE_DATETIME_VARIATION_DATE, textView.getInputType());
3312         assertTrue(textView.getKeyListener() instanceof DateKeyListener);
3313 
3314         textView.setInputType(InputType.TYPE_CLASS_DATETIME
3315                 | InputType.TYPE_DATETIME_VARIATION_TIME);
3316         assertEquals(InputType.TYPE_CLASS_DATETIME
3317                 | InputType.TYPE_DATETIME_VARIATION_TIME, textView.getInputType());
3318         assertTrue(textView.getKeyListener() instanceof TimeKeyListener);
3319 
3320         textView.setInputType(InputType.TYPE_CLASS_NUMBER
3321                 | InputType.TYPE_NUMBER_FLAG_DECIMAL
3322                 | InputType.TYPE_NUMBER_FLAG_SIGNED);
3323         assertEquals(InputType.TYPE_CLASS_NUMBER
3324                 | InputType.TYPE_NUMBER_FLAG_DECIMAL
3325                 | InputType.TYPE_NUMBER_FLAG_SIGNED, textView.getInputType());
3326         assertSame(textView.getKeyListener(), DigitsKeyListener.getInstance(true, true));
3327 
3328         textView.setInputType(InputType.TYPE_CLASS_PHONE);
3329         assertEquals(InputType.TYPE_CLASS_PHONE, textView.getInputType());
3330         assertTrue(textView.getKeyListener() instanceof DialerKeyListener);
3331 
3332         textView.setInputType(InputType.TYPE_CLASS_TEXT
3333                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
3334         assertEquals(InputType.TYPE_CLASS_TEXT
3335                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT, textView.getInputType());
3336         assertSame(textView.getKeyListener(), TextKeyListener.getInstance(true, Capitalize.NONE));
3337 
3338         textView.setSingleLine();
3339         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3340         textView.setInputType(InputType.TYPE_CLASS_TEXT
3341                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
3342                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
3343         assertEquals(InputType.TYPE_CLASS_TEXT
3344                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
3345                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS, textView.getInputType());
3346         assertSame(textView.getKeyListener(),
3347                 TextKeyListener.getInstance(false, Capitalize.CHARACTERS));
3348         assertNull(textView.getTransformationMethod());
3349 
3350         textView.setInputType(InputType.TYPE_CLASS_TEXT
3351                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
3352         assertEquals(InputType.TYPE_CLASS_TEXT
3353                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS, textView.getInputType());
3354         assertSame(textView.getKeyListener(),
3355                 TextKeyListener.getInstance(false, Capitalize.WORDS));
3356         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3357 
3358         textView.setInputType(InputType.TYPE_CLASS_TEXT
3359                 | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
3360         assertEquals(InputType.TYPE_CLASS_TEXT
3361                 | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, textView.getInputType());
3362         assertSame(textView.getKeyListener(),
3363                 TextKeyListener.getInstance(false, Capitalize.SENTENCES));
3364 
3365         textView.setInputType(InputType.TYPE_NULL);
3366         assertEquals(InputType.TYPE_NULL, textView.getInputType());
3367         assertTrue(textView.getKeyListener() instanceof TextKeyListener);
3368     }
3369 
testAccessRawContentType()3370     public void testAccessRawContentType() {
3371         TextView textView = new TextView(mActivity);
3372         textView.setText(null, BufferType.EDITABLE);
3373         textView.setKeyListener(null);
3374         textView.setTransformationMethod(null);
3375 
3376         textView.setRawInputType(InputType.TYPE_CLASS_DATETIME
3377                 | InputType.TYPE_DATETIME_VARIATION_NORMAL);
3378         assertEquals(InputType.TYPE_CLASS_DATETIME
3379                 | InputType.TYPE_DATETIME_VARIATION_NORMAL, textView.getInputType());
3380         assertNull(textView.getTransformationMethod());
3381         assertNull(textView.getKeyListener());
3382 
3383         textView.setRawInputType(InputType.TYPE_CLASS_DATETIME
3384                 | InputType.TYPE_DATETIME_VARIATION_DATE);
3385         assertEquals(InputType.TYPE_CLASS_DATETIME
3386                 | InputType.TYPE_DATETIME_VARIATION_DATE, textView.getInputType());
3387         assertNull(textView.getTransformationMethod());
3388         assertNull(textView.getKeyListener());
3389 
3390         textView.setRawInputType(InputType.TYPE_CLASS_DATETIME
3391                 | InputType.TYPE_DATETIME_VARIATION_TIME);
3392         assertEquals(InputType.TYPE_CLASS_DATETIME
3393                 | InputType.TYPE_DATETIME_VARIATION_TIME, textView.getInputType());
3394         assertNull(textView.getTransformationMethod());
3395         assertNull(textView.getKeyListener());
3396 
3397         textView.setRawInputType(InputType.TYPE_CLASS_NUMBER
3398                 | InputType.TYPE_NUMBER_FLAG_DECIMAL
3399                 | InputType.TYPE_NUMBER_FLAG_SIGNED);
3400         assertEquals(InputType.TYPE_CLASS_NUMBER
3401                 | InputType.TYPE_NUMBER_FLAG_DECIMAL
3402                 | InputType.TYPE_NUMBER_FLAG_SIGNED, textView.getInputType());
3403         assertNull(textView.getTransformationMethod());
3404         assertNull(textView.getKeyListener());
3405 
3406         textView.setRawInputType(InputType.TYPE_CLASS_PHONE);
3407         assertEquals(InputType.TYPE_CLASS_PHONE, textView.getInputType());
3408         assertNull(textView.getTransformationMethod());
3409         assertNull(textView.getKeyListener());
3410 
3411         textView.setRawInputType(InputType.TYPE_CLASS_TEXT
3412                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT);
3413         assertEquals(InputType.TYPE_CLASS_TEXT
3414                 | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT, textView.getInputType());
3415         assertNull(textView.getTransformationMethod());
3416         assertNull(textView.getKeyListener());
3417 
3418         textView.setSingleLine();
3419         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3420         textView.setRawInputType(InputType.TYPE_CLASS_TEXT
3421                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
3422                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);
3423         assertEquals(InputType.TYPE_CLASS_TEXT
3424                 | InputType.TYPE_TEXT_FLAG_MULTI_LINE
3425                 | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS, textView.getInputType());
3426         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3427         assertNull(textView.getKeyListener());
3428 
3429         textView.setRawInputType(InputType.TYPE_CLASS_TEXT
3430                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS);
3431         assertEquals(InputType.TYPE_CLASS_TEXT
3432                 | InputType.TYPE_TEXT_FLAG_CAP_WORDS, textView.getInputType());
3433         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3434         assertNull(textView.getKeyListener());
3435 
3436         textView.setRawInputType(InputType.TYPE_CLASS_TEXT
3437                 | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
3438         assertEquals(InputType.TYPE_CLASS_TEXT
3439                 | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES, textView.getInputType());
3440         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3441         assertNull(textView.getKeyListener());
3442 
3443         textView.setRawInputType(InputType.TYPE_NULL);
3444         assertTrue(textView.getTransformationMethod() instanceof SingleLineTransformationMethod);
3445         assertNull(textView.getKeyListener());
3446     }
3447 
testOnPrivateIMECommand()3448     public void testOnPrivateIMECommand() {
3449         // Do not test. Implementation details.
3450     }
3451 
testFoo()3452     public void testFoo() {
3453         // Do not test. Implementation details.
3454     }
3455 
testVerifyDrawable()3456     public void testVerifyDrawable() {
3457         MockTextView textView = new MockTextView(mActivity);
3458 
3459         Drawable d = getDrawable(R.drawable.pass);
3460         assertFalse(textView.verifyDrawable(d));
3461 
3462         textView.setCompoundDrawables(null, d, null, null);
3463         assertTrue(textView.verifyDrawable(d));
3464     }
3465 
testAccessPrivateImeOptions()3466     public void testAccessPrivateImeOptions() {
3467         mTextView = findTextView(R.id.textview_text);
3468         assertNull(mTextView.getPrivateImeOptions());
3469 
3470         mTextView.setPrivateImeOptions("com.example.myapp.SpecialMode=3");
3471         assertEquals("com.example.myapp.SpecialMode=3", mTextView.getPrivateImeOptions());
3472 
3473         mTextView.setPrivateImeOptions(null);
3474         assertNull(mTextView.getPrivateImeOptions());
3475     }
3476 
testSetOnEditorActionListener()3477     public void testSetOnEditorActionListener() {
3478         mTextView = findTextView(R.id.textview_text);
3479 
3480         MockOnEditorActionListener listener = new MockOnEditorActionListener();
3481         assertFalse(listener.isOnEditorActionCalled());
3482 
3483         mTextView.setOnEditorActionListener(listener);
3484         assertFalse(listener.isOnEditorActionCalled());
3485 
3486         mTextView.onEditorAction(EditorInfo.IME_ACTION_DONE);
3487         assertTrue(listener.isOnEditorActionCalled());
3488     }
3489 
testAccessImeOptions()3490     public void testAccessImeOptions() {
3491         mTextView = findTextView(R.id.textview_text);
3492         assertEquals(EditorInfo.IME_NULL, mTextView.getImeOptions());
3493 
3494         mTextView.setImeOptions(EditorInfo.IME_ACTION_GO);
3495         assertEquals(EditorInfo.IME_ACTION_GO, mTextView.getImeOptions());
3496 
3497         mTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
3498         assertEquals(EditorInfo.IME_ACTION_DONE, mTextView.getImeOptions());
3499 
3500         mTextView.setImeOptions(EditorInfo.IME_NULL);
3501         assertEquals(EditorInfo.IME_NULL, mTextView.getImeOptions());
3502     }
3503 
testAccessImeActionLabel()3504     public void testAccessImeActionLabel() {
3505         mTextView = findTextView(R.id.textview_text);
3506         assertNull(mTextView.getImeActionLabel());
3507         assertEquals(0, mTextView.getImeActionId());
3508 
3509         mTextView.setImeActionLabel("pinyin", 1);
3510         assertEquals("pinyin", mTextView.getImeActionLabel().toString());
3511         assertEquals(1, mTextView.getImeActionId());
3512     }
3513 
testSetTextLong()3514     public void testSetTextLong() {
3515         mActivity.runOnUiThread(new Runnable() {
3516             public void run() {
3517                 final int MAX_COUNT = 1 << 21;
3518                 char[] longText = new char[MAX_COUNT];
3519                 for (int n = 0; n < MAX_COUNT; n++) {
3520                     longText[n] = 'm';
3521                 }
3522                 mTextView = findTextView(R.id.textview_text);
3523                 mTextView.setText(new String(longText));
3524             }
3525         });
3526         mInstrumentation.waitForIdleSync();
3527     }
3528 
3529     @UiThreadTest
testSetExtractedText()3530     public void testSetExtractedText() {
3531         mTextView = findTextView(R.id.textview_text);
3532         assertEquals(mActivity.getResources().getString(R.string.text_view_hello),
3533                 mTextView.getText().toString());
3534 
3535         ExtractedText et = new ExtractedText();
3536         et.text = "test";
3537 
3538         mTextView.setExtractedText(et);
3539         assertEquals("test", mTextView.getText().toString());
3540     }
3541 
testMoveCursorToVisibleOffset()3542     public void testMoveCursorToVisibleOffset() throws Throwable {
3543         mTextView = findTextView(R.id.textview_text);
3544 
3545         // not a spannable text
3546         runTestOnUiThread(new Runnable() {
3547             public void run() {
3548                 assertFalse(mTextView.moveCursorToVisibleOffset());
3549             }
3550         });
3551         mInstrumentation.waitForIdleSync();
3552 
3553         // a selection range
3554         final String spannableText = "text";
3555         mTextView = new TextView(mActivity);
3556 
3557         runTestOnUiThread(new Runnable() {
3558             public void run() {
3559                 mTextView.setText(spannableText, BufferType.SPANNABLE);
3560             }
3561         });
3562         mInstrumentation.waitForIdleSync();
3563         Selection.setSelection((Spannable) mTextView.getText(), 0, spannableText.length());
3564 
3565         assertEquals(0, mTextView.getSelectionStart());
3566         assertEquals(spannableText.length(), mTextView.getSelectionEnd());
3567         runTestOnUiThread(new Runnable() {
3568             public void run() {
3569                 assertFalse(mTextView.moveCursorToVisibleOffset());
3570             }
3571         });
3572         mInstrumentation.waitForIdleSync();
3573 
3574         // a spannable without range
3575         runTestOnUiThread(new Runnable() {
3576             public void run() {
3577                 mTextView = findTextView(R.id.textview_text);
3578                 mTextView.setText(spannableText, BufferType.SPANNABLE);
3579             }
3580         });
3581         mInstrumentation.waitForIdleSync();
3582 
3583         runTestOnUiThread(new Runnable() {
3584             public void run() {
3585                 assertTrue(mTextView.moveCursorToVisibleOffset());
3586             }
3587         });
3588         mInstrumentation.waitForIdleSync();
3589     }
3590 
testIsInputMethodTarget()3591     public void testIsInputMethodTarget() throws Throwable {
3592         mTextView = findTextView(R.id.textview_text);
3593         assertFalse(mTextView.isInputMethodTarget());
3594 
3595         assertFalse(mTextView.isFocused());
3596         runTestOnUiThread(new Runnable() {
3597            @Override
3598             public void run() {
3599                mTextView.setFocusable(true);
3600                mTextView.requestFocus();
3601             }
3602         });
3603         mInstrumentation.waitForIdleSync();
3604         assertTrue(mTextView.isFocused());
3605 
3606         new PollingCheck() {
3607             @Override
3608             protected boolean check() {
3609                 return mTextView.isInputMethodTarget();
3610             }
3611         }.run();
3612     }
3613 
testBeginEndBatchEdit()3614     public void testBeginEndBatchEdit() {
3615         mTextView = findTextView(R.id.textview_text);
3616 
3617         mTextView.beginBatchEdit();
3618         mTextView.endBatchEdit();
3619     }
3620 
3621     @UiThreadTest
testBringPointIntoView()3622     public void testBringPointIntoView() throws Throwable {
3623         mTextView = findTextView(R.id.textview_text);
3624         assertFalse(mTextView.bringPointIntoView(1));
3625 
3626         mTextView.layout(0, 0, 100, 100);
3627         assertFalse(mTextView.bringPointIntoView(2));
3628     }
3629 
testCancelLongPress()3630     public void testCancelLongPress() {
3631         mTextView = findTextView(R.id.textview_text);
3632         TouchUtils.longClickView(this, mTextView);
3633         mTextView.cancelLongPress();
3634     }
3635 
3636     @UiThreadTest
testClearComposingText()3637     public void testClearComposingText() {
3638         mTextView = findTextView(R.id.textview_text);
3639         mTextView.setText("Hello world!", BufferType.SPANNABLE);
3640         Spannable text = (Spannable) mTextView.getText();
3641 
3642         assertEquals(-1, BaseInputConnection.getComposingSpanStart(text));
3643         assertEquals(-1, BaseInputConnection.getComposingSpanStart(text));
3644 
3645         BaseInputConnection.setComposingSpans((Spannable) mTextView.getText());
3646         assertEquals(0, BaseInputConnection.getComposingSpanStart(text));
3647         assertEquals(0, BaseInputConnection.getComposingSpanStart(text));
3648 
3649         mTextView.clearComposingText();
3650         assertEquals(-1, BaseInputConnection.getComposingSpanStart(text));
3651         assertEquals(-1, BaseInputConnection.getComposingSpanStart(text));
3652     }
3653 
testComputeVerticalScrollExtent()3654     public void testComputeVerticalScrollExtent() {
3655         MockTextView textView = new MockTextView(mActivity);
3656         assertEquals(0, textView.computeVerticalScrollExtent());
3657 
3658         Drawable d = getDrawable(R.drawable.pass);
3659         textView.setCompoundDrawables(null, d, null, d);
3660 
3661         assertEquals(0, textView.computeVerticalScrollExtent());
3662     }
3663 
3664     @UiThreadTest
testDidTouchFocusSelect()3665     public void testDidTouchFocusSelect() {
3666         mTextView = new EditText(mActivity);
3667         assertFalse(mTextView.didTouchFocusSelect());
3668 
3669         mTextView.setFocusable(true);
3670         mTextView.requestFocus();
3671         assertTrue(mTextView.didTouchFocusSelect());
3672     }
3673 
testSelectAllJustAfterTap()3674     public void testSelectAllJustAfterTap() {
3675         // Prepare an EditText with focus.
3676         mActivity.runOnUiThread(new Runnable() {
3677             public void run() {
3678                 mTextView = new EditText(mActivity);
3679                 mActivity.setContentView(mTextView);
3680 
3681                 assertFalse(mTextView.didTouchFocusSelect());
3682                 mTextView.setFocusable(true);
3683                 mTextView.requestFocus();
3684                 assertTrue(mTextView.didTouchFocusSelect());
3685 
3686                 mTextView.setText("Hello, World.", BufferType.SPANNABLE);
3687             }
3688         });
3689         mInstrumentation.waitForIdleSync();
3690 
3691         // Tap the view to show InsertPointController.
3692         TouchUtils.tapView(this, mTextView);
3693 
3694         // Execute SelectAll context menu.
3695         mActivity.runOnUiThread(new Runnable() {
3696             public void run() {
3697                 mTextView.onTextContextMenuItem(android.R.id.selectAll);
3698             }
3699         });
3700         mInstrumentation.waitForIdleSync();
3701 
3702         // The selection must be whole of the text contents.
3703         assertEquals(0, mTextView.getSelectionStart());
3704         assertEquals(mTextView.length(), mTextView.getSelectionEnd());
3705     }
3706 
testExtractText()3707     public void testExtractText() {
3708         mTextView = new TextView(mActivity);
3709 
3710         ExtractedTextRequest request = new ExtractedTextRequest();
3711         ExtractedText outText = new ExtractedText();
3712 
3713         request.token = 0;
3714         request.flags = 10;
3715         request.hintMaxLines = 2;
3716         request.hintMaxChars = 20;
3717         assertTrue(mTextView.extractText(request, outText));
3718 
3719         mTextView = findTextView(R.id.textview_text);
3720         assertTrue(mTextView.extractText(request, outText));
3721 
3722         assertEquals(mActivity.getResources().getString(R.string.text_view_hello),
3723                 outText.text.toString());
3724 
3725         // Tests for invalid arguments.
3726         assertFalse(mTextView.extractText(request, null));
3727         assertFalse(mTextView.extractText(null, outText));
3728         assertFalse(mTextView.extractText(null, null));
3729     }
3730 
3731     @UiThreadTest
testTextDirectionDefault()3732     public void testTextDirectionDefault() {
3733         TextView tv = new TextView(mActivity);
3734         assertEquals(View.TEXT_DIRECTION_INHERIT, tv.getRawTextDirection());
3735     }
3736 
3737     @UiThreadTest
testSetGetTextDirection()3738     public void testSetGetTextDirection() {
3739         TextView tv = new TextView(mActivity);
3740 
3741         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3742         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getRawTextDirection());
3743 
3744         tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3745         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getRawTextDirection());
3746 
3747         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3748         assertEquals(View.TEXT_DIRECTION_INHERIT, tv.getRawTextDirection());
3749 
3750         tv.setTextDirection(View.TEXT_DIRECTION_LTR);
3751         assertEquals(View.TEXT_DIRECTION_LTR, tv.getRawTextDirection());
3752 
3753         tv.setTextDirection(View.TEXT_DIRECTION_RTL);
3754         assertEquals(View.TEXT_DIRECTION_RTL, tv.getRawTextDirection());
3755 
3756         tv.setTextDirection(View.TEXT_DIRECTION_LOCALE);
3757         assertEquals(View.TEXT_DIRECTION_LOCALE, tv.getRawTextDirection());
3758 
3759         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3760         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getRawTextDirection());
3761 
3762         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
3763         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getRawTextDirection());
3764     }
3765 
3766     @UiThreadTest
testGetResolvedTextDirectionLtr()3767     public void testGetResolvedTextDirectionLtr() {
3768         TextView tv = new TextView(mActivity);
3769         tv.setText("this is a test");
3770 
3771         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3772 
3773         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3774         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3775 
3776         tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3777         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
3778 
3779         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3780         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3781 
3782         tv.setTextDirection(View.TEXT_DIRECTION_LTR);
3783         assertEquals(View.TEXT_DIRECTION_LTR, tv.getTextDirection());
3784 
3785         tv.setTextDirection(View.TEXT_DIRECTION_RTL);
3786         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3787 
3788         tv.setTextDirection(View.TEXT_DIRECTION_LOCALE);
3789         assertEquals(View.TEXT_DIRECTION_LOCALE, tv.getTextDirection());
3790 
3791         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3792         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3793 
3794         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
3795         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
3796     }
3797 
3798     @UiThreadTest
testGetResolvedTextDirectionLtrWithInheritance()3799     public void testGetResolvedTextDirectionLtrWithInheritance() {
3800         LinearLayout ll = new LinearLayout(mActivity);
3801         ll.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3802 
3803         TextView tv = new TextView(mActivity);
3804         tv.setText("this is a test");
3805         ll.addView(tv);
3806 
3807         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3808         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3809 
3810         tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3811         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
3812 
3813         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3814         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
3815 
3816         tv.setTextDirection(View.TEXT_DIRECTION_LTR);
3817         assertEquals(View.TEXT_DIRECTION_LTR, tv.getTextDirection());
3818 
3819         tv.setTextDirection(View.TEXT_DIRECTION_RTL);
3820         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3821 
3822         tv.setTextDirection(View.TEXT_DIRECTION_LOCALE);
3823         assertEquals(View.TEXT_DIRECTION_LOCALE, tv.getTextDirection());
3824 
3825         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3826         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3827 
3828         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
3829         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
3830     }
3831 
3832     @UiThreadTest
testGetResolvedTextDirectionRtl()3833     public void testGetResolvedTextDirectionRtl() {
3834         TextView tv = new TextView(mActivity);
3835         tv.setText("\u05DD\u05DE"); // hebrew
3836 
3837         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3838 
3839         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3840         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3841 
3842         tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3843         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
3844 
3845         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3846         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3847 
3848         tv.setTextDirection(View.TEXT_DIRECTION_LTR);
3849         assertEquals(View.TEXT_DIRECTION_LTR, tv.getTextDirection());
3850 
3851         tv.setTextDirection(View.TEXT_DIRECTION_RTL);
3852         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3853 
3854         tv.setTextDirection(View.TEXT_DIRECTION_LOCALE);
3855         assertEquals(View.TEXT_DIRECTION_LOCALE, tv.getTextDirection());
3856 
3857         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3858         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3859 
3860         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
3861         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
3862     }
3863 
3864     @UiThreadTest
testGetResolvedTextDirectionRtlWithInheritance()3865     public void testGetResolvedTextDirectionRtlWithInheritance() {
3866         LinearLayout ll = new LinearLayout(mActivity);
3867         ll.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3868 
3869         TextView tv = new TextView(mActivity);
3870         tv.setText("\u05DD\u05DE"); // hebrew
3871         ll.addView(tv);
3872 
3873         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3874         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3875 
3876         tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3877         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
3878 
3879         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3880         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3881 
3882         tv.setTextDirection(View.TEXT_DIRECTION_LTR);
3883         assertEquals(View.TEXT_DIRECTION_LTR, tv.getTextDirection());
3884 
3885         tv.setTextDirection(View.TEXT_DIRECTION_RTL);
3886         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3887 
3888         tv.setTextDirection(View.TEXT_DIRECTION_LOCALE);
3889         assertEquals(View.TEXT_DIRECTION_LOCALE, tv.getTextDirection());
3890 
3891         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3892         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3893 
3894         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
3895         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
3896 
3897         // Force to RTL text direction on the layout
3898         ll.setTextDirection(View.TEXT_DIRECTION_RTL);
3899 
3900         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG);
3901         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3902 
3903         tv.setTextDirection(View.TEXT_DIRECTION_ANY_RTL);
3904         assertEquals(View.TEXT_DIRECTION_ANY_RTL, tv.getTextDirection());
3905 
3906         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3907         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3908 
3909         tv.setTextDirection(View.TEXT_DIRECTION_LTR);
3910         assertEquals(View.TEXT_DIRECTION_LTR, tv.getTextDirection());
3911 
3912         tv.setTextDirection(View.TEXT_DIRECTION_RTL);
3913         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3914 
3915         tv.setTextDirection(View.TEXT_DIRECTION_LOCALE);
3916         assertEquals(View.TEXT_DIRECTION_LOCALE, tv.getTextDirection());
3917 
3918         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3919         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3920 
3921         tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
3922         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
3923     }
3924 
3925     @UiThreadTest
testResetTextDirection()3926     public void testResetTextDirection() {
3927         LinearLayout ll = (LinearLayout) mActivity.findViewById(R.id.layout_textviewtest);
3928         TextView tv = (TextView) mActivity.findViewById(R.id.textview_rtl);
3929 
3930         ll.setTextDirection(View.TEXT_DIRECTION_RTL);
3931         tv.setTextDirection(View.TEXT_DIRECTION_INHERIT);
3932         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3933 
3934         // No reset when we remove the view
3935         ll.removeView(tv);
3936         assertEquals(View.TEXT_DIRECTION_RTL, tv.getTextDirection());
3937 
3938         // Reset is done when we add the view
3939         ll.addView(tv);
3940         assertEquals(View.TEXT_DIRECTION_FIRST_STRONG, tv.getTextDirection());
3941     }
3942 
3943     @UiThreadTest
testTextDirectionFirstStrongLtr()3944     public void testTextDirectionFirstStrongLtr() {
3945         {
3946             // The first directional character is LTR, the paragraph direction is LTR.
3947             LinearLayout ll = new LinearLayout(mActivity);
3948 
3949             TextView tv = new TextView(mActivity);
3950             tv.setText("this is a test");
3951             ll.addView(tv);
3952 
3953             tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3954             assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3955 
3956             tv.onPreDraw();  // For freezing layout.
3957             Layout layout = tv.getLayout();
3958             assertEquals(Layout.DIR_LEFT_TO_RIGHT, layout.getParagraphDirection(0));
3959         }
3960         {
3961             // The first directional character is RTL, the paragraph direction is RTL.
3962             LinearLayout ll = new LinearLayout(mActivity);
3963 
3964             TextView tv = new TextView(mActivity);
3965             tv.setText("\u05DD\u05DE"); // Hebrew
3966             ll.addView(tv);
3967 
3968             tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3969             assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3970 
3971             tv.onPreDraw();  // For freezing layout.
3972             Layout layout = tv.getLayout();
3973             assertEquals(Layout.DIR_RIGHT_TO_LEFT, layout.getParagraphDirection(0));
3974         }
3975         {
3976             // The first directional character is not a strong directional character, the paragraph
3977             // direction is LTR.
3978             LinearLayout ll = new LinearLayout(mActivity);
3979 
3980             TextView tv = new TextView(mActivity);
3981             tv.setText("\uFFFD");  // REPLACEMENT CHARACTER. Neutral direction.
3982             ll.addView(tv);
3983 
3984             tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_LTR);
3985             assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_LTR, tv.getTextDirection());
3986 
3987             tv.onPreDraw();  // For freezing layout.
3988             Layout layout = tv.getLayout();
3989             assertEquals(Layout.DIR_LEFT_TO_RIGHT, layout.getParagraphDirection(0));
3990         }
3991     }
3992 
3993     @UiThreadTest
testTextDirectionFirstStrongRtl()3994     public void testTextDirectionFirstStrongRtl() {
3995         {
3996             // The first directional character is LTR, the paragraph direction is LTR.
3997             LinearLayout ll = new LinearLayout(mActivity);
3998 
3999             TextView tv = new TextView(mActivity);
4000             tv.setText("this is a test");
4001             ll.addView(tv);
4002 
4003             tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
4004             assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
4005 
4006             tv.onPreDraw();  // For freezing layout.
4007             Layout layout = tv.getLayout();
4008             assertEquals(Layout.DIR_LEFT_TO_RIGHT, layout.getParagraphDirection(0));
4009         }
4010         {
4011             // The first directional character is RTL, the paragraph direction is RTL.
4012             LinearLayout ll = new LinearLayout(mActivity);
4013 
4014             TextView tv = new TextView(mActivity);
4015             tv.setText("\u05DD\u05DE"); // Hebrew
4016             ll.addView(tv);
4017 
4018             tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
4019             assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
4020 
4021             tv.onPreDraw();  // For freezing layout.
4022             Layout layout = tv.getLayout();
4023             assertEquals(Layout.DIR_RIGHT_TO_LEFT, layout.getParagraphDirection(0));
4024         }
4025         {
4026             // The first directional character is not a strong directional character, the paragraph
4027             // direction is RTL.
4028             LinearLayout ll = new LinearLayout(mActivity);
4029 
4030             TextView tv = new TextView(mActivity);
4031             tv.setText("\uFFFD");  // REPLACEMENT CHARACTER. Neutral direction.
4032             ll.addView(tv);
4033 
4034             tv.setTextDirection(View.TEXT_DIRECTION_FIRST_STRONG_RTL);
4035             assertEquals(View.TEXT_DIRECTION_FIRST_STRONG_RTL, tv.getTextDirection());
4036 
4037             tv.onPreDraw();  // For freezing layout.
4038             Layout layout = tv.getLayout();
4039             assertEquals(Layout.DIR_RIGHT_TO_LEFT, layout.getParagraphDirection(0));
4040         }
4041     }
4042 
testAllCapsLocalization()4043     public void testAllCapsLocalization() {
4044         String testString = "abcdefghijklmnopqrstuvwxyz";
4045 
4046         // The capitalized characters of "i" on Turkish and Azerbaijani are different from English.
4047         Locale[] testLocales = {
4048             new Locale("az", "AZ"),
4049             new Locale("tr", "TR"),
4050             new Locale("en", "US"),
4051         };
4052 
4053         TextView tv = new TextView(mActivity);
4054         tv.setAllCaps(true);
4055         for (Locale locale: testLocales) {
4056             tv.setTextLocale(locale);
4057             assertEquals("Locale: " + locale.getDisplayName(),
4058                          testString.toUpperCase(locale),
4059                          tv.getTransformationMethod().getTransformation(testString, tv).toString());
4060         }
4061     }
4062 
4063     @UiThreadTest
testTextAlignmentDefault()4064     public void testTextAlignmentDefault() {
4065         TextView tv = new TextView(getActivity());
4066         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
4067         // resolved default text alignment is GRAVITY
4068         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
4069     }
4070 
4071     @UiThreadTest
testSetGetTextAlignment()4072     public void testSetGetTextAlignment() {
4073         TextView tv = new TextView(getActivity());
4074 
4075         tv.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
4076         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
4077 
4078         tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
4079         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getRawTextAlignment());
4080 
4081         tv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
4082         assertEquals(View.TEXT_ALIGNMENT_TEXT_START, tv.getRawTextAlignment());
4083 
4084         tv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
4085         assertEquals(View.TEXT_ALIGNMENT_TEXT_END, tv.getRawTextAlignment());
4086 
4087         tv.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
4088         assertEquals(View.TEXT_ALIGNMENT_VIEW_START, tv.getRawTextAlignment());
4089 
4090         tv.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
4091         assertEquals(View.TEXT_ALIGNMENT_VIEW_END, tv.getRawTextAlignment());
4092     }
4093 
4094     @UiThreadTest
testGetResolvedTextAlignment()4095     public void testGetResolvedTextAlignment() {
4096         TextView tv = new TextView(getActivity());
4097 
4098         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
4099 
4100         // Test center alignment first so that we dont hit the default case
4101         tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
4102         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4103 
4104         // Test the default case too
4105         tv.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
4106         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
4107 
4108         tv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
4109         assertEquals(View.TEXT_ALIGNMENT_TEXT_START, tv.getTextAlignment());
4110 
4111         tv.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
4112         assertEquals(View.TEXT_ALIGNMENT_TEXT_END, tv.getTextAlignment());
4113 
4114         tv.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
4115         assertEquals(View.TEXT_ALIGNMENT_VIEW_START, tv.getTextAlignment());
4116 
4117         tv.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
4118         assertEquals(View.TEXT_ALIGNMENT_VIEW_END, tv.getTextAlignment());
4119     }
4120 
4121     @UiThreadTest
testGetResolvedTextAlignmentWithInheritance()4122     public void testGetResolvedTextAlignmentWithInheritance() {
4123         LinearLayout ll = new LinearLayout(getActivity());
4124         ll.setTextAlignment(View.TEXT_ALIGNMENT_GRAVITY);
4125 
4126         TextView tv = new TextView(getActivity());
4127         ll.addView(tv);
4128 
4129         // check defaults
4130         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
4131         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
4132 
4133         // set inherit and check that child is following parent
4134         tv.setTextAlignment(View.TEXT_ALIGNMENT_INHERIT);
4135         assertEquals(View.TEXT_ALIGNMENT_INHERIT, tv.getRawTextAlignment());
4136 
4137         ll.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
4138         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4139 
4140         ll.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
4141         assertEquals(View.TEXT_ALIGNMENT_TEXT_START, tv.getTextAlignment());
4142 
4143         ll.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
4144         assertEquals(View.TEXT_ALIGNMENT_TEXT_END, tv.getTextAlignment());
4145 
4146         ll.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
4147         assertEquals(View.TEXT_ALIGNMENT_VIEW_START, tv.getTextAlignment());
4148 
4149         ll.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
4150         assertEquals(View.TEXT_ALIGNMENT_VIEW_END, tv.getTextAlignment());
4151 
4152         // now get rid of the inheritance but still change the parent
4153         tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
4154 
4155         ll.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
4156         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4157 
4158         ll.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
4159         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4160 
4161         ll.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_END);
4162         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4163 
4164         ll.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
4165         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4166 
4167         ll.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_END);
4168         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4169     }
4170 
4171     @UiThreadTest
testResetTextAlignment()4172     public void testResetTextAlignment() {
4173         TextViewCtsActivity activity = getActivity();
4174 
4175         LinearLayout ll = (LinearLayout) activity.findViewById(R.id.layout_textviewtest);
4176         TextView tv = (TextView) activity.findViewById(R.id.textview_rtl);
4177 
4178         ll.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
4179         tv.setTextAlignment(View.TEXT_ALIGNMENT_INHERIT);
4180         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4181 
4182         // No reset when we remove the view
4183         ll.removeView(tv);
4184         assertEquals(View.TEXT_ALIGNMENT_CENTER, tv.getTextAlignment());
4185 
4186         // Reset is done when we add the view
4187         // Default text alignment is GRAVITY
4188         ll.addView(tv);
4189         assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getTextAlignment());
4190     }
4191 
4192     @UiThreadTest
testDrawableResolution()4193     public void testDrawableResolution() {
4194         final int LEFT = 0;
4195         final int TOP = 1;
4196         final int RIGHT = 2;
4197         final int BOTTOM = 3;
4198 
4199         TextViewCtsActivity activity = getActivity();
4200 
4201         // Case 1.1: left / right drawable defined in default LTR mode
4202         TextView tv = (TextView) activity.findViewById(R.id.textview_drawable_1_1);
4203         Drawable[] drawables = tv.getCompoundDrawables();
4204 
4205         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4206                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4207         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4208                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4209         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4210                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4211         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4212                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4213 
4214         // Case 1.2: left / right drawable defined in default RTL mode
4215         tv = (TextView) activity.findViewById(R.id.textview_drawable_1_2);
4216         drawables = tv.getCompoundDrawables();
4217 
4218         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4219                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4220         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4221                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4222         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4223                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4224         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4225                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4226 
4227         // Case 2.1: start / end drawable defined in LTR mode
4228         tv = (TextView) activity.findViewById(R.id.textview_drawable_2_1);
4229         drawables = tv.getCompoundDrawables();
4230 
4231         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4232                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4233         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4234                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4235         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4236                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4237         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4238                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4239 
4240         // Case 2.2: start / end drawable defined in RTL mode
4241         tv = (TextView) activity.findViewById(R.id.textview_drawable_2_2);
4242         drawables = tv.getCompoundDrawables();
4243 
4244         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4245                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4246         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4247                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4248         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4249                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4250         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4251                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4252 
4253         // Case 3.1: left / right / start / end drawable defined in LTR mode
4254         tv = (TextView) activity.findViewById(R.id.textview_drawable_3_1);
4255         drawables = tv.getCompoundDrawables();
4256 
4257         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4258                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4259         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4260                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4261         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4262                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4263         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4264                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4265 
4266         // Case 3.2: left / right / start / end drawable defined in RTL mode
4267         tv = (TextView) activity.findViewById(R.id.textview_drawable_3_2);
4268         drawables = tv.getCompoundDrawables();
4269 
4270         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4271                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4272         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4273                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4274         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4275                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4276         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4277                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4278 
4279         // Case 4.1: start / end drawable defined in LTR mode inside a layout
4280         // that defines the layout direction
4281         tv = (TextView) activity.findViewById(R.id.textview_drawable_4_1);
4282         drawables = tv.getCompoundDrawables();
4283 
4284         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4285                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4286         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4287                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4288         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4289                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4290         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4291                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4292 
4293         // Case 4.2: start / end drawable defined in RTL mode inside a layout
4294         // that defines the layout direction
4295         tv = (TextView) activity.findViewById(R.id.textview_drawable_4_2);
4296         drawables = tv.getCompoundDrawables();
4297 
4298         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4299                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4300         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4301                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4302         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4303                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4304         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4305                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4306 
4307         // Case 5.1: left / right / start / end drawable defined in LTR mode inside a layout
4308         // that defines the layout direction
4309         tv = (TextView) activity.findViewById(R.id.textview_drawable_3_1);
4310         drawables = tv.getCompoundDrawables();
4311 
4312         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4313                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4314         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4315                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4316         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4317                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4318         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4319                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4320 
4321         // Case 5.2: left / right / start / end drawable defined in RTL mode inside a layout
4322         // that defines the layout direction
4323         tv = (TextView) activity.findViewById(R.id.textview_drawable_3_2);
4324         drawables = tv.getCompoundDrawables();
4325 
4326         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4327                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4328         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4329                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4330         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4331                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4332         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4333                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4334     }
4335 
4336     @UiThreadTest
testDrawableResolution2()4337     public void testDrawableResolution2() {
4338         final int LEFT = 0;
4339         final int TOP = 1;
4340         final int RIGHT = 2;
4341         final int BOTTOM = 3;
4342 
4343         TextViewCtsActivity activity = getActivity();
4344 
4345         // Case 1.1: left / right drawable defined in default LTR mode
4346         TextView tv = (TextView) activity.findViewById(R.id.textview_drawable_1_1);
4347         Drawable[] drawables = tv.getCompoundDrawables();
4348 
4349         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4350                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4351         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4352                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4353         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4354                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4355         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4356                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4357 
4358         tv.setCompoundDrawables(null, null, getDrawable(R.drawable.icon_yellow), null);
4359         drawables = tv.getCompoundDrawables();
4360 
4361         assertNull(drawables[LEFT]);
4362         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4363                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4364         assertNull(drawables[TOP]);
4365         assertNull(drawables[BOTTOM]);
4366 
4367         tv = (TextView) activity.findViewById(R.id.textview_drawable_1_2);
4368         drawables = tv.getCompoundDrawables();
4369 
4370         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4371                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4372         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4373                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4374         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_green),
4375                 ((BitmapDrawable) drawables[TOP]).getBitmap());
4376         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4377                 ((BitmapDrawable) drawables[BOTTOM]).getBitmap());
4378 
4379         tv.setCompoundDrawables(getDrawable(R.drawable.icon_yellow), null, null, null);
4380         drawables = tv.getCompoundDrawables();
4381 
4382         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4383                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4384         assertNull(drawables[RIGHT]);
4385         assertNull(drawables[TOP]);
4386         assertNull(drawables[BOTTOM]);
4387 
4388         tv = (TextView) activity.findViewById(R.id.textview_ltr);
4389         drawables = tv.getCompoundDrawables();
4390 
4391         assertNull(drawables[LEFT]);
4392         assertNull(drawables[RIGHT]);
4393         assertNull(drawables[TOP]);
4394         assertNull(drawables[BOTTOM]);
4395 
4396         tv.setCompoundDrawables(getDrawable(R.drawable.icon_blue), null, getDrawable(R.drawable.icon_red), null);
4397         drawables = tv.getCompoundDrawables();
4398 
4399         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_blue),
4400                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4401         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_red),
4402                 ((BitmapDrawable) drawables[RIGHT]).getBitmap());
4403         assertNull(drawables[TOP]);
4404         assertNull(drawables[BOTTOM]);
4405 
4406         tv.setCompoundDrawablesRelative(getDrawable(R.drawable.icon_yellow), null, null, null);
4407         drawables = tv.getCompoundDrawables();
4408 
4409         WidgetTestUtils.assertEquals(getBitmap(R.drawable.icon_yellow),
4410                 ((BitmapDrawable) drawables[LEFT]).getBitmap());
4411         assertNull(drawables[RIGHT]);
4412         assertNull(drawables[TOP]);
4413         assertNull(drawables[BOTTOM]);
4414     }
4415 
testSetGetBreakStrategy()4416     public void testSetGetBreakStrategy() {
4417         TextView tv = new TextView(mActivity);
4418 
4419         // The default value is from the theme, here the default is BREAK_STRATEGY_HIGH_QUALITY for
4420         // TextView.
4421         assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
4422 
4423         tv.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
4424         assertEquals(Layout.BREAK_STRATEGY_SIMPLE, tv.getBreakStrategy());
4425 
4426         tv.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY);
4427         assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, tv.getBreakStrategy());
4428 
4429         tv.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
4430         assertEquals(Layout.BREAK_STRATEGY_BALANCED, tv.getBreakStrategy());
4431 
4432         EditText et = new EditText(mActivity);
4433 
4434         // The default value is from the theme, here the default is BREAK_STRATEGY_SIMPLE for
4435         // EditText.
4436         assertEquals(Layout.BREAK_STRATEGY_SIMPLE, et.getBreakStrategy());
4437 
4438         et.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
4439         assertEquals(Layout.BREAK_STRATEGY_SIMPLE, et.getBreakStrategy());
4440 
4441         et.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY);
4442         assertEquals(Layout.BREAK_STRATEGY_HIGH_QUALITY, et.getBreakStrategy());
4443 
4444         et.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
4445         assertEquals(Layout.BREAK_STRATEGY_BALANCED, et.getBreakStrategy());
4446     }
4447 
testSetGetHyphenationFrequency()4448     public void testSetGetHyphenationFrequency() {
4449         TextView tv = new TextView(mActivity);
4450 
4451         assertEquals(Layout.HYPHENATION_FREQUENCY_NORMAL, tv.getHyphenationFrequency());
4452 
4453         tv.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
4454         assertEquals(Layout.HYPHENATION_FREQUENCY_NONE, tv.getHyphenationFrequency());
4455 
4456         tv.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
4457         assertEquals(Layout.HYPHENATION_FREQUENCY_NORMAL, tv.getHyphenationFrequency());
4458 
4459         tv.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
4460         assertEquals(Layout.HYPHENATION_FREQUENCY_FULL, tv.getHyphenationFrequency());
4461     }
4462 
testSetAndGetCustomSelectionActionModeCallback()4463     public void testSetAndGetCustomSelectionActionModeCallback() {
4464         final String text = "abcde";
4465         mActivity.runOnUiThread(new Runnable() {
4466             public void run() {
4467                 mTextView = new EditText(mActivity);
4468                 mActivity.setContentView(mTextView);
4469                 mTextView.setText(text, BufferType.SPANNABLE);
4470                 mTextView.setTextIsSelectable(true);
4471                 mTextView.requestFocus();
4472                 mTextView.setSelected(true);
4473             }
4474         });
4475         mInstrumentation.waitForIdleSync();
4476 
4477         // Check default value.
4478         assertNull(mTextView.getCustomSelectionActionModeCallback());
4479 
4480         MockActionModeCallback callbackBlockActionMode = new MockActionModeCallback(false);
4481         mTextView.setCustomSelectionActionModeCallback(callbackBlockActionMode);
4482         assertEquals(callbackBlockActionMode,
4483                 mTextView.getCustomSelectionActionModeCallback());
4484 
4485         mActivity.runOnUiThread(new Runnable() {
4486             public void run() {
4487                 // Set selection and try to start action mode.
4488                 final Bundle args = new Bundle();
4489                 args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
4490                 args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
4491                 mTextView.performAccessibilityAction(
4492                         AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
4493             }
4494         });
4495         mInstrumentation.waitForIdleSync();
4496 
4497         assertEquals(1, callbackBlockActionMode.getCreateCount());
4498 
4499         mActivity.runOnUiThread(new Runnable() {
4500             public void run() {
4501                 // Remove selection and stop action mode.
4502                 mTextView.onTextContextMenuItem(android.R.id.copy);
4503             }
4504         });
4505         mInstrumentation.waitForIdleSync();
4506 
4507         // Action mode was blocked.
4508         assertEquals(0, callbackBlockActionMode.getDestroyCount());
4509 
4510         // Overwrite callback.
4511         MockActionModeCallback callbackStartActionMode = new MockActionModeCallback(true);
4512         mTextView.setCustomSelectionActionModeCallback(callbackStartActionMode);
4513         assertEquals(callbackStartActionMode, mTextView.getCustomSelectionActionModeCallback());
4514 
4515         mActivity.runOnUiThread(new Runnable() {
4516             public void run() {
4517                 // Set selection and try to start action mode.
4518                 final Bundle args = new Bundle();
4519                 args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
4520                 args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
4521                 mTextView.performAccessibilityAction(
4522                         AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
4523 
4524             }
4525         });
4526         mInstrumentation.waitForIdleSync();
4527 
4528         assertEquals(1, callbackStartActionMode.getCreateCount());
4529 
4530         mActivity.runOnUiThread(new Runnable() {
4531             public void run() {
4532                 // Remove selection and stop action mode.
4533                 mTextView.onTextContextMenuItem(android.R.id.copy);
4534             }
4535         });
4536         mInstrumentation.waitForIdleSync();
4537 
4538         // Action mode was started
4539         assertEquals(1, callbackStartActionMode.getDestroyCount());
4540     }
4541 
testSetAndGetCustomInseltionActionMode()4542     public void testSetAndGetCustomInseltionActionMode() {
4543         initTextViewForTyping();
4544         // Check default value.
4545         assertNull(mTextView.getCustomInsertionActionModeCallback());
4546 
4547         MockActionModeCallback callback = new MockActionModeCallback(false);
4548         mTextView.setCustomInsertionActionModeCallback(callback);
4549         assertEquals(callback, mTextView.getCustomInsertionActionModeCallback());
4550         // TODO(Bug: 22033189): Tests the set callback is actually used.
4551     }
4552 
4553     private static class MockActionModeCallback implements ActionMode.Callback {
4554         private int mCreateCount = 0;
4555         private int mDestroyCount = 0;
4556         private final boolean mAllowToStartActionMode;
4557 
MockActionModeCallback(boolean allowToStartActionMode)4558         public MockActionModeCallback(boolean allowToStartActionMode) {
4559             mAllowToStartActionMode = allowToStartActionMode;
4560         }
4561 
getCreateCount()4562         public int getCreateCount() {
4563             return mCreateCount;
4564         }
4565 
getDestroyCount()4566         public int getDestroyCount() {
4567             return mDestroyCount;
4568         }
4569 
4570         @Override
onPrepareActionMode(ActionMode mode, Menu menu)4571         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
4572             return false;
4573         }
4574 
4575         @Override
onDestroyActionMode(ActionMode mode)4576         public void onDestroyActionMode(ActionMode mode) {
4577             mDestroyCount++;
4578         }
4579 
4580         @Override
onCreateActionMode(ActionMode mode, Menu menu)4581         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
4582             mCreateCount++;
4583             return mAllowToStartActionMode;
4584         }
4585 
4586         @Override
onActionItemClicked(ActionMode mode, MenuItem item)4587         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
4588             return false;
4589         }
4590     };
4591 
4592     private static class MockOnEditorActionListener implements OnEditorActionListener {
4593         private boolean isOnEditorActionCalled;
4594 
onEditorAction(TextView v, int actionId, KeyEvent event)4595         public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
4596             isOnEditorActionCalled = true;
4597             return true;
4598         }
4599 
isOnEditorActionCalled()4600         public boolean isOnEditorActionCalled() {
4601             return isOnEditorActionCalled;
4602         }
4603     }
4604 
layout(final TextView textView)4605     private void layout(final TextView textView) {
4606         mActivity.runOnUiThread(new Runnable() {
4607             public void run() {
4608                 mActivity.setContentView(textView);
4609             }
4610         });
4611         mInstrumentation.waitForIdleSync();
4612     }
4613 
layout(final int layoutId)4614     private void layout(final int layoutId) {
4615         mActivity.runOnUiThread(new Runnable() {
4616             public void run() {
4617                 mActivity.setContentView(layoutId);
4618             }
4619         });
4620         mInstrumentation.waitForIdleSync();
4621     }
4622 
findTextView(int id)4623     private TextView findTextView(int id) {
4624         return (TextView) mActivity.findViewById(id);
4625     }
4626 
getAutoLinkMask(int id)4627     private int getAutoLinkMask(int id) {
4628         return findTextView(id).getAutoLinkMask();
4629     }
4630 
getBitmap(int resid)4631     private Bitmap getBitmap(int resid) {
4632         return ((BitmapDrawable) getDrawable(resid)).getBitmap();
4633     }
4634 
getDrawable(int resid)4635     private Drawable getDrawable(int resid) {
4636         return mActivity.getResources().getDrawable(resid);
4637     }
4638 
setMaxWidth(final int pixels)4639     private void setMaxWidth(final int pixels) {
4640         mActivity.runOnUiThread(new Runnable() {
4641             public void run() {
4642                 mTextView.setMaxWidth(pixels);
4643             }
4644         });
4645         mInstrumentation.waitForIdleSync();
4646     }
4647 
setMinWidth(final int pixels)4648     private void setMinWidth(final int pixels) {
4649         mActivity.runOnUiThread(new Runnable() {
4650             public void run() {
4651                 mTextView.setMinWidth(pixels);
4652             }
4653         });
4654         mInstrumentation.waitForIdleSync();
4655     }
4656 
setMaxHeight(final int pixels)4657     private void setMaxHeight(final int pixels) {
4658         mActivity.runOnUiThread(new Runnable() {
4659             public void run() {
4660                 mTextView.setMaxHeight(pixels);
4661             }
4662         });
4663         mInstrumentation.waitForIdleSync();
4664     }
4665 
setMinHeight(final int pixels)4666     private void setMinHeight(final int pixels) {
4667         mActivity.runOnUiThread(new Runnable() {
4668             public void run() {
4669                 mTextView.setMinHeight(pixels);
4670             }
4671         });
4672         mInstrumentation.waitForIdleSync();
4673     }
4674 
setMinLines(final int minlines)4675     private void setMinLines(final int minlines) {
4676         mActivity.runOnUiThread(new Runnable() {
4677             public void run() {
4678                 mTextView.setMinLines(minlines);
4679             }
4680         });
4681         mInstrumentation.waitForIdleSync();
4682     }
4683 
4684     /**
4685      * Convenience for {@link TextView#setText(CharSequence, BufferType)}. And
4686      * the buffer type is fixed to SPANNABLE.
4687      *
4688      * @param tv the text view
4689      * @param content the content
4690      */
setSpannableText(final TextView tv, final String content)4691     private void setSpannableText(final TextView tv, final String content) {
4692         mActivity.runOnUiThread(new Runnable() {
4693             public void run() {
4694                 tv.setText(content, BufferType.SPANNABLE);
4695             }
4696         });
4697         mInstrumentation.waitForIdleSync();
4698     }
4699 
setLines(final int lines)4700     private void setLines(final int lines) {
4701         mActivity.runOnUiThread(new Runnable() {
4702             public void run() {
4703                 mTextView.setLines(lines);
4704             }
4705         });
4706         mInstrumentation.waitForIdleSync();
4707     }
4708 
setHorizontallyScrolling(final boolean whether)4709     private void setHorizontallyScrolling(final boolean whether) {
4710         mActivity.runOnUiThread(new Runnable() {
4711             public void run() {
4712                 mTextView.setHorizontallyScrolling(whether);
4713             }
4714         });
4715         mInstrumentation.waitForIdleSync();
4716     }
4717 
setWidth(final int pixels)4718     private void setWidth(final int pixels) {
4719         mActivity.runOnUiThread(new Runnable() {
4720             public void run() {
4721                 mTextView.setWidth(pixels);
4722             }
4723         });
4724         mInstrumentation.waitForIdleSync();
4725     }
4726 
setHeight(final int pixels)4727     private void setHeight(final int pixels) {
4728         mActivity.runOnUiThread(new Runnable() {
4729             public void run() {
4730                 mTextView.setHeight(pixels);
4731             }
4732         });
4733         mInstrumentation.waitForIdleSync();
4734     }
4735 
setMinEms(final int ems)4736     private void setMinEms(final int ems) {
4737         mActivity.runOnUiThread(new Runnable() {
4738             public void run() {
4739                 mTextView.setMinEms(ems);
4740             }
4741         });
4742         mInstrumentation.waitForIdleSync();
4743     }
4744 
setMaxEms(final int ems)4745     private void setMaxEms(final int ems) {
4746         mActivity.runOnUiThread(new Runnable() {
4747             public void run() {
4748                 mTextView.setMaxEms(ems);
4749             }
4750         });
4751         mInstrumentation.waitForIdleSync();
4752     }
4753 
setEms(final int ems)4754     private void setEms(final int ems) {
4755         mActivity.runOnUiThread(new Runnable() {
4756             public void run() {
4757                 mTextView.setEms(ems);
4758             }
4759         });
4760         mInstrumentation.waitForIdleSync();
4761     }
4762 
setLineSpacing(final float add, final float mult)4763     private void setLineSpacing(final float add, final float mult) {
4764         mActivity.runOnUiThread(new Runnable() {
4765             public void run() {
4766                 mTextView.setLineSpacing(add, mult);
4767             }
4768         });
4769         mInstrumentation.waitForIdleSync();
4770     }
4771 
4772     private static abstract class TestSelectedRunnable implements Runnable {
4773         private TextView mTextView;
4774         private boolean mIsSelected1;
4775         private boolean mIsSelected2;
4776 
TestSelectedRunnable(TextView textview)4777         public TestSelectedRunnable(TextView textview) {
4778             mTextView = textview;
4779         }
4780 
getIsSelected1()4781         public boolean getIsSelected1() {
4782             return mIsSelected1;
4783         }
4784 
getIsSelected2()4785         public boolean getIsSelected2() {
4786             return mIsSelected2;
4787         }
4788 
saveIsSelected1()4789         public void saveIsSelected1() {
4790             mIsSelected1 = mTextView.isSelected();
4791         }
4792 
saveIsSelected2()4793         public void saveIsSelected2() {
4794             mIsSelected2 = mTextView.isSelected();
4795         }
4796     }
4797 
4798     private static abstract class TestLayoutRunnable implements Runnable {
4799         private TextView mTextView;
4800         private Layout mLayout;
4801 
TestLayoutRunnable(TextView textview)4802         public TestLayoutRunnable(TextView textview) {
4803             mTextView = textview;
4804         }
4805 
getLayout()4806         public Layout getLayout() {
4807             return mLayout;
4808         }
4809 
saveLayout()4810         public void saveLayout() {
4811             mLayout = mTextView.getLayout();
4812         }
4813     }
4814 
4815     private class MockEditableFactory extends Editable.Factory {
4816         private boolean mhasCalledNewEditable;
4817         private CharSequence mSource;
4818 
hasCalledNewEditable()4819         public boolean hasCalledNewEditable() {
4820             return mhasCalledNewEditable;
4821         }
4822 
reset()4823         public void reset() {
4824             mhasCalledNewEditable = false;
4825             mSource = null;
4826         }
4827 
getSource()4828         public CharSequence getSource() {
4829             return mSource;
4830         }
4831 
4832         @Override
newEditable(CharSequence source)4833         public Editable newEditable(CharSequence source) {
4834             mhasCalledNewEditable = true;
4835             mSource = source;
4836             return super.newEditable(source);
4837         }
4838     }
4839 
4840     private class MockSpannableFactory extends Spannable.Factory {
4841         private boolean mHasCalledNewSpannable;
4842         private CharSequence mSource;
4843 
hasCalledNewSpannable()4844         public boolean hasCalledNewSpannable() {
4845             return mHasCalledNewSpannable;
4846         }
4847 
reset()4848         public void reset() {
4849             mHasCalledNewSpannable = false;
4850             mSource = null;
4851         }
4852 
getSource()4853         public CharSequence getSource() {
4854             return mSource;
4855         }
4856 
4857         @Override
newSpannable(CharSequence source)4858         public Spannable newSpannable(CharSequence source) {
4859             mHasCalledNewSpannable = true;
4860             mSource = source;
4861             return super.newSpannable(source);
4862         }
4863     }
4864 
4865     private static class MockTextWatcher implements TextWatcher {
4866         private boolean mHasCalledAfterTextChanged;
4867         private boolean mHasCalledBeforeTextChanged;
4868         private boolean mHasOnTextChanged;
4869 
reset()4870         public void reset(){
4871             mHasCalledAfterTextChanged = false;
4872             mHasCalledBeforeTextChanged = false;
4873             mHasOnTextChanged = false;
4874         }
4875 
hasCalledAfterTextChanged()4876         public boolean hasCalledAfterTextChanged() {
4877             return mHasCalledAfterTextChanged;
4878         }
4879 
hasCalledBeforeTextChanged()4880         public boolean hasCalledBeforeTextChanged() {
4881             return mHasCalledBeforeTextChanged;
4882         }
4883 
hasCalledOnTextChanged()4884         public boolean hasCalledOnTextChanged() {
4885             return mHasOnTextChanged;
4886         }
4887 
afterTextChanged(Editable s)4888         public void afterTextChanged(Editable s) {
4889             mHasCalledAfterTextChanged = true;
4890         }
4891 
beforeTextChanged(CharSequence s, int start, int count, int after)4892         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
4893             mHasCalledBeforeTextChanged = true;
4894         }
4895 
onTextChanged(CharSequence s, int start, int before, int count)4896         public void onTextChanged(CharSequence s, int start, int before, int count) {
4897             mHasOnTextChanged = true;
4898         }
4899     }
4900 
4901     /**
4902      * The listener interface for receiving mockOnLongClick events. The class
4903      * that is interested in processing a mockOnLongClick event implements this
4904      * interface, and the object created with that class is registered with a
4905      * component using the component's
4906      * <code>addMockOnLongClickListener<code> method. When
4907      * the mockOnLongClick event occurs, that object's appropriate
4908      * method is invoked.
4909      *
4910      * @see MockOnLongClickEvent
4911      */
4912     private static class MockOnLongClickListener implements OnLongClickListener {
4913         private boolean mExpectedOnLongClickResult;
4914         private boolean mHasLongClicked;
4915 
MockOnLongClickListener(boolean result)4916         MockOnLongClickListener(boolean result) {
4917             mExpectedOnLongClickResult = result;
4918         }
4919 
hasLongClicked()4920         public boolean hasLongClicked() {
4921             return mHasLongClicked;
4922         }
4923 
onLongClick(View v)4924         public boolean onLongClick(View v) {
4925             mHasLongClicked = true;
4926             return mExpectedOnLongClickResult;
4927         }
4928     }
4929 
4930     /**
4931      * The listener interface for receiving mockOnCreateContextMenu events. The
4932      * class that is interested in processing a mockOnCreateContextMenu event
4933      * implements this interface, and the object created with that class is
4934      * registered with a component using the component's
4935      * <code>addMockOnCreateContextMenuListener<code> method. When the
4936      * mockOnCreateContextMenu event occurs, that object's appropriate method is
4937      * invoked.
4938      *
4939      * @see MockOnCreateContextMenuEvent
4940      */
4941     private static class MockOnCreateContextMenuListener implements OnCreateContextMenuListener {
4942         private boolean mIsMenuItemsBlank;
4943         private boolean mHasCreatedContextMenu;
4944 
MockOnCreateContextMenuListener(boolean isBlank)4945         MockOnCreateContextMenuListener(boolean isBlank) {
4946             this.mIsMenuItemsBlank = isBlank;
4947         }
4948 
hasCreatedContextMenu()4949         public boolean hasCreatedContextMenu() {
4950             return mHasCreatedContextMenu;
4951         }
4952 
reset()4953         public void reset() {
4954             mHasCreatedContextMenu = false;
4955         }
4956 
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)4957         public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
4958             mHasCreatedContextMenu = true;
4959             if (!mIsMenuItemsBlank) {
4960                 menu.add("menu item");
4961             }
4962         }
4963     }
4964 
4965     /**
4966      * A TextWatcher that converts the text to spaces whenever the text changes.
4967      */
4968     private static class ConvertToSpacesTextWatcher implements TextWatcher {
4969         boolean mChangingText;
4970 
4971         @Override
beforeTextChanged(CharSequence s, int start, int count, int after)4972         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
4973         }
4974 
4975         @Override
onTextChanged(CharSequence s, int start, int before, int count)4976         public void onTextChanged(CharSequence s, int start, int before, int count) {
4977         }
4978 
4979         @Override
afterTextChanged(Editable s)4980         public void afterTextChanged(Editable s) {
4981             // Avoid infinite recursion.
4982             if (mChangingText) {
4983                 return;
4984             }
4985             mChangingText = true;
4986             // Create a string of s.length() spaces.
4987             StringBuilder builder = new StringBuilder(s.length());
4988             for (int i = 0; i < s.length(); i++) {
4989                 builder.append(' ');
4990             }
4991             s.replace(0, s.length(), builder.toString());
4992             mChangingText = false;
4993         }
4994     }
4995 }
4996