1 /* 2 * Copyright (C) 2022 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.view.inputmethod; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SuppressLint; 22 import android.graphics.RectF; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.widget.TextView; 26 27 import java.util.Objects; 28 29 /** 30 * A sub-class of {@link HandwritingGesture} for selecting an area of text using single rectangle. 31 * This class holds the information required for selection of text in 32 * toolkit widgets like {@link TextView}. 33 * <p>Note: This selects all text <em>within</em> the given area. To select a range <em>between</em> 34 * two areas, use {@link SelectRangeGesture}.</p> 35 */ 36 public final class SelectGesture extends PreviewableHandwritingGesture implements Parcelable { 37 38 private @Granularity int mGranularity; 39 private RectF mArea; 40 SelectGesture(int granularity, RectF area, String fallbackText)41 private SelectGesture(int granularity, RectF area, String fallbackText) { 42 mType = GESTURE_TYPE_SELECT; 43 mArea = area; 44 mGranularity = granularity; 45 mFallbackText = fallbackText; 46 } 47 SelectGesture(@onNull Parcel source)48 private SelectGesture(@NonNull Parcel source) { 49 mType = GESTURE_TYPE_SELECT; 50 mFallbackText = source.readString8(); 51 mGranularity = source.readInt(); 52 mArea = source.readTypedObject(RectF.CREATOR); 53 } 54 55 /** 56 * Returns Granular level on which text should be operated. 57 * @see #GRANULARITY_CHARACTER 58 * @see #GRANULARITY_WORD 59 */ 60 @Granularity getGranularity()61 public int getGranularity() { 62 return mGranularity; 63 } 64 65 /** 66 * Returns the Selection area {@link RectF} in screen coordinates. 67 * 68 * Getter for selection area set with {@link Builder#setSelectionArea(RectF)}. 69 */ 70 @NonNull getSelectionArea()71 public RectF getSelectionArea() { 72 return mArea; 73 } 74 75 /** 76 * Builder for {@link SelectGesture}. This class is not designed to be thread-safe. 77 */ 78 public static final class Builder { 79 private int mGranularity; 80 private RectF mArea; 81 private String mFallbackText; 82 83 /** 84 * Define text selection granularity. Intersecting words/characters will be 85 * included in the operation. 86 * @param granularity {@link HandwritingGesture#GRANULARITY_WORD} or 87 * {@link HandwritingGesture#GRANULARITY_CHARACTER}. 88 * @return {@link Builder}. 89 */ 90 @NonNull 91 @SuppressLint("MissingGetterMatchingBuilder") setGranularity(@ranularity int granularity)92 public Builder setGranularity(@Granularity int granularity) { 93 mGranularity = granularity; 94 return this; 95 } 96 97 /** 98 * Set rectangular single/multiline text selection area intersecting with text. 99 * 100 * The resulting selection would be performed for all text intersecting rectangle. The 101 * selection includes the first word/character in the rectangle, and the last 102 * word/character in the rectangle, and includes everything in between even if it's not 103 * in the rectangle. 104 * 105 * Intersection is determined using 106 * {@link #setGranularity(int)}. e.g. {@link HandwritingGesture#GRANULARITY_WORD} includes 107 * all the words with their width/height center included in the selection rectangle. 108 * @param area {@link RectF} (in screen coordinates) for which text will be selection. 109 */ 110 @NonNull 111 @SuppressLint("MissingGetterMatchingBuilder") setSelectionArea(@onNull RectF area)112 public Builder setSelectionArea(@NonNull RectF area) { 113 mArea = area; 114 return this; 115 } 116 117 /** 118 * Set fallback text that will be committed at current cursor position if there is no 119 * applicable text beneath the area of gesture. 120 * @param fallbackText text to set 121 */ 122 @NonNull setFallbackText(@ullable String fallbackText)123 public Builder setFallbackText(@Nullable String fallbackText) { 124 mFallbackText = fallbackText; 125 return this; 126 } 127 128 /** 129 * @return {@link SelectGesture} using parameters in this {@link Builder}. 130 * @throws IllegalArgumentException if one or more positional parameters are not specified. 131 */ 132 @NonNull build()133 public SelectGesture build() { 134 if (mArea == null || mArea.isEmpty()) { 135 throw new IllegalArgumentException("Selection area must be set."); 136 } 137 if (mGranularity <= GRANULARITY_UNDEFINED) { 138 throw new IllegalArgumentException("Selection granularity must be set."); 139 } 140 return new SelectGesture(mGranularity, mArea, mFallbackText); 141 } 142 } 143 144 /** 145 * Used to make this class parcelable. 146 */ 147 @NonNull 148 public static final Parcelable.Creator<SelectGesture> CREATOR = 149 new Parcelable.Creator<SelectGesture>() { 150 @Override 151 public SelectGesture createFromParcel(Parcel source) { 152 return new SelectGesture(source); 153 } 154 155 @Override 156 public SelectGesture[] newArray(int size) { 157 return new SelectGesture[size]; 158 } 159 }; 160 161 @Override hashCode()162 public int hashCode() { 163 return Objects.hash(mGranularity, mArea, mFallbackText); 164 } 165 166 @Override equals(Object o)167 public boolean equals(Object o) { 168 if (!(o instanceof SelectGesture)) return false; 169 170 SelectGesture that = (SelectGesture) o; 171 172 if (mGranularity != that.mGranularity) return false; 173 if (!Objects.equals(mFallbackText, that.mFallbackText)) return false; 174 return Objects.equals(mArea, that.mArea); 175 } 176 177 @Override describeContents()178 public int describeContents() { 179 return 0; 180 } 181 182 /** 183 * Used to package this object into a {@link Parcel}. 184 * 185 * @param dest The {@link Parcel} to be written. 186 * @param flags The flags used for parceling. 187 */ 188 @Override writeToParcel(@onNull Parcel dest, int flags)189 public void writeToParcel(@NonNull Parcel dest, int flags) { 190 dest.writeString8(mFallbackText); 191 dest.writeInt(mGranularity); 192 dest.writeTypedObject(mArea, flags); 193 } 194 } 195