1 /*
2  * Copyright 2024 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 androidx.pdf.data;
18 
19 import android.annotation.SuppressLint;
20 import android.os.Build;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 
24 import androidx.annotation.RequiresApi;
25 import androidx.annotation.RestrictTo;
26 import androidx.pdf.models.SelectionBoundary;
27 
28 import org.jspecify.annotations.NonNull;
29 
30 import java.util.Objects;
31 
32 /** Represents the selection of part of a piece of text - a start and a stop. */
33 @RestrictTo(RestrictTo.Scope.LIBRARY)
34 public class TextSelection implements Parcelable {
35 
36     public static final TextSelection EMPTY_SELECTION = new TextSelection(
37             SelectionBoundary.PAGE_START, SelectionBoundary.PAGE_START);
38 
39     public static final Creator<TextSelection> CREATOR = new Creator<TextSelection>() {
40         @SuppressLint("ObsoleteSdkInt") //TODO: Remove after sdk extension 13 release
41         @Override
42         public TextSelection createFromParcel(Parcel parcel) {
43             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
44                 return Api33Impl.createFromParcel(parcel);
45             } else {
46                 return ApiPre33Impl.createFromParcel(parcel);
47             }
48         }
49 
50         @Override
51         public TextSelection[] newArray(int size) {
52             return new TextSelection[size];
53         }
54     };
55 
56     /** The start of the selection - index is inclusive. */
57     private final SelectionBoundary mStart;
58 
59     /** The end of the selection - index is exclusive. */
60     private final SelectionBoundary mStop;
61 
TextSelection(@onNull SelectionBoundary start, @NonNull SelectionBoundary stop)62     public TextSelection(@NonNull SelectionBoundary start, @NonNull SelectionBoundary stop) {
63         this.mStart = start;
64         this.mStop = stop;
65     }
66 
getStart()67     public @NonNull SelectionBoundary getStart() {
68         return mStart;
69     }
70 
getStop()71     public @NonNull SelectionBoundary getStop() {
72         return mStop;
73     }
74 
75     @Override
toString()76     public @NonNull String toString() {
77         return String.format("TextSelection(start=%s, stop=%s)", mStart, mStop);
78     }
79 
80     @SuppressLint("ObsoleteSdkInt") //TODO: Remove after sdk extension 13 release
81     @Override
writeToParcel(@onNull Parcel parcel, int flags)82     public void writeToParcel(@NonNull Parcel parcel, int flags) {
83         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
84             Api33Impl.writeToParcel(this, parcel, flags);
85         } else {
86             ApiPre33Impl.writeToParcel(this, parcel, flags);
87         }
88     }
89 
90     @Override
describeContents()91     public int describeContents() {
92         return 0;
93     }
94 
95     @SuppressLint("ObsoleteSdkInt") //TODO: Remove after sdk extension 13 release
96     @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) // API 33
97     private static final class Api33Impl {
98 
Api33Impl()99         private Api33Impl() {
100         } // Prevent instantiation
101 
createFromParcel(Parcel parcel)102         public static TextSelection createFromParcel(Parcel parcel) {
103             SelectionBoundary start = parcel.readParcelable(
104                     SelectionBoundary.class.getClassLoader(), SelectionBoundary.class);
105             SelectionBoundary stop = parcel.readParcelable(
106                     SelectionBoundary.class.getClassLoader(), SelectionBoundary.class);
107 
108             Objects.requireNonNull(start, "Start SelectionBoundary cannot be null");
109             Objects.requireNonNull(stop, "Stop SelectionBoundary cannot be null");
110 
111             return new TextSelection(start, stop);
112         }
113 
writeToParcel( TextSelection selection, @NonNull Parcel parcel, int flags )114         public static void writeToParcel(
115                 TextSelection selection,
116                 @NonNull Parcel parcel,
117                 int flags
118         ) {
119             parcel.writeParcelable(selection.mStart, flags);
120             parcel.writeParcelable(selection.mStop, flags);
121         }
122     }
123 
124     private static final class ApiPre33Impl {
125 
ApiPre33Impl()126         private ApiPre33Impl() {
127         } // Prevent instantiation
128 
createFromParcel(Parcel parcel)129         public static TextSelection createFromParcel(Parcel parcel) {
130             SelectionBoundary start = SelectionBoundary.CREATOR.createFromParcel(parcel);
131             SelectionBoundary stop = SelectionBoundary.CREATOR.createFromParcel(parcel);
132 
133             Objects.requireNonNull(start, "Start SelectionBoundary cannot be null");
134             Objects.requireNonNull(stop, "Stop SelectionBoundary cannot be null");
135 
136             return new TextSelection(start, stop);
137         }
138 
writeToParcel( TextSelection selection, @NonNull Parcel parcel, int flags )139         public static void writeToParcel(
140                 TextSelection selection,
141                 @NonNull Parcel parcel,
142                 int flags
143         ) {
144             selection.mStart.writeToParcel(parcel, flags);
145             selection.mStop.writeToParcel(parcel, flags);
146         }
147     }
148 }
149