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