1 /* 2 * Copyright (C) 2006 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.text.method; 18 19 import android.graphics.Rect; 20 import android.text.Editable; 21 import android.text.GetChars; 22 import android.text.Spannable; 23 import android.text.Spanned; 24 import android.text.SpannedString; 25 import android.text.TextUtils; 26 import android.view.View; 27 28 /** 29 * This transformation method causes the characters in the {@link #getOriginal} 30 * array to be replaced by the corresponding characters in the 31 * {@link #getReplacement} array. 32 */ 33 @android.ravenwood.annotation.RavenwoodKeepWholeClass 34 public abstract class ReplacementTransformationMethod 35 implements TransformationMethod 36 { 37 /** 38 * Returns the list of characters that are to be replaced by other 39 * characters when displayed. 40 */ getOriginal()41 protected abstract char[] getOriginal(); 42 /** 43 * Returns a parallel array of replacement characters for the ones 44 * that are to be replaced. 45 */ getReplacement()46 protected abstract char[] getReplacement(); 47 48 /** 49 * Returns a CharSequence that will mirror the contents of the 50 * source CharSequence but with the characters in {@link #getOriginal} 51 * replaced by ones from {@link #getReplacement}. 52 */ getTransformation(CharSequence source, View v)53 public CharSequence getTransformation(CharSequence source, View v) { 54 char[] original = getOriginal(); 55 char[] replacement = getReplacement(); 56 57 /* 58 * Short circuit for faster display if the text will never change. 59 */ 60 if (!(source instanceof Editable)) { 61 /* 62 * Check whether the text does not contain any of the 63 * source characters so can be used unchanged. 64 */ 65 boolean doNothing = true; 66 int n = original.length; 67 for (int i = 0; i < n; i++) { 68 if (TextUtils.indexOf(source, original[i]) >= 0) { 69 doNothing = false; 70 break; 71 } 72 } 73 if (doNothing) { 74 return source; 75 } 76 77 if (!(source instanceof Spannable)) { 78 /* 79 * The text contains some of the source characters, 80 * but they can be flattened out now instead of 81 * at display time. 82 */ 83 if (source instanceof Spanned) { 84 return new SpannedString(new SpannedReplacementCharSequence( 85 (Spanned) source, 86 original, replacement)); 87 } else { 88 return new ReplacementCharSequence(source, 89 original, 90 replacement).toString(); 91 } 92 } 93 } 94 95 if (source instanceof Spanned) { 96 return new SpannedReplacementCharSequence((Spanned) source, 97 original, replacement); 98 } else { 99 return new ReplacementCharSequence(source, original, replacement); 100 } 101 } 102 onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect)103 public void onFocusChanged(View view, CharSequence sourceText, 104 boolean focused, int direction, 105 Rect previouslyFocusedRect) { 106 // This callback isn't used. 107 } 108 109 private static class ReplacementCharSequence 110 implements CharSequence, GetChars { 111 private char[] mOriginal, mReplacement; 112 ReplacementCharSequence(CharSequence source, char[] original, char[] replacement)113 public ReplacementCharSequence(CharSequence source, char[] original, 114 char[] replacement) { 115 mSource = source; 116 mOriginal = original; 117 mReplacement = replacement; 118 } 119 length()120 public int length() { 121 return mSource.length(); 122 } 123 charAt(int i)124 public char charAt(int i) { 125 char c = mSource.charAt(i); 126 127 int n = mOriginal.length; 128 for (int j = 0; j < n; j++) { 129 if (c == mOriginal[j]) { 130 c = mReplacement[j]; 131 } 132 } 133 134 return c; 135 } 136 subSequence(int start, int end)137 public CharSequence subSequence(int start, int end) { 138 char[] c = new char[end - start]; 139 140 getChars(start, end, c, 0); 141 return new String(c); 142 } 143 toString()144 public String toString() { 145 char[] c = new char[length()]; 146 147 getChars(0, length(), c, 0); 148 return new String(c); 149 } 150 getChars(int start, int end, char[] dest, int off)151 public void getChars(int start, int end, char[] dest, int off) { 152 TextUtils.getChars(mSource, start, end, dest, off); 153 int offend = end - start + off; 154 int n = mOriginal.length; 155 156 for (int i = off; i < offend; i++) { 157 char c = dest[i]; 158 159 for (int j = 0; j < n; j++) { 160 if (c == mOriginal[j]) { 161 dest[i] = mReplacement[j]; 162 } 163 } 164 } 165 } 166 167 private CharSequence mSource; 168 } 169 170 private static class SpannedReplacementCharSequence 171 extends ReplacementCharSequence 172 implements Spanned 173 { SpannedReplacementCharSequence(Spanned source, char[] original, char[] replacement)174 public SpannedReplacementCharSequence(Spanned source, char[] original, 175 char[] replacement) { 176 super(source, original, replacement); 177 mSpanned = source; 178 } 179 subSequence(int start, int end)180 public CharSequence subSequence(int start, int end) { 181 return new SpannedString(this).subSequence(start, end); 182 } 183 getSpans(int start, int end, Class<T> type)184 public <T> T[] getSpans(int start, int end, Class<T> type) { 185 return mSpanned.getSpans(start, end, type); 186 } 187 getSpanStart(Object tag)188 public int getSpanStart(Object tag) { 189 return mSpanned.getSpanStart(tag); 190 } 191 getSpanEnd(Object tag)192 public int getSpanEnd(Object tag) { 193 return mSpanned.getSpanEnd(tag); 194 } 195 getSpanFlags(Object tag)196 public int getSpanFlags(Object tag) { 197 return mSpanned.getSpanFlags(tag); 198 } 199 nextSpanTransition(int start, int end, Class type)200 public int nextSpanTransition(int start, int end, Class type) { 201 return mSpanned.nextSpanTransition(start, end, type); 202 } 203 204 private Spanned mSpanned; 205 } 206 } 207