SuggestionSpan.java revision 4dacef25662de37825fa7a67fd6bdb318b31d8d9
1/* 2 * Copyright (C) 2011 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 17package android.text.style; 18 19import android.content.Context; 20import android.os.Parcel; 21import android.os.Parcelable; 22import android.os.SystemClock; 23import android.text.ParcelableSpan; 24import android.text.TextUtils; 25import android.widget.TextView; 26 27import java.util.Arrays; 28import java.util.Locale; 29 30/** 31 * Holds suggestion candidates for the text enclosed in this span. 32 * 33 * When such a span is edited in an EditText, double tapping on the text enclosed in this span will 34 * display a popup dialog listing suggestion replacement for that text. The user can then replace 35 * the original text by one of the suggestions. 36 * 37 * These spans should typically be created by the input method to privide correction and alternates 38 * for the text. 39 * 40 * @see TextView#setSuggestionsEnabled(boolean) 41 */ 42public class SuggestionSpan implements ParcelableSpan { 43 /** 44 * Flag for indicating that the input is verbatim. TextView refers to this flag to determine 45 * how it displays a word with SuggestionSpan. 46 */ 47 public static final int FLAG_VERBATIM = 0x0001; 48 49 public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED"; 50 public static final String SUGGESTION_SPAN_PICKED_AFTER = "after"; 51 public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before"; 52 public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode"; 53 54 public static final int SUGGESTIONS_MAX_SIZE = 5; 55 56 /* 57 * TODO: Needs to check the validity and add a feature that TextView will change 58 * the current IME to the other IME which is specified in SuggestionSpan. 59 * An IME needs to set the span by specifying the target IME and Subtype of SuggestionSpan. 60 * And the current IME might want to specify any IME as the target IME including other IMEs. 61 */ 62 63 private final int mFlags; 64 private final String[] mSuggestions; 65 private final String mLocaleString; 66 private final String mNotificationTargetClassName; 67 private final int mHashCode; 68 69 /* 70 * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo 71 * and InputMethodSubtype. 72 */ 73 74 /** 75 * @param context Context for the application 76 * @param suggestions Suggestions for the string under the span 77 * @param flags Additional flags indicating how this span is handled in TextView 78 */ 79 public SuggestionSpan(Context context, String[] suggestions, int flags) { 80 this(context, null, suggestions, flags, null); 81 } 82 83 /** 84 * @param locale Locale of the suggestions 85 * @param suggestions Suggestions for the string under the span 86 * @param flags Additional flags indicating how this span is handled in TextView 87 */ 88 public SuggestionSpan(Locale locale, String[] suggestions, int flags) { 89 this(null, locale, suggestions, flags, null); 90 } 91 92 /** 93 * @param context Context for the application 94 * @param locale locale Locale of the suggestions 95 * @param suggestions Suggestions for the string under the span 96 * @param flags Additional flags indicating how this span is handled in TextView 97 * @param notificationTargetClass if not null, this class will get notified when the user 98 * selects one of the suggestions. 99 */ 100 public SuggestionSpan(Context context, Locale locale, String[] suggestions, int flags, 101 Class<?> notificationTargetClass) { 102 final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length); 103 mSuggestions = Arrays.copyOf(suggestions, N); 104 mFlags = flags; 105 if (context != null && locale == null) { 106 mLocaleString = context.getResources().getConfiguration().locale.toString(); 107 } else { 108 mLocaleString = locale.toString(); 109 } 110 if (notificationTargetClass != null) { 111 mNotificationTargetClassName = notificationTargetClass.getCanonicalName(); 112 } else { 113 mNotificationTargetClassName = ""; 114 } 115 mHashCode = hashCodeInternal( 116 mFlags, mSuggestions, mLocaleString, mNotificationTargetClassName); 117 } 118 119 public SuggestionSpan(Parcel src) { 120 mSuggestions = src.readStringArray(); 121 mFlags = src.readInt(); 122 mLocaleString = src.readString(); 123 mNotificationTargetClassName = src.readString(); 124 mHashCode = src.readInt(); 125 } 126 127 /** 128 * @return an array of suggestion texts for this span 129 */ 130 public String[] getSuggestions() { 131 return mSuggestions; 132 } 133 134 /** 135 * @return the locale of the suggestions 136 */ 137 public String getLocale() { 138 return mLocaleString; 139 } 140 141 /** 142 * @return The name of the class to notify. The class of the original IME package will receive 143 * a notification when the user selects one of the suggestions. The notification will include 144 * the original string, the suggested replacement string as well as the hashCode of this span. 145 * The class will get notified by an intent that has those information. 146 * This is an internal API because only the framework should know the class name. 147 * 148 * @hide 149 */ 150 public String getNotificationTargetClassName() { 151 return mNotificationTargetClassName; 152 } 153 154 public int getFlags() { 155 return mFlags; 156 } 157 158 @Override 159 public int describeContents() { 160 return 0; 161 } 162 163 @Override 164 public void writeToParcel(Parcel dest, int flags) { 165 dest.writeStringArray(mSuggestions); 166 dest.writeInt(mFlags); 167 dest.writeString(mLocaleString); 168 dest.writeString(mNotificationTargetClassName); 169 dest.writeInt(mHashCode); 170 } 171 172 @Override 173 public int getSpanTypeId() { 174 return TextUtils.SUGGESTION_SPAN; 175 } 176 177 @Override 178 public boolean equals(Object o) { 179 if (o instanceof SuggestionSpan) { 180 return ((SuggestionSpan)o).hashCode() == mHashCode; 181 } 182 return false; 183 } 184 185 @Override 186 public int hashCode() { 187 return mHashCode; 188 } 189 190 private static int hashCodeInternal(int flags, String[] suggestions,String locale, 191 String notificationTargetClassName) { 192 return Arrays.hashCode(new Object[] {SystemClock.uptimeMillis(), flags, suggestions, locale, 193 notificationTargetClassName}); 194 } 195 196 public static final Parcelable.Creator<SuggestionSpan> CREATOR = 197 new Parcelable.Creator<SuggestionSpan>() { 198 @Override 199 public SuggestionSpan createFromParcel(Parcel source) { 200 return new SuggestionSpan(source); 201 } 202 203 @Override 204 public SuggestionSpan[] newArray(int size) { 205 return new SuggestionSpan[size]; 206 } 207 }; 208} 209