blob: 555aac5de6bfe87575312eae89141d063c0ab297 [file] [log] [blame]
/*
* Copyright (C) 2011 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.style;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.text.ParcelableSpan;
import android.text.TextUtils;
import android.widget.TextView;
import java.util.Arrays;
import java.util.Locale;
/**
* Holds suggestion candidates for the text enclosed in this span.
*
* When such a span is edited in an EditText, double tapping on the text enclosed in this span will
* display a popup dialog listing suggestion replacement for that text. The user can then replace
* the original text by one of the suggestions.
*
* These spans should typically be created by the input method to privide correction and alternates
* for the text.
*
* @see TextView#setSuggestionsEnabled(boolean)
*/
public class SuggestionSpan implements ParcelableSpan {
/**
* Flag for indicating that the input is verbatim. TextView refers to this flag to determine
* how it displays a word with SuggestionSpan.
*/
public static final int FLAG_VERBATIM = 0x0001;
public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before";
public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode";
public static final int SUGGESTIONS_MAX_SIZE = 5;
/*
* TODO: Needs to check the validity and add a feature that TextView will change
* the current IME to the other IME which is specified in SuggestionSpan.
* An IME needs to set the span by specifying the target IME and Subtype of SuggestionSpan.
* And the current IME might want to specify any IME as the target IME including other IMEs.
*/
private final int mFlags;
private final String[] mSuggestions;
private final String mLocaleString;
private final String mNotificationTargetClassName;
private final int mHashCode;
/*
* TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
* and InputMethodSubtype.
*/
/**
* @param context Context for the application
* @param suggestions Suggestions for the string under the span
* @param flags Additional flags indicating how this span is handled in TextView
*/
public SuggestionSpan(Context context, String[] suggestions, int flags) {
this(context, null, suggestions, flags, null);
}
/**
* @param locale Locale of the suggestions
* @param suggestions Suggestions for the string under the span
* @param flags Additional flags indicating how this span is handled in TextView
*/
public SuggestionSpan(Locale locale, String[] suggestions, int flags) {
this(null, locale, suggestions, flags, null);
}
/**
* @param context Context for the application
* @param locale locale Locale of the suggestions
* @param suggestions Suggestions for the string under the span
* @param flags Additional flags indicating how this span is handled in TextView
* @param notificationTargetClass if not null, this class will get notified when the user
* selects one of the suggestions.
*/
public SuggestionSpan(Context context, Locale locale, String[] suggestions, int flags,
Class<?> notificationTargetClass) {
final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length);
mSuggestions = Arrays.copyOf(suggestions, N);
mFlags = flags;
if (context != null && locale == null) {
mLocaleString = context.getResources().getConfiguration().locale.toString();
} else {
mLocaleString = locale.toString();
}
if (notificationTargetClass != null) {
mNotificationTargetClassName = notificationTargetClass.getCanonicalName();
} else {
mNotificationTargetClassName = "";
}
mHashCode = hashCodeInternal(
mFlags, mSuggestions, mLocaleString, mNotificationTargetClassName);
}
public SuggestionSpan(Parcel src) {
mSuggestions = src.readStringArray();
mFlags = src.readInt();
mLocaleString = src.readString();
mNotificationTargetClassName = src.readString();
mHashCode = src.readInt();
}
/**
* @return an array of suggestion texts for this span
*/
public String[] getSuggestions() {
return mSuggestions;
}
/**
* @return the locale of the suggestions
*/
public String getLocale() {
return mLocaleString;
}
/**
* @return The name of the class to notify. The class of the original IME package will receive
* a notification when the user selects one of the suggestions. The notification will include
* the original string, the suggested replacement string as well as the hashCode of this span.
* The class will get notified by an intent that has those information.
* This is an internal API because only the framework should know the class name.
*
* @hide
*/
public String getNotificationTargetClassName() {
return mNotificationTargetClassName;
}
public int getFlags() {
return mFlags;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(mSuggestions);
dest.writeInt(mFlags);
dest.writeString(mLocaleString);
dest.writeString(mNotificationTargetClassName);
dest.writeInt(mHashCode);
}
@Override
public int getSpanTypeId() {
return TextUtils.SUGGESTION_SPAN;
}
@Override
public boolean equals(Object o) {
if (o instanceof SuggestionSpan) {
return ((SuggestionSpan)o).hashCode() == mHashCode;
}
return false;
}
@Override
public int hashCode() {
return mHashCode;
}
private static int hashCodeInternal(int flags, String[] suggestions,String locale,
String notificationTargetClassName) {
return Arrays.hashCode(new Object[] {SystemClock.uptimeMillis(), flags, suggestions, locale,
notificationTargetClassName});
}
public static final Parcelable.Creator<SuggestionSpan> CREATOR =
new Parcelable.Creator<SuggestionSpan>() {
@Override
public SuggestionSpan createFromParcel(Parcel source) {
return new SuggestionSpan(source);
}
@Override
public SuggestionSpan[] newArray(int size) {
return new SuggestionSpan[size];
}
};
}