blob: d6f879aa43538e8109588ff435617f7de7d66f80 [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.text.method;
import android.graphics.Rect;
import android.text.Editable;
import android.text.GetChars;
import android.text.Spannable;
import android.text.Spanned;
import android.text.SpannedString;
import android.text.TextUtils;
import android.view.View;
/**
* This transformation method causes the characters in the {@link #getOriginal}
* array to be replaced by the corresponding characters in the
* {@link #getReplacement} array.
*/
public abstract class ReplacementTransformationMethod
implements TransformationMethod
{
/**
* Returns the list of characters that are to be replaced by other
* characters when displayed.
*/
protected abstract char[] getOriginal();
/**
* Returns a parallel array of replacement characters for the ones
* that are to be replaced.
*/
protected abstract char[] getReplacement();
/**
* Returns a CharSequence that will mirror the contents of the
* source CharSequence but with the characters in {@link #getOriginal}
* replaced by ones from {@link #getReplacement}.
*/
public CharSequence getTransformation(CharSequence source, View v) {
char[] original = getOriginal();
char[] replacement = getReplacement();
/*
* Short circuit for faster display if the text will never change.
*/
if (!(source instanceof Editable)) {
/*
* Check whether the text does not contain any of the
* source characters so can be used unchanged.
*/
boolean doNothing = true;
int n = original.length;
for (int i = 0; i < n; i++) {
if (TextUtils.indexOf(source, original[i]) >= 0) {
doNothing = false;
break;
}
}
if (doNothing) {
return source;
}
if (!(source instanceof Spannable)) {
/*
* The text contains some of the source characters,
* but they can be flattened out now instead of
* at display time.
*/
if (source instanceof Spanned) {
return new SpannedString(new SpannedReplacementCharSequence(
(Spanned) source,
original, replacement));
} else {
return new ReplacementCharSequence(source,
original,
replacement).toString();
}
}
}
if (source instanceof Spanned) {
return new SpannedReplacementCharSequence((Spanned) source,
original, replacement);
} else {
return new ReplacementCharSequence(source, original, replacement);
}
}
public void onFocusChanged(View view, CharSequence sourceText,
boolean focused, int direction,
Rect previouslyFocusedRect) {
// This callback isn't used.
}
private static class ReplacementCharSequence
implements CharSequence, GetChars {
private char[] mOriginal, mReplacement;
public ReplacementCharSequence(CharSequence source, char[] original,
char[] replacement) {
mSource = source;
mOriginal = original;
mReplacement = replacement;
}
public int length() {
return mSource.length();
}
public char charAt(int i) {
char c = mSource.charAt(i);
int n = mOriginal.length;
for (int j = 0; j < n; j++) {
if (c == mOriginal[j]) {
c = mReplacement[j];
}
}
return c;
}
public CharSequence subSequence(int start, int end) {
char[] c = new char[end - start];
getChars(start, end, c, 0);
return new String(c);
}
public String toString() {
char[] c = new char[length()];
getChars(0, length(), c, 0);
return new String(c);
}
public void getChars(int start, int end, char[] dest, int off) {
TextUtils.getChars(mSource, start, end, dest, off);
int offend = end - start + off;
int n = mOriginal.length;
for (int i = off; i < offend; i++) {
char c = dest[i];
for (int j = 0; j < n; j++) {
if (c == mOriginal[j]) {
dest[i] = mReplacement[j];
}
}
}
}
private CharSequence mSource;
}
private static class SpannedReplacementCharSequence
extends ReplacementCharSequence
implements Spanned
{
public SpannedReplacementCharSequence(Spanned source, char[] original,
char[] replacement) {
super(source, original, replacement);
mSpanned = source;
}
public CharSequence subSequence(int start, int end) {
return new SpannedString(this).subSequence(start, end);
}
public <T> T[] getSpans(int start, int end, Class<T> type) {
return mSpanned.getSpans(start, end, type);
}
public int getSpanStart(Object tag) {
return mSpanned.getSpanStart(tag);
}
public int getSpanEnd(Object tag) {
return mSpanned.getSpanEnd(tag);
}
public int getSpanFlags(Object tag) {
return mSpanned.getSpanFlags(tag);
}
public int nextSpanTransition(int start, int end, Class type) {
return mSpanned.nextSpanTransition(start, end, type);
}
private Spanned mSpanned;
}
}