/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.appsearch.builtintypes;
import android.content.Intent;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appsearch.annotation.Document;
import androidx.appsearch.app.AppSearchSchema.StringPropertyConfig;
import androidx.core.util.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* AppSearch document representing a <a href="http://schema.org/Thing">Thing</a>, the most generic
* type of an item.
*/
@Document(name = "builtin:Thing")
public class Thing {
@Document.Namespace
private final String mNamespace;
@Document.Id
private final String mId;
@Document.Score
private final int mDocumentScore;
@Document.CreationTimestampMillis
private final long mCreationTimestampMillis;
@Document.TtlMillis
private final long mDocumentTtlMillis;
@Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES)
private final String mName;
@Document.StringProperty
private final List<String> mAlternateNames;
@Document.StringProperty
private final String mDescription;
@Document.StringProperty
private final String mImage;
@Document.StringProperty
private final String mUrl;
Thing(@NonNull 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) {
mNamespace = Preconditions.checkNotNull(namespace);
mId = Preconditions.checkNotNull(id);
mDocumentScore = documentScore;
mCreationTimestampMillis = creationTimestampMillis;
mDocumentTtlMillis = documentTtlMillis;
mName = name;
// If an old schema does not define the alternateNames field, AppSearch may attempt to
// pass in null when converting its GenericDocument to the java class.
if (alternateNames == null) {
mAlternateNames = Collections.emptyList();
} else {
mAlternateNames = Collections.unmodifiableList(alternateNames);
}
mDescription = description;
mImage = image;
mUrl = url;
}
/** Returns the namespace (or logical grouping) for this item. */
@NonNull
public String getNamespace() {
return mNamespace;
}
/** Returns the unique identifier for this item. */
@NonNull
public String getId() {
return mId;
}
/** Returns the intrinsic score (or importance) of this item. */
public int getDocumentScore() {
return mDocumentScore;
}
/** Returns the creation timestamp, in milliseconds since Unix epoch, of this item. */
public long getCreationTimestampMillis() {
return mCreationTimestampMillis;
}
/**
* Returns the time-to-live timestamp, in milliseconds since
* {@link #getCreationTimestampMillis()}, for this item.
*/
public long getDocumentTtlMillis() {
return mDocumentTtlMillis;
}
/** Returns the name of this item. */
@Nullable
public String getName() {
return mName;
}
/** Returns an unmodifiable list of aliases, if any, for this item. */
@NonNull
public List<String> getAlternateNames() {
return mAlternateNames;
}
/** Returns a description of this item. */
@Nullable
public String getDescription() {
return mDescription;
}
/** Returns the URL for an image of this item. */
@Nullable
public String getImage() {
return mImage;
}
/**
* Returns the deeplink URL of this item.
*
* <p>This item can be opened (or viewed) by creating an {@link Intent#ACTION_VIEW} intent
* with this URL as the {@link Intent#setData(Uri)} uri.
*
* @see <a href="//reference/android/content/Intent#intent-structure">Intent Structure</a>
*/
@Nullable
public String getUrl() {
return mUrl;
}
/** Builder for {@link Thing}. */
public static final class Builder extends BuilderImpl<Builder> {
/** Constructs {@link Thing.Builder} with given {@code namespace} and {@code id} */
public Builder(@NonNull String namespace, @NonNull String id) {
super(namespace, id);
}
/** Constructs {@link Thing.Builder} from existing values in given {@link Thing}. */
public Builder(@NonNull Thing thing) {
super(thing);
}
}
@SuppressWarnings("unchecked")
// TODO: currently this can only be extends by classes in this package. Make this publicly
// extensible.
static class BuilderImpl<T extends BuilderImpl<T>> {
protected final String mNamespace;
protected final String mId;
protected int mDocumentScore;
protected long mCreationTimestampMillis;
protected long mDocumentTtlMillis;
protected String mName;
protected List<String> mAlternateNames = new ArrayList<>();
protected String mDescription;
protected String mImage;
protected String mUrl;
BuilderImpl(@NonNull String namespace, @NonNull String id) {
mNamespace = Preconditions.checkNotNull(namespace);
mId = Preconditions.checkNotNull(id);
// Default for unset creationTimestampMillis. AppSearch will internally convert this
// to current time when creating the GenericDocument.
mCreationTimestampMillis = -1;
}
BuilderImpl(@NonNull Thing thing) {
this(thing.getNamespace(), thing.getId());
mDocumentScore = thing.getDocumentScore();
mCreationTimestampMillis = thing.getCreationTimestampMillis();
mDocumentTtlMillis = thing.getDocumentTtlMillis();
mName = thing.getName();
mAlternateNames = new ArrayList<>(thing.getAlternateNames());
mDescription = thing.getDescription();
mImage = thing.getImage();
mUrl = thing.getUrl();
}
/**
* Sets the user-provided opaque document score of the current AppSearch document, which can
* be used for ranking using
* {@link androidx.appsearch.app.SearchSpec.RankingStrategy#RANKING_STRATEGY_DOCUMENT_SCORE}.
*
* <p>See {@link androidx.appsearch.annotation.Document.Score} for more information on
* score.
*/
@NonNull
@SuppressWarnings("unchecked")
public T setDocumentScore(int documentScore) {
mDocumentScore = documentScore;
return (T) this;
}
/**
* Sets the creation timestamp for the current AppSearch entity, in milliseconds using the
* {@link System#currentTimeMillis()} time base.
*
* <p>This timestamp refers to the creation time of the AppSearch entity, not when the
* document is written into AppSearch.
*
* <p>If not set, then the current timestamp will be used.
*
* <p>See {@link androidx.appsearch.annotation.Document.CreationTimestampMillis} for more
* information on creation timestamp.
*/
@NonNull
@SuppressWarnings("unchecked")
public T setCreationTimestampMillis(long creationTimestampMillis) {
mCreationTimestampMillis = creationTimestampMillis;
return (T) this;
}
/**
* Sets the time-to-live (TTL) for the current AppSearch document as a duration in
* milliseconds.
*
* <p>The document will be automatically deleted when the TTL expires.
*
* <p>If not set, then the document will never expire.
*
* <p>See {@link androidx.appsearch.annotation.Document.TtlMillis} for more information on
* TTL.
*/
@NonNull
@SuppressWarnings("unchecked")
public T setDocumentTtlMillis(long documentTtlMillis) {
mDocumentTtlMillis = documentTtlMillis;
return (T) this;
}
/** Sets the name of the item. */
@NonNull
public T setName(@Nullable String name) {
mName = name;
return (T) this;
}
/** Adds an alias for the item. */
@NonNull
public T addAlternateName(@NonNull String alternateName) {
Preconditions.checkNotNull(alternateName);
mAlternateNames.add(alternateName);
return (T) this;
}
/** Clears the aliases, if any, for the item. */
@NonNull
public T clearAlternateNames() {
mAlternateNames.clear();
return (T) this;
}
/** Sets the description for the item. */
@NonNull
public T setDescription(@Nullable String description) {
mDescription = description;
return (T) this;
}
/** Sets the URL for an image of the item. */
@NonNull
public T setImage(@Nullable String image) {
mImage = image;
return (T) this;
}
/**
* Sets the deeplink URL of the item.
*
* <p>If this item can be displayed by any system UI surface, or can be read by another
* Android package, through one of the
* {@link androidx.appsearch.app.SetSchemaRequest.Builder} methods, this {@code url}
* should act as a deeplink into the activity that can open it. Callers should be able to
* construct an {@link Intent#ACTION_VIEW} intent with the {@code url} as the
* {@link Intent#setData(Uri)} to view the item inside your application.
*
* <p>See <a href="//training/basics/intents/filters">Allowing Other Apps to Start Your
* Activity</a> for more details on how to make activities in your app open for use by other
* apps by defining intent filters.
*/
@NonNull
public T setUrl(@Nullable String url) {
mUrl = url;
return (T) this;
}
/** Builds a {@link Thing} object. */
@NonNull
public Thing build() {
return new Thing(mNamespace, mId, mDocumentScore, mCreationTimestampMillis,
mDocumentTtlMillis, mName, mAlternateNames, mDescription, mImage, mUrl);
}
}
}