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