1 package android.text; 2 3 import static android.text.Spanned.SPAN_INCLUSIVE_INCLUSIVE; 4 5 import android.text.style.BulletSpan; 6 7 import java.util.Random; 8 9 /** 10 * 11 */ 12 public class NonEditableTextGenerator { 13 14 enum TextType { 15 STRING, 16 SPANNED, 17 SPANNABLE_BUILDER 18 } 19 20 private boolean mCreateBoring; 21 private TextType mTextType; 22 private int mSequenceLength; 23 private final Random mRandom; 24 NonEditableTextGenerator(Random random)25 public NonEditableTextGenerator(Random random) { 26 mRandom = random; 27 } 28 setCreateBoring(boolean createBoring)29 public NonEditableTextGenerator setCreateBoring(boolean createBoring) { 30 mCreateBoring = createBoring; 31 return this; 32 } 33 setTextType(TextType textType)34 public NonEditableTextGenerator setTextType(TextType textType) { 35 mTextType = textType; 36 return this; 37 } 38 setSequenceLength(int sequenceLength)39 public NonEditableTextGenerator setSequenceLength(int sequenceLength) { 40 mSequenceLength = sequenceLength; 41 return this; 42 } 43 44 /** 45 * Sample charSequence generated: 46 * NRjPzjvUadHmH ExoEoTqfx pCLw qtndsqfpk AqajVCbgjGZ igIeC dfnXRgA 47 */ build()48 public CharSequence build() { 49 final RandomCharSequenceGenerator sequenceGenerator = new RandomCharSequenceGenerator( 50 mRandom); 51 if (mSequenceLength > 0) { 52 sequenceGenerator.setSequenceLength(mSequenceLength); 53 } 54 55 final CharSequence charSequence = sequenceGenerator.buildLatinSequence(); 56 57 switch (mTextType) { 58 case SPANNED: 59 case SPANNABLE_BUILDER: 60 return createSpannable(charSequence); 61 case STRING: 62 default: 63 return createString(charSequence); 64 } 65 } 66 createSpannable(CharSequence charSequence)67 private Spannable createSpannable(CharSequence charSequence) { 68 final Spannable spannable = (mTextType == TextType.SPANNABLE_BUILDER) ? 69 new SpannableStringBuilder(charSequence) : new SpannableString(charSequence); 70 71 if (!mCreateBoring) { 72 // add a paragraph style to make it non boring 73 spannable.setSpan(new BulletSpan(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE); 74 } 75 76 spannable.setSpan(new Object(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE); 77 spannable.setSpan(new Object(), 0, 1, SPAN_INCLUSIVE_INCLUSIVE); 78 79 return spannable; 80 } 81 createString(CharSequence charSequence)82 private String createString(CharSequence charSequence) { 83 if (mCreateBoring) { 84 return charSequence.toString(); 85 } else { 86 // BoringLayout checks to see if there is a surrogate pair and if so tells that 87 // the charSequence is not suitable for boring. Add an emoji to make it non boring. 88 // Emoji is added instead of RTL, since emoji stays in the same run and is a more 89 // common case. 90 return charSequence.toString() + "\uD83D\uDC68\uD83C\uDFFF"; 91 } 92 } 93 94 public static class RandomCharSequenceGenerator { 95 96 private static final int DEFAULT_MIN_WORD_LENGTH = 3; 97 private static final int DEFAULT_MAX_WORD_LENGTH = 15; 98 private static final int DEFAULT_SEQUENCE_LENGTH = 256; 99 100 private int mMinWordLength = DEFAULT_MIN_WORD_LENGTH; 101 private int mMaxWordLength = DEFAULT_MAX_WORD_LENGTH; 102 private int mSequenceLength = DEFAULT_SEQUENCE_LENGTH; 103 private final Random mRandom; 104 RandomCharSequenceGenerator(Random random)105 public RandomCharSequenceGenerator(Random random) { 106 mRandom = random; 107 } 108 setSequenceLength(int sequenceLength)109 public RandomCharSequenceGenerator setSequenceLength(int sequenceLength) { 110 mSequenceLength = sequenceLength; 111 return this; 112 } 113 buildLatinSequence()114 public CharSequence buildLatinSequence() { 115 final StringBuilder result = new StringBuilder(); 116 while (result.length() < mSequenceLength) { 117 // add random word 118 result.append(buildLatinWord()); 119 result.append(' '); 120 } 121 return result.substring(0, mSequenceLength); 122 } 123 buildLatinWord()124 public CharSequence buildLatinWord() { 125 final StringBuilder result = new StringBuilder(); 126 // create a random length that is (mMinWordLength + random amount of chars) where 127 // total size is less than mMaxWordLength 128 final int length = mRandom.nextInt(mMaxWordLength - mMinWordLength) + mMinWordLength; 129 while (result.length() < length) { 130 // add random letter 131 int base = mRandom.nextInt(2) == 0 ? 'A' : 'a'; 132 result.append(Character.toChars(mRandom.nextInt(26) + base)); 133 } 134 return result.toString(); 135 } 136 } 137 138 } 139