1 /*
2  * Copyright 2023 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.appsearch.builtintypes;
18 
19 import static androidx.core.util.Preconditions.checkNotNull;
20 
21 import androidx.annotation.OptIn;
22 import androidx.appsearch.annotation.Document;
23 import androidx.appsearch.app.ExperimentalAppSearchApi;
24 import androidx.appsearch.builtintypes.properties.Keyword;
25 
26 import org.jspecify.annotations.NonNull;
27 import org.jspecify.annotations.Nullable;
28 
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.Objects;
33 
34 /**
35  * Represents an image file.
36  *
37  * <p>See <a href="http://schema.org/ImageObject">http://schema.org/ImageObject</a> for more
38  * context.
39  */
40 @Document(name = "builtin:ImageObject")
41 public final class ImageObject extends Thing {
42 
43     @Document.DocumentProperty(name = "keywords", indexNestedProperties = true)
44     private final @NonNull List<Keyword> mKeywords;
45 
46     @Document.StringProperty
47     private final @Nullable String mSha256;
48 
49     @Document.StringProperty
50     private final @Nullable String mThumbnailSha256;
51 
52     @Document.BytesProperty
53     private final byte @Nullable [] mBytes;
54 
55     @OptIn(markerClass = ExperimentalAppSearchApi.class)
ImageObject(@onNull String namespace, @NonNull String id, int documentScore, long creationTimestampMillis, long documentTtlMillis, @Nullable String name, @Nullable List<String> alternateNames, @Nullable String description, @Nullable String image, @Nullable String url, @NonNull List<PotentialAction> potentialActions, @NonNull List<Keyword> keywords, @Nullable String sha256, @Nullable String thumbnailSha256, byte @Nullable [] bytes)56     ImageObject(@NonNull String namespace, @NonNull String id, int documentScore,
57             long creationTimestampMillis, long documentTtlMillis, @Nullable String name,
58             @Nullable List<String> alternateNames, @Nullable String description,
59             @Nullable String image, @Nullable String url,
60             @NonNull List<PotentialAction> potentialActions,
61             @NonNull List<Keyword> keywords,
62             @Nullable String sha256, @Nullable String thumbnailSha256, byte @Nullable [] bytes) {
63         super(namespace, id, documentScore, creationTimestampMillis, documentTtlMillis, name,
64                 alternateNames, description, image, url, potentialActions);
65         mKeywords = checkNotNull(keywords);
66         mSha256 = sha256;
67         mThumbnailSha256 = thumbnailSha256;
68         mBytes = bytes;
69     }
70 
71     /**
72      * Keywords or tags used to describe some item.
73      *
74      * <p>See <a href="http://schema.org/keywords">http://schema.org/keywords</a> for more context.
75      */
getKeywords()76     public @NonNull List<Keyword> getKeywords() {
77         return mKeywords;
78     }
79 
80     /**
81      * The SHA-2 SHA256 hash of the content of the item.
82      * For example, a zero-length input has value
83      * 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'.
84      *
85      * <p>See <a href="http://schema.org/sha256">http://schema.org/sha256</a> for more context.
86      */
getSha256()87     public @Nullable String getSha256() {
88         return mSha256;
89     }
90 
91     /**
92      * Returns the {@code sha256} for the thumbnail of this image or video.
93      */
getThumbnailSha256()94     public @Nullable String getThumbnailSha256() {
95         return mThumbnailSha256;
96     }
97 
98     /**
99      * Returns the byte representation of this image or video.
100      * Can be a compressed bitmap (e.g. JPEG or PNG).
101      */
getBytes()102     public byte @Nullable [] getBytes() {
103         return mBytes;
104     }
105 
106     @Override
equals(Object o)107     public boolean equals(Object o) {
108         if (this == o) return true;
109         if (o == null || getClass() != o.getClass()) return false;
110         ImageObject that = (ImageObject) o;
111         return mKeywords.equals(that.mKeywords) && Objects.equals(mSha256, that.mSha256)
112                 && Objects.equals(mThumbnailSha256, that.mThumbnailSha256)
113                 && Arrays.equals(mBytes, that.mBytes);
114     }
115 
116     @Override
hashCode()117     public int hashCode() {
118         return Objects.hash(mKeywords, mSha256, mThumbnailSha256, Arrays.hashCode(mBytes));
119     }
120 
121     /**
122      * Builder for {@link ImageObject}.
123      */
124     public static final class Builder extends BuilderImpl<Builder> {
125         /**
126          * Constructor for an empty {@link Builder}.
127          *
128          * @param namespace Namespace for the Document. See
129          *                  {@link Document.Namespace}.
130          * @param id        Unique identifier for the Document. See {@link Document.Id}.
131          */
Builder(@onNull String namespace, @NonNull String id)132         public Builder(@NonNull String namespace, @NonNull String id) {
133             super(namespace, id);
134         }
135 
136         /**
137          * Copy constructor.
138          */
Builder(@onNull ImageObject copyFrom)139         public Builder(@NonNull ImageObject copyFrom) {
140             super(copyFrom);
141         }
142     }
143 
144     @SuppressWarnings("unchecked")
145     static class BuilderImpl<Self extends BuilderImpl<Self>> extends Thing.BuilderImpl<Self> {
146         protected final @NonNull List<Keyword> mKeywords;
147 
148         protected @Nullable String mSha256;
149 
150         protected @Nullable String mThumbnailSha256;
151 
152         protected byte @Nullable [] mBytes;
153 
BuilderImpl(@onNull String namespace, @NonNull String id)154         BuilderImpl(@NonNull String namespace, @NonNull String id) {
155             super(namespace, id);
156             mKeywords = new ArrayList<>();
157             mSha256 = null;
158             mThumbnailSha256 = null;
159             mBytes = null;
160         }
161 
BuilderImpl(@onNull ImageObject copyFrom)162         BuilderImpl(@NonNull ImageObject copyFrom) {
163             super(new Thing.Builder(checkNotNull(copyFrom)).build());
164             mKeywords = new ArrayList<>(copyFrom.getKeywords());
165             mSha256 = copyFrom.getSha256();
166             mThumbnailSha256 = copyFrom.getThumbnailSha256();
167             mBytes = copyFrom.getBytes();
168         }
169 
170         @Override
build()171         public @NonNull ImageObject build() {
172             return new ImageObject(mNamespace, mId, mDocumentScore, mCreationTimestampMillis,
173                     mDocumentTtlMillis, mName, mAlternateNames, mDescription, mImage, mUrl,
174                     mPotentialActions, new ArrayList<>(mKeywords), mSha256, mThumbnailSha256,
175                     mBytes);
176         }
177 
178         /**
179          * Appends the {@link Keyword} as a Text i.e. {@link String}.
180          */
181         // Atypical overloads in the Builder to model union types.
182         @SuppressWarnings("MissingGetterMatchingBuilder")
addKeyword(@onNull String text)183         public @NonNull Self addKeyword(@NonNull String text) {
184             mKeywords.add(new Keyword(checkNotNull(text)));
185             return (Self) this;
186         }
187 
188         /**
189          * Appends the {@link Keyword}.
190          */
addKeyword(@onNull Keyword keyword)191         public @NonNull Self addKeyword(@NonNull Keyword keyword) {
192             mKeywords.add(checkNotNull(keyword));
193             return (Self) this;
194         }
195 
196         /**
197          * Appends all the {@code values}.
198          */
addKeywords(@onNull Iterable<Keyword> values)199         public @NonNull Self addKeywords(@NonNull Iterable<Keyword> values) {
200             for (Keyword value : checkNotNull(values)) {
201                 mKeywords.add(checkNotNull(value));
202             }
203             return (Self) this;
204         }
205 
206         /**
207          * Sets the {@code sha256}.
208          */
setSha256(@ullable String text)209         public @NonNull Self setSha256(@Nullable String text) {
210             mSha256 = text;
211             return (Self) this;
212         }
213 
214         /**
215          * Sets the {@code sha256} of the thumbnail of this image of video.
216          */
setThumbnailSha256(@ullable String text)217         public @NonNull Self setThumbnailSha256(@Nullable String text) {
218             mThumbnailSha256 = text;
219             return (Self) this;
220         }
221 
222         /**
223          * Sets the byte representation of this image or video.
224          */
setBytes(byte @Nullable [] bytes)225         public @NonNull Self setBytes(byte @Nullable [] bytes) {
226             mBytes = bytes;
227             return (Self) this;
228         }
229     }
230 }
231