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