satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 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 | |
| 17 | package android.text.style; |
| 18 | |
| 19 | import android.content.Context; |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 20 | import android.content.Intent; |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 21 | import android.content.res.TypedArray; |
| 22 | import android.graphics.Color; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 23 | import android.os.Parcel; |
| 24 | import android.os.Parcelable; |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 25 | import android.os.SystemClock; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 26 | import android.text.ParcelableSpan; |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 27 | import android.text.TextPaint; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 28 | import android.text.TextUtils; |
Gilles Debunne | 6e0b22b | 2012-01-25 14:57:40 -0800 | [diff] [blame] | 29 | import android.util.Log; |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 30 | import android.view.inputmethod.InputMethodManager; |
Gilles Debunne | 4dacef2 | 2011-07-08 11:45:39 -0700 | [diff] [blame] | 31 | import android.widget.TextView; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 32 | |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 33 | import java.util.Arrays; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 34 | import java.util.Locale; |
| 35 | |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 36 | /** |
Gilles Debunne | 4dacef2 | 2011-07-08 11:45:39 -0700 | [diff] [blame] | 37 | * Holds suggestion candidates for the text enclosed in this span. |
| 38 | * |
| 39 | * When such a span is edited in an EditText, double tapping on the text enclosed in this span will |
| 40 | * display a popup dialog listing suggestion replacement for that text. The user can then replace |
| 41 | * the original text by one of the suggestions. |
| 42 | * |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 43 | * These spans should typically be created by the input method to provide correction and alternates |
Gilles Debunne | 4dacef2 | 2011-07-08 11:45:39 -0700 | [diff] [blame] | 44 | * for the text. |
| 45 | * |
Gilles Debunne | 6435a56 | 2011-08-04 21:22:30 -0700 | [diff] [blame] | 46 | * @see TextView#isSuggestionsEnabled() |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 47 | */ |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 48 | public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { |
| 49 | |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 50 | private static final String TAG = "SuggestionSpan"; |
| 51 | |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 52 | /** |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 53 | * Sets this flag if the suggestions should be easily accessible with few interactions. |
| 54 | * This flag should be set for every suggestions that the user is likely to use. |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 55 | */ |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 56 | public static final int FLAG_EASY_CORRECT = 0x0001; |
| 57 | |
| 58 | /** |
| 59 | * Sets this flag if the suggestions apply to a misspelled word/text. This type of suggestion is |
| 60 | * rendered differently to highlight the error. |
| 61 | */ |
| 62 | public static final int FLAG_MISSPELLED = 0x0002; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 63 | |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 64 | /** |
| 65 | * Sets this flag if the auto correction is about to be applied to a word/text |
| 66 | * that the user is typing/composing. This type of suggestion is rendered differently |
| 67 | * to indicate the auto correction is happening. |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 68 | */ |
| 69 | public static final int FLAG_AUTO_CORRECTION = 0x0004; |
| 70 | |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 71 | public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED"; |
| 72 | public static final String SUGGESTION_SPAN_PICKED_AFTER = "after"; |
| 73 | public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before"; |
| 74 | public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode"; |
| 75 | |
| 76 | public static final int SUGGESTIONS_MAX_SIZE = 5; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 77 | |
| 78 | /* |
| 79 | * TODO: Needs to check the validity and add a feature that TextView will change |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 80 | * the current IME to the other IME which is specified in SuggestionSpan. |
| 81 | * An IME needs to set the span by specifying the target IME and Subtype of SuggestionSpan. |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 82 | * And the current IME might want to specify any IME as the target IME including other IMEs. |
| 83 | */ |
| 84 | |
Gilles Debunne | 6435a56 | 2011-08-04 21:22:30 -0700 | [diff] [blame] | 85 | private int mFlags; |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 86 | private final String[] mSuggestions; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 87 | private final String mLocaleString; |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 88 | private final String mNotificationTargetClassName; |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 89 | private final String mNotificationTargetPackageName; |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 90 | private final int mHashCode; |
| 91 | |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 92 | private float mEasyCorrectUnderlineThickness; |
| 93 | private int mEasyCorrectUnderlineColor; |
| 94 | |
| 95 | private float mMisspelledUnderlineThickness; |
| 96 | private int mMisspelledUnderlineColor; |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 97 | |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 98 | private float mAutoCorrectionUnderlineThickness; |
| 99 | private int mAutoCorrectionUnderlineColor; |
| 100 | |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 101 | /** |
| 102 | * @param context Context for the application |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 103 | * @param suggestions Suggestions for the string under the span |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 104 | * @param flags Additional flags indicating how this span is handled in TextView |
| 105 | */ |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 106 | public SuggestionSpan(Context context, String[] suggestions, int flags) { |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 107 | this(context, null, suggestions, flags, null); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | /** |
| 111 | * @param locale Locale of the suggestions |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 112 | * @param suggestions Suggestions for the string under the span |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 113 | * @param flags Additional flags indicating how this span is handled in TextView |
| 114 | */ |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 115 | public SuggestionSpan(Locale locale, String[] suggestions, int flags) { |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 116 | this(null, locale, suggestions, flags, null); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 117 | } |
| 118 | |
| 119 | /** |
| 120 | * @param context Context for the application |
| 121 | * @param locale locale Locale of the suggestions |
Gilles Debunne | c9fd978 | 2011-09-09 09:20:12 -0700 | [diff] [blame] | 122 | * @param suggestions Suggestions for the string under the span. Only the first up to |
Gilles Debunne | 6e0b22b | 2012-01-25 14:57:40 -0800 | [diff] [blame] | 123 | * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. Null values not permitted. |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 124 | * @param flags Additional flags indicating how this span is handled in TextView |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 125 | * @param notificationTargetClass if not null, this class will get notified when the user |
| 126 | * selects one of the suggestions. |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 127 | */ |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 128 | public SuggestionSpan(Context context, Locale locale, String[] suggestions, int flags, |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 129 | Class<?> notificationTargetClass) { |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 130 | final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length); |
| 131 | mSuggestions = Arrays.copyOf(suggestions, N); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 132 | mFlags = flags; |
Gilles Debunne | 6e0b22b | 2012-01-25 14:57:40 -0800 | [diff] [blame] | 133 | if (locale != null) { |
| 134 | mLocaleString = locale.toString(); |
| 135 | } else if (context != null) { |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 136 | mLocaleString = context.getResources().getConfiguration().locale.toString(); |
| 137 | } else { |
Gilles Debunne | 6e0b22b | 2012-01-25 14:57:40 -0800 | [diff] [blame] | 138 | Log.e("SuggestionSpan", "No locale or context specified in SuggestionSpan constructor"); |
| 139 | mLocaleString = ""; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 140 | } |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 141 | |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 142 | if (context != null) { |
| 143 | mNotificationTargetPackageName = context.getPackageName(); |
| 144 | } else { |
| 145 | mNotificationTargetPackageName = null; |
| 146 | } |
| 147 | |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 148 | if (notificationTargetClass != null) { |
| 149 | mNotificationTargetClassName = notificationTargetClass.getCanonicalName(); |
| 150 | } else { |
| 151 | mNotificationTargetClassName = ""; |
| 152 | } |
Gilles Debunne | 6435a56 | 2011-08-04 21:22:30 -0700 | [diff] [blame] | 153 | mHashCode = hashCodeInternal(mSuggestions, mLocaleString, mNotificationTargetClassName); |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 154 | |
| 155 | initStyle(context); |
| 156 | } |
| 157 | |
| 158 | private void initStyle(Context context) { |
Gilles Debunne | c5436f2 | 2011-12-06 10:27:00 -0800 | [diff] [blame] | 159 | if (context == null) { |
| 160 | mMisspelledUnderlineThickness = 0; |
| 161 | mEasyCorrectUnderlineThickness = 0; |
| 162 | mAutoCorrectionUnderlineThickness = 0; |
| 163 | mMisspelledUnderlineColor = Color.BLACK; |
| 164 | mEasyCorrectUnderlineColor = Color.BLACK; |
| 165 | mAutoCorrectionUnderlineColor = Color.BLACK; |
| 166 | return; |
| 167 | } |
| 168 | |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 169 | int defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion; |
| 170 | TypedArray typedArray = context.obtainStyledAttributes( |
| 171 | null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0); |
| 172 | mMisspelledUnderlineThickness = typedArray.getDimension( |
Luca Zanolin | e6d3682 | 2011-08-30 18:04:34 +0100 | [diff] [blame] | 173 | com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0); |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 174 | mMisspelledUnderlineColor = typedArray.getColor( |
| 175 | com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK); |
| 176 | |
| 177 | defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion; |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 178 | typedArray = context.obtainStyledAttributes( |
| 179 | null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0); |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 180 | mEasyCorrectUnderlineThickness = typedArray.getDimension( |
| 181 | com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0); |
| 182 | mEasyCorrectUnderlineColor = typedArray.getColor( |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 183 | com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK); |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 184 | |
| 185 | defStyle = com.android.internal.R.attr.textAppearanceAutoCorrectionSuggestion; |
| 186 | typedArray = context.obtainStyledAttributes( |
| 187 | null, com.android.internal.R.styleable.SuggestionSpan, defStyle, 0); |
| 188 | mAutoCorrectionUnderlineThickness = typedArray.getDimension( |
| 189 | com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0); |
| 190 | mAutoCorrectionUnderlineColor = typedArray.getColor( |
| 191 | com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 192 | } |
| 193 | |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 194 | public SuggestionSpan(Parcel src) { |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 195 | mSuggestions = src.readStringArray(); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 196 | mFlags = src.readInt(); |
| 197 | mLocaleString = src.readString(); |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 198 | mNotificationTargetClassName = src.readString(); |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 199 | mNotificationTargetPackageName = src.readString(); |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 200 | mHashCode = src.readInt(); |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 201 | mEasyCorrectUnderlineColor = src.readInt(); |
| 202 | mEasyCorrectUnderlineThickness = src.readFloat(); |
| 203 | mMisspelledUnderlineColor = src.readInt(); |
| 204 | mMisspelledUnderlineThickness = src.readFloat(); |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 205 | mAutoCorrectionUnderlineColor = src.readInt(); |
| 206 | mAutoCorrectionUnderlineThickness = src.readFloat(); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | /** |
Gilles Debunne | 4dacef2 | 2011-07-08 11:45:39 -0700 | [diff] [blame] | 210 | * @return an array of suggestion texts for this span |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 211 | */ |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 212 | public String[] getSuggestions() { |
Gilles Debunne | ee511cc | 2011-05-05 14:57:50 -0700 | [diff] [blame] | 213 | return mSuggestions; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 214 | } |
| 215 | |
| 216 | /** |
Gilles Debunne | 4dacef2 | 2011-07-08 11:45:39 -0700 | [diff] [blame] | 217 | * @return the locale of the suggestions |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 218 | */ |
| 219 | public String getLocale() { |
| 220 | return mLocaleString; |
| 221 | } |
| 222 | |
| 223 | /** |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 224 | * @return The name of the class to notify. The class of the original IME package will receive |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 225 | * a notification when the user selects one of the suggestions. The notification will include |
| 226 | * the original string, the suggested replacement string as well as the hashCode of this span. |
| 227 | * The class will get notified by an intent that has those information. |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 228 | * This is an internal API because only the framework should know the class name. |
| 229 | * |
| 230 | * @hide |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 231 | */ |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 232 | public String getNotificationTargetClassName() { |
| 233 | return mNotificationTargetClassName; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | public int getFlags() { |
| 237 | return mFlags; |
| 238 | } |
| 239 | |
Gilles Debunne | 6435a56 | 2011-08-04 21:22:30 -0700 | [diff] [blame] | 240 | public void setFlags(int flags) { |
| 241 | mFlags = flags; |
| 242 | } |
| 243 | |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 244 | @Override |
| 245 | public int describeContents() { |
| 246 | return 0; |
| 247 | } |
| 248 | |
| 249 | @Override |
| 250 | public void writeToParcel(Parcel dest, int flags) { |
satok | e3797a1 | 2011-03-22 06:34:48 +0900 | [diff] [blame] | 251 | dest.writeStringArray(mSuggestions); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 252 | dest.writeInt(mFlags); |
| 253 | dest.writeString(mLocaleString); |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 254 | dest.writeString(mNotificationTargetClassName); |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 255 | dest.writeString(mNotificationTargetPackageName); |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 256 | dest.writeInt(mHashCode); |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 257 | dest.writeInt(mEasyCorrectUnderlineColor); |
| 258 | dest.writeFloat(mEasyCorrectUnderlineThickness); |
| 259 | dest.writeInt(mMisspelledUnderlineColor); |
| 260 | dest.writeFloat(mMisspelledUnderlineThickness); |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 261 | dest.writeInt(mAutoCorrectionUnderlineColor); |
| 262 | dest.writeFloat(mAutoCorrectionUnderlineThickness); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | @Override |
| 266 | public int getSpanTypeId() { |
Gilles Debunne | a00972a | 2011-04-13 16:07:31 -0700 | [diff] [blame] | 267 | return TextUtils.SUGGESTION_SPAN; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 268 | } |
| 269 | |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 270 | @Override |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 271 | public boolean equals(Object o) { |
| 272 | if (o instanceof SuggestionSpan) { |
| 273 | return ((SuggestionSpan)o).hashCode() == mHashCode; |
| 274 | } |
| 275 | return false; |
| 276 | } |
| 277 | |
| 278 | @Override |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 279 | public int hashCode() { |
| 280 | return mHashCode; |
| 281 | } |
| 282 | |
Gilles Debunne | 6435a56 | 2011-08-04 21:22:30 -0700 | [diff] [blame] | 283 | private static int hashCodeInternal(String[] suggestions, String locale, |
satok | 42c5a16 | 2011-05-26 16:46:14 +0900 | [diff] [blame] | 284 | String notificationTargetClassName) { |
Gilles Debunne | 6435a56 | 2011-08-04 21:22:30 -0700 | [diff] [blame] | 285 | return Arrays.hashCode(new Object[] {Long.valueOf(SystemClock.uptimeMillis()), suggestions, |
| 286 | locale, notificationTargetClassName}); |
satok | f9f0100 | 2011-05-19 21:31:50 +0900 | [diff] [blame] | 287 | } |
| 288 | |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 289 | public static final Parcelable.Creator<SuggestionSpan> CREATOR = |
| 290 | new Parcelable.Creator<SuggestionSpan>() { |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 291 | @Override |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 292 | public SuggestionSpan createFromParcel(Parcel source) { |
| 293 | return new SuggestionSpan(source); |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | @Override |
satok | b3fc1a5 | 2011-04-06 18:28:55 +0900 | [diff] [blame] | 297 | public SuggestionSpan[] newArray(int size) { |
| 298 | return new SuggestionSpan[size]; |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 299 | } |
| 300 | }; |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 301 | |
| 302 | @Override |
| 303 | public void updateDrawState(TextPaint tp) { |
Gilles Debunne | c9fd978 | 2011-09-09 09:20:12 -0700 | [diff] [blame] | 304 | final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0; |
| 305 | final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0; |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 306 | final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0; |
Gilles Debunne | c9fd978 | 2011-09-09 09:20:12 -0700 | [diff] [blame] | 307 | if (easy) { |
| 308 | if (!misspelled) { |
| 309 | tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness); |
| 310 | } else if (tp.underlineColor == 0) { |
| 311 | // Spans are rendered in an arbitrary order. Since misspelled is less prioritary |
| 312 | // than just easy, do not apply misspelled if an easy (or a mispelled) has been set |
| 313 | tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness); |
| 314 | } |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 315 | } else if (autoCorrection) { |
| 316 | tp.setUnderlineText(mAutoCorrectionUnderlineColor, mAutoCorrectionUnderlineThickness); |
Luca Zanolin | fe5e983 | 2011-09-02 19:41:42 +0100 | [diff] [blame] | 317 | } |
Luca Zanolin | 7d1c55f | 2011-08-16 14:59:26 +0100 | [diff] [blame] | 318 | } |
Gilles Debunne | fa4e2d9 | 2011-09-08 18:34:22 -0700 | [diff] [blame] | 319 | |
| 320 | /** |
| 321 | * @return The color of the underline for that span, or 0 if there is no underline |
Gilles Debunne | 5132273 | 2011-09-09 16:46:42 -0700 | [diff] [blame] | 322 | * |
| 323 | * @hide |
Gilles Debunne | fa4e2d9 | 2011-09-08 18:34:22 -0700 | [diff] [blame] | 324 | */ |
| 325 | public int getUnderlineColor() { |
| 326 | // The order here should match what is used in updateDrawState |
Gilles Debunne | c9fd978 | 2011-09-09 09:20:12 -0700 | [diff] [blame] | 327 | final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0; |
| 328 | final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0; |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 329 | final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0; |
Gilles Debunne | c9fd978 | 2011-09-09 09:20:12 -0700 | [diff] [blame] | 330 | if (easy) { |
| 331 | if (!misspelled) { |
| 332 | return mEasyCorrectUnderlineColor; |
| 333 | } else { |
| 334 | return mMisspelledUnderlineColor; |
| 335 | } |
satok | 9ca4b43 | 2011-10-07 15:08:19 +0900 | [diff] [blame] | 336 | } else if (autoCorrection) { |
| 337 | return mAutoCorrectionUnderlineColor; |
Gilles Debunne | c9fd978 | 2011-09-09 09:20:12 -0700 | [diff] [blame] | 338 | } |
Gilles Debunne | fa4e2d9 | 2011-09-08 18:34:22 -0700 | [diff] [blame] | 339 | return 0; |
| 340 | } |
Luca Zanolin | 0c96b81f | 2012-08-29 11:33:12 +0100 | [diff] [blame] | 341 | |
| 342 | /** |
| 343 | * Notifies a suggestion selection. |
| 344 | * |
| 345 | * @hide |
| 346 | */ |
| 347 | public void notifySelection(Context context, String original, int index) { |
| 348 | final Intent intent = new Intent(); |
| 349 | |
| 350 | if (context == null || mNotificationTargetClassName == null) { |
| 351 | return; |
| 352 | } |
| 353 | // Ensures that only a class in the original IME package will receive the |
| 354 | // notification. |
| 355 | if (mSuggestions == null || index < 0 || index >= mSuggestions.length) { |
| 356 | Log.w(TAG, "Unable to notify the suggestion as the index is out of range index=" + index |
| 357 | + " length=" + mSuggestions.length); |
| 358 | return; |
| 359 | } |
| 360 | |
| 361 | // The package name is not mandatory (legacy from JB), and if the package name |
| 362 | // is missing, we try to notify the suggestion through the input method manager. |
| 363 | if (mNotificationTargetPackageName != null) { |
| 364 | intent.setClassName(mNotificationTargetPackageName, mNotificationTargetClassName); |
| 365 | intent.setAction(SuggestionSpan.ACTION_SUGGESTION_PICKED); |
| 366 | intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_BEFORE, original); |
| 367 | intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_AFTER, mSuggestions[index]); |
| 368 | intent.putExtra(SuggestionSpan.SUGGESTION_SPAN_PICKED_HASHCODE, hashCode()); |
| 369 | context.sendBroadcast(intent); |
| 370 | } else { |
| 371 | InputMethodManager imm = InputMethodManager.peekInstance(); |
| 372 | if (imm != null) { |
| 373 | imm.notifySuggestionPicked(this, original, index); |
| 374 | } |
| 375 | } |
| 376 | } |
satok | adb4358 | 2011-03-09 10:08:47 +0900 | [diff] [blame] | 377 | } |