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.SuppressLint; 21 import android.graphics.PointF; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.widget.TextView; 25 26 import androidx.annotation.Nullable; 27 28 import java.util.Objects; 29 30 /** 31 * A sub-class of {@link HandwritingGesture} for inserting text at the defined insertion point. 32 * This class holds the information required for insertion of text in 33 * toolkit widgets like {@link TextView}. 34 */ 35 public final class InsertGesture extends HandwritingGesture implements Parcelable { 36 37 private String mTextToInsert; 38 private PointF mPoint; 39 InsertGesture(String text, PointF point, String fallbackText)40 private InsertGesture(String text, PointF point, String fallbackText) { 41 mType = GESTURE_TYPE_INSERT; 42 mPoint = point; 43 mTextToInsert = text; 44 mFallbackText = fallbackText; 45 } 46 InsertGesture(final Parcel source)47 private InsertGesture(final Parcel source) { 48 mType = GESTURE_TYPE_INSERT; 49 mFallbackText = source.readString8(); 50 mTextToInsert = source.readString8(); 51 mPoint = source.readTypedObject(PointF.CREATOR); 52 } 53 54 /** Returns the text that will be inserted at {@link #getInsertionPoint()}. When text is 55 * empty, cursor should be moved the insertion point. **/ 56 @NonNull getTextToInsert()57 public String getTextToInsert() { 58 return mTextToInsert; 59 } 60 61 /** 62 * Returns the insertion point {@link PointF} (in screen coordinates) where 63 * {@link #getTextToInsert()} will be inserted. 64 */ 65 @NonNull getInsertionPoint()66 public PointF getInsertionPoint() { 67 return mPoint; 68 } 69 70 /** 71 * Builder for {@link InsertGesture}. This class is not designed to be thread-safe. 72 */ 73 public static final class Builder { 74 private String mText; 75 private PointF mPoint; 76 private String mFallbackText; 77 78 /** 79 * Set the text that will be inserted at {@link #setInsertionPoint(PointF)}. When set with 80 * an empty string, cursor will be moved to {@link #getInsertionPoint()} and no text 81 * would be inserted. 82 */ 83 @NonNull 84 @SuppressLint("MissingGetterMatchingBuilder") setTextToInsert(@onNull String text)85 public Builder setTextToInsert(@NonNull String text) { 86 mText = text; 87 return this; 88 } 89 90 /** 91 * Sets the insertion point (in screen coordinates) where {@link #setTextToInsert(String)} 92 * should be inserted. 93 */ 94 @NonNull 95 @SuppressLint("MissingGetterMatchingBuilder") setInsertionPoint(@onNull PointF point)96 public Builder setInsertionPoint(@NonNull PointF point) { 97 mPoint = point; 98 return this; 99 } 100 101 /** 102 * Set fallback text that will be committed at current cursor position if there is no 103 * applicable text beneath the area of gesture. 104 * @param fallbackText text to set 105 */ 106 @NonNull setFallbackText(@ullable String fallbackText)107 public Builder setFallbackText(@Nullable String fallbackText) { 108 mFallbackText = fallbackText; 109 return this; 110 } 111 112 /** 113 * @return {@link InsertGesture} using parameters in this {@link InsertGesture.Builder}. 114 * @throws IllegalArgumentException if one or more positional parameters are not specified. 115 */ 116 @NonNull build()117 public InsertGesture build() { 118 if (mPoint == null) { 119 throw new IllegalArgumentException("Insertion point must be set."); 120 } 121 if (mText == null) { 122 throw new IllegalArgumentException("Text to insert must be set."); 123 } 124 return new InsertGesture(mText, mPoint, mFallbackText); 125 } 126 } 127 128 /** 129 * Used to make this class parcelable. 130 */ 131 @NonNull 132 public static final Creator<InsertGesture> CREATOR = 133 new Creator<InsertGesture>() { 134 @Override 135 public InsertGesture createFromParcel(Parcel source) { 136 return new InsertGesture(source); 137 } 138 139 @Override 140 public InsertGesture[] newArray(int size) { 141 return new InsertGesture[size]; 142 } 143 }; 144 145 @Override hashCode()146 public int hashCode() { 147 return Objects.hash(mPoint, mTextToInsert, mFallbackText); 148 } 149 150 @Override equals(Object o)151 public boolean equals(Object o) { 152 if (this == o) return true; 153 if (!(o instanceof InsertGesture)) return false; 154 155 InsertGesture that = (InsertGesture) o; 156 157 if (!Objects.equals(mFallbackText, that.mFallbackText)) return false; 158 if (!Objects.equals(mTextToInsert, that.mTextToInsert)) return false; 159 return Objects.equals(mPoint, that.mPoint); 160 } 161 162 @Override describeContents()163 public int describeContents() { 164 return 0; 165 } 166 167 /** 168 * Used to package this object into a {@link Parcel}. 169 * 170 * @param dest The {@link Parcel} to be written. 171 * @param flags The flags used for parceling. 172 */ 173 @Override writeToParcel(@onNull Parcel dest, int flags)174 public void writeToParcel(@NonNull Parcel dest, int flags) { 175 dest.writeString8(mFallbackText); 176 dest.writeString8(mTextToInsert); 177 dest.writeTypedObject(mPoint, flags); 178 } 179 } 180