blob: 3fc7f47c01f194e4098eb853ecfd0e96e2b41e82 [file] [log] [blame]
/*
* Copyright (C) 2017 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.tvprovider.media.tv;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Build;
import androidx.annotation.IntDef;
import androidx.annotation.RestrictTo;
import androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
import java.util.Set;
/**
* A convenience class to access {@link WatchNextPrograms} entries in the system content
* provider.
*
* <p>This class makes it easy to insert or retrieve a program from the system content provider,
* which is defined in {@link TvContractCompat}.
*
* <p>Usage example when inserting a "watch next" program:
* <pre>
* WatchNextProgram watchNextProgram = new WatchNextProgram.Builder()
* .setWatchNextType(WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
* .setType(PreviewPrograms.TYPE_MOVIE)
* .setTitle("Program Title")
* .setDescription("Program Description")
* .setPosterArtUri(Uri.parse("http://example.com/poster_art.png"))
* // Set more attributes...
* .build();
* Uri watchNextProgramUri = getContentResolver().insert(WatchNextPrograms.CONTENT_URI,
* watchNextProgram.toContentValues());
* </pre>
*
* <p>Usage example when retrieving a "watch next" program:
* <pre>
* WatchNextProgram watchNextProgram;
* try (Cursor cursor = resolver.query(watchNextProgramUri, null, null, null, null)) {
* if (cursor != null && cursor.getCount() != 0) {
* cursor.moveToNext();
* watchNextProgram = WatchNextProgram.fromCursor(cursor);
* }
* }
* </pre>
*
* <p>Usage example when updating an existing "watch next" program:
* <pre>
* WatchNextProgram updatedProgram = new WatchNextProgram.Builder(watchNextProgram)
* .setLastEngagementTimeUtcMillis(System.currentTimeMillis())
* .build();
* getContentResolver().update(TvContractCompat.buildWatchNextProgramUri(updatedProgram.getId()),
* updatedProgram.toContentValues(), null, null);
* </pre>
*
* <p>Usage example when deleting a "watch next" program:
* <pre>
* getContentResolver().delete(TvContractCompat.buildWatchNextProgramUri(existingProgram.getId()),
* null, null);
* </pre>
*/
public final class WatchNextProgram extends BasePreviewProgram {
/**
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
public static final String[] PROJECTION = getProjection();
private static final long INVALID_LONG_VALUE = -1;
private static final int INVALID_INT_VALUE = -1;
/** @hide */
@IntDef({
WATCH_NEXT_TYPE_UNKNOWN,
WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE,
WatchNextPrograms.WATCH_NEXT_TYPE_NEXT,
WatchNextPrograms.WATCH_NEXT_TYPE_NEW,
WatchNextPrograms.WATCH_NEXT_TYPE_WATCHLIST,
})
@Retention(RetentionPolicy.SOURCE)
@RestrictTo(LIBRARY_GROUP)
public @interface WatchNextType {
}
/**
* The unknown watch next type. Use this type when the actual type is not known.
*/
public static final int WATCH_NEXT_TYPE_UNKNOWN = -1;
private WatchNextProgram(Builder builder) {
super(builder);
}
/**
* @return The value of {@link WatchNextPrograms#COLUMN_WATCH_NEXT_TYPE} for the program,
* or {@link #WATCH_NEXT_TYPE_UNKNOWN} if it's unknown.
*/
public @WatchNextType int getWatchNextType() {
Integer i = mValues.getAsInteger(WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE);
return i == null ? WATCH_NEXT_TYPE_UNKNOWN : i;
}
/**
* @return The value of {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS} for the
* program.
*/
public long getLastEngagementTimeUtcMillis() {
Long l = mValues.getAsLong(WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS);
return l == null ? INVALID_LONG_VALUE : l;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof WatchNextProgram)) {
return false;
}
return mValues.equals(((WatchNextProgram) other).mValues);
}
/**
* Indicates whether some other WatchNextProgram has any set attribute that is different from
* this WatchNextProgram's respective attributes. An attribute is considered "set" if its key
* is present in the ContentValues vector.
*/
public boolean hasAnyUpdatedValues(WatchNextProgram update) {
Set<String> updateKeys = update.mValues.keySet();
for (String key : updateKeys) {
Object updateValue = update.mValues.get(key);
Object currValue = mValues.get(key);
if (!Objects.deepEquals(updateValue, currValue)) {
return true;
}
}
return false;
}
@Override
public String toString() {
return "WatchNextProgram{" + mValues.toString() + "}";
}
/**
* @return The fields of the Program in the ContentValues format to be easily inserted into the
* TV Input Framework database.
*/
@Override
public ContentValues toContentValues() {
return toContentValues(false);
}
/**
* Returns fields of the WatchNextProgram in the ContentValues format to be easily inserted
* into the TV Input Framework database.
*
* @param includeProtectedFields Whether the fields protected by system is included or not.
* @hide
*/
@RestrictTo(LIBRARY_GROUP)
@Override
public ContentValues toContentValues(boolean includeProtectedFields) {
ContentValues values = super.toContentValues(includeProtectedFields);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
values.remove(WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE);
values.remove(WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS);
}
return values;
}
/**
* Creates a WatchNextProgram object from a cursor including the fields defined in
* {@link WatchNextPrograms}.
*
* @param cursor A row from the TV Input Framework database.
* @return A Program with the values taken from the cursor.
*/
public static WatchNextProgram fromCursor(Cursor cursor) {
// TODO: Add additional API which does not use costly getColumnIndex().
Builder builder = new Builder();
BasePreviewProgram.setFieldsFromCursor(cursor, builder);
int index;
if ((index = cursor.getColumnIndex(WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE)) >= 0
&& !cursor.isNull(index)) {
builder.setWatchNextType(cursor.getInt(index));
}
if ((index = cursor.getColumnIndex(
WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS)) >= 0
&& !cursor.isNull(index)) {
builder.setLastEngagementTimeUtcMillis(cursor.getLong(index));
}
return builder.build();
}
private static String[] getProjection() {
String[] oColumns = new String[]{
WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE,
WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
};
return CollectionUtils.concatAll(BasePreviewProgram.PROJECTION, oColumns);
}
/**
* This Builder class simplifies the creation of a {@link WatchNextProgram} object.
*/
public static final class Builder extends BasePreviewProgram.Builder<Builder> {
/**
* Creates a new Builder object.
*/
public Builder() {
}
/**
* Creates a new Builder object with values copied from another Program.
*
* @param other The Program you're copying from.
*/
public Builder(WatchNextProgram other) {
mValues = new ContentValues(other.mValues);
}
/**
* Sets the "watch next" type of this program content.
*
* <p>The value should match one of the followings:
* {@link WatchNextPrograms#WATCH_NEXT_TYPE_CONTINUE},
* {@link WatchNextPrograms#WATCH_NEXT_TYPE_NEXT}, and
* {@link WatchNextPrograms#WATCH_NEXT_TYPE_NEW}.
*
* @param watchNextType The value of {@link WatchNextPrograms#COLUMN_WATCH_NEXT_TYPE} for
* the program.
* @return This Builder object to allow for chaining of calls to builder methods.
*/
public Builder setWatchNextType(@WatchNextType int watchNextType) {
mValues.put(WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE, watchNextType);
return this;
}
/**
* Sets the time when the program is going to begin in milliseconds since the epoch.
*
* @param lastEngagementTimeUtcMillis The value of
* {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS}
* for the program.
* @return This Builder object to allow for chaining of calls to builder methods.
*/
public Builder setLastEngagementTimeUtcMillis(long lastEngagementTimeUtcMillis) {
mValues.put(WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
lastEngagementTimeUtcMillis);
return this;
}
/**
* @return A new Program with values supplied by the Builder.
*/
public WatchNextProgram build() {
return new WatchNextProgram(this);
}
}
}