BasePreviewProgram.java revision b31c3281d870e9abb673db239234d580dcc4feff
1/*
2 * Copyright (C) 2017 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 */
16package androidx.tvprovider.media.tv;
17
18import static androidx.annotation.RestrictTo.Scope.LIBRARY;
19import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
20
21import android.content.ContentValues;
22import android.content.Intent;
23import android.database.Cursor;
24import android.net.Uri;
25import android.os.Build;
26import androidx.annotation.IntDef;
27import androidx.annotation.RestrictTo;
28import androidx.tvprovider.media.tv.TvContractCompat.PreviewProgramColumns;
29import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms;
30
31import java.lang.annotation.Retention;
32import java.lang.annotation.RetentionPolicy;
33import java.net.URISyntaxException;
34import java.text.SimpleDateFormat;
35import java.util.Date;
36import java.util.TimeZone;
37
38/**
39 * Base class for derived classes that want to have common fields for preview programs.
40 *
41 * @hide
42 */
43@RestrictTo(LIBRARY)
44public abstract class BasePreviewProgram extends BaseProgram {
45    /**
46     * @hide
47     */
48    @RestrictTo(LIBRARY_GROUP)
49    public static final String[] PROJECTION = getProjection();
50
51    private static final int INVALID_INT_VALUE = -1;
52    private static final long INVALID_LONG_VALUE = -1;
53    private static final int IS_TRANSIENT = 1;
54    private static final int IS_LIVE = 1;
55    private static final int IS_BROWSABLE = 1;
56
57    /** @hide */
58    @IntDef({
59            TYPE_UNKNOWN,
60            PreviewProgramColumns.TYPE_MOVIE,
61            PreviewProgramColumns.TYPE_TV_SERIES,
62            PreviewProgramColumns.TYPE_TV_SEASON,
63            PreviewProgramColumns.TYPE_TV_EPISODE,
64            PreviewProgramColumns.TYPE_CLIP,
65            PreviewProgramColumns.TYPE_EVENT,
66            PreviewProgramColumns.TYPE_CHANNEL,
67            PreviewProgramColumns.TYPE_TRACK,
68            PreviewProgramColumns.TYPE_ALBUM,
69            PreviewProgramColumns.TYPE_ARTIST,
70            PreviewProgramColumns.TYPE_PLAYLIST,
71            PreviewProgramColumns.TYPE_STATION,
72            PreviewProgramColumns.TYPE_GAME
73    })
74    @Retention(RetentionPolicy.SOURCE)
75    @RestrictTo(LIBRARY_GROUP)
76    public @interface Type {}
77
78    /**
79     * The unknown program type.
80     */
81    private static final int TYPE_UNKNOWN = -1;
82
83    /** @hide */
84    @IntDef({
85            ASPECT_RATIO_UNKNOWN,
86            PreviewProgramColumns.ASPECT_RATIO_16_9,
87            PreviewProgramColumns.ASPECT_RATIO_3_2,
88            PreviewProgramColumns.ASPECT_RATIO_4_3,
89            PreviewProgramColumns.ASPECT_RATIO_1_1,
90            PreviewProgramColumns.ASPECT_RATIO_2_3,
91            PreviewProgramColumns.ASPECT_RATIO_MOVIE_POSTER
92    })
93    @Retention(RetentionPolicy.SOURCE)
94    @RestrictTo(LIBRARY_GROUP)
95    public @interface AspectRatio {}
96
97    /**
98     * The aspect ratio for unknown aspect ratios.
99     */
100    private static final int ASPECT_RATIO_UNKNOWN = -1;
101
102    /** @hide */
103    @IntDef({
104            AVAILABILITY_UNKNOWN,
105            PreviewProgramColumns.AVAILABILITY_AVAILABLE,
106            PreviewProgramColumns.AVAILABILITY_FREE_WITH_SUBSCRIPTION,
107            PreviewProgramColumns.AVAILABILITY_PAID_CONTENT,
108            PreviewProgramColumns.AVAILABILITY_PURCHASED,
109            PreviewProgramColumns.AVAILABILITY_FREE
110    })
111    @Retention(RetentionPolicy.SOURCE)
112    @RestrictTo(LIBRARY_GROUP)
113    public @interface Availability {}
114
115    /**
116     * The unknown availability.
117     */
118    private static final int AVAILABILITY_UNKNOWN = -1;
119
120    /** @hide */
121    @IntDef({
122            INTERACTION_TYPE_UNKNOWN,
123            PreviewProgramColumns.INTERACTION_TYPE_VIEWS,
124            PreviewProgramColumns.INTERACTION_TYPE_LISTENS,
125            PreviewProgramColumns.INTERACTION_TYPE_FOLLOWERS,
126            PreviewProgramColumns.INTERACTION_TYPE_FANS,
127            PreviewProgramColumns.INTERACTION_TYPE_LIKES,
128            PreviewProgramColumns.INTERACTION_TYPE_THUMBS,
129            PreviewProgramColumns.INTERACTION_TYPE_VIEWERS,
130    })
131    @Retention(RetentionPolicy.SOURCE)
132    @RestrictTo(LIBRARY_GROUP)
133    public @interface InteractionType {}
134
135    /**
136     * The unknown interaction type.
137     */
138    private static final int INTERACTION_TYPE_UNKNOWN = -1;
139
140    BasePreviewProgram(Builder builder) {
141        super(builder);
142    }
143
144    /**
145     * @return The internal provider ID for the program.
146     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
147     */
148    public String getInternalProviderId() {
149        return mValues.getAsString(PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID);
150    }
151
152    /**
153     * @return The preview video URI for the program.
154     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
155     */
156    public Uri getPreviewVideoUri() {
157        String uri = mValues.getAsString(PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI);
158        return uri == null ? null : Uri.parse(uri);
159    }
160
161    /**
162     * @return The last playback position of the program in millis.
163     * @see androidx.tvprovider.media.tv.TvContractCompat
164     * .PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
165     */
166    public int getLastPlaybackPositionMillis() {
167        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
168        return i == null ? INVALID_INT_VALUE : i;
169    }
170
171    /**
172     * @return The duration of the program in millis.
173     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_DURATION_MILLIS
174     */
175    public int getDurationMillis() {
176        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_DURATION_MILLIS);
177        return i == null ? INVALID_INT_VALUE : i;
178    }
179
180    /**
181     * @return The intent URI which is launched when the program is selected.
182     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTENT_URI
183     */
184    public Uri getIntentUri() {
185        String uri = mValues.getAsString(PreviewPrograms.COLUMN_INTENT_URI);
186        return uri == null ? null : Uri.parse(uri);
187    }
188
189    /**
190     * @return The intent which is launched when the program is selected.
191     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTENT_URI
192     */
193    public Intent getIntent() throws URISyntaxException {
194        String uri = mValues.getAsString(PreviewPrograms.COLUMN_INTENT_URI);
195        return uri == null ? null : Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
196    }
197
198    /**
199     * @return Whether the program is transient or not.
200     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TRANSIENT
201     */
202    public boolean isTransient() {
203        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_TRANSIENT);
204        return i != null && i == IS_TRANSIENT;
205    }
206
207    /**
208     * @return The type of the program.
209     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TYPE
210     */
211    public @Type int getType() {
212        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_TYPE);
213        return i == null ? TYPE_UNKNOWN : i;
214    }
215
216    /**
217     * @return The poster art aspect ratio for the program.
218     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
219     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_POSTER_ART_URI
220     */
221    public @AspectRatio int getPosterArtAspectRatio() {
222        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO);
223        return i == null ? ASPECT_RATIO_UNKNOWN : i;
224    }
225
226    /**
227     * @return The thumbnail aspect ratio for the program.
228     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
229     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_THUMBNAIL_URI
230     */
231    public @AspectRatio int getThumbnailAspectRatio() {
232        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO);
233        return i == null ? ASPECT_RATIO_UNKNOWN : i;
234    }
235
236    /**
237     * @return The logo URI for the program.
238     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
239     */
240    public Uri getLogoUri() {
241        String uri = mValues.getAsString(PreviewPrograms.COLUMN_LOGO_URI);
242        return uri == null ? null : Uri.parse(uri);
243    }
244
245    /**
246     * @return The availability of the program.
247     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AVAILABILITY
248     */
249    public @Availability int getAvailability() {
250        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_AVAILABILITY);
251        return i == null ? AVAILABILITY_UNKNOWN : i;
252    }
253
254    /**
255     * @return The starting price of the program.
256     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_STARTING_PRICE
257     */
258    public String getStartingPrice() {
259        return mValues.getAsString(PreviewPrograms.COLUMN_STARTING_PRICE);
260    }
261
262    /**
263     * @return The offer price of the program.
264     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_OFFER_PRICE
265     */
266    public String getOfferPrice() {
267        return mValues.getAsString(PreviewPrograms.COLUMN_OFFER_PRICE);
268    }
269
270    /**
271     * @return The release date of the program.
272     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_RELEASE_DATE
273     */
274    public String getReleaseDate() {
275        return mValues.getAsString(PreviewPrograms.COLUMN_RELEASE_DATE);
276    }
277
278    /**
279     * @return The item count for the program.
280     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_ITEM_COUNT
281     */
282    public int getItemCount() {
283        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_ITEM_COUNT);
284        return i == null ? INVALID_INT_VALUE : i;
285    }
286
287    /**
288     * @return Whether the program is live or not.
289     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LIVE
290     */
291    public boolean isLive() {
292        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_LIVE);
293        return i != null && i == IS_LIVE;
294    }
295
296    /**
297     * @return The interaction type for the program.
298     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_TYPE
299     */
300    public @InteractionType int getInteractionType() {
301        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_INTERACTION_TYPE);
302        return i == null ? INTERACTION_TYPE_UNKNOWN : i;
303    }
304
305    /**
306     * @return The interaction count for the program.
307     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_COUNT
308     */
309    public long getInteractionCount() {
310        Long l = mValues.getAsLong(PreviewPrograms.COLUMN_INTERACTION_COUNT);
311        return l == null ? INVALID_LONG_VALUE : l;
312    }
313
314    /**
315     * @return The author for the program.
316     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AUTHOR
317     */
318    public String getAuthor() {
319        return mValues.getAsString(PreviewPrograms.COLUMN_AUTHOR);
320    }
321
322    /**
323     * @return Whether the program is browsable or not.
324     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_BROWSABLE
325     */
326    public boolean isBrowsable() {
327        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_BROWSABLE);
328        return i != null && i == IS_BROWSABLE;
329    }
330
331    /**
332     * @return The content ID for the program.
333     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_CONTENT_ID
334     */
335    public String getContentId() {
336        return mValues.getAsString(PreviewPrograms.COLUMN_CONTENT_ID);
337    }
338
339    /**
340     * @return The logo content description for the program.
341     * @see androidx.tvprovider.media.tv.TvContractCompat
342     * .PreviewPrograms#COLUMN_LOGO_CONTENT_DESCRIPTION
343     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
344     */
345    public String getLogoContentDescription() {
346        return mValues.getAsString(PreviewPrograms.COLUMN_LOGO_CONTENT_DESCRIPTION);
347    }
348
349    /**
350     * @return The genre for the program.
351     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_GENRE
352     */
353    public String getGenre() {
354        return mValues.getAsString(PreviewPrograms.COLUMN_GENRE);
355    }
356
357    /**
358     * @return The start time for the program.
359     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_START_TIME_UTC_MILLIS
360     */
361    public long getStartTimeUtcMillis() {
362        Long l = mValues.getAsLong(PreviewPrograms.COLUMN_START_TIME_UTC_MILLIS);
363        return l == null ? INVALID_LONG_VALUE : l;
364    }
365
366    /**
367     * @return The end time for the program.
368     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_END_TIME_UTC_MILLIS
369     */
370    public long getEndTimeUtcMillis() {
371        Long l = mValues.getAsLong(PreviewPrograms.COLUMN_END_TIME_UTC_MILLIS);
372        return l == null ? INVALID_LONG_VALUE : l;
373    }
374
375    /**
376     * @return The preview audio URI for the program.
377     * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_AUDIO_URI
378     */
379    public Uri getPreviewAudioUri() {
380        String uri = mValues.getAsString(PreviewPrograms.COLUMN_PREVIEW_AUDIO_URI);
381        return uri == null ? null : Uri.parse(uri);
382    }
383
384    @Override
385    public boolean equals(Object other) {
386        if (!(other instanceof BasePreviewProgram)) {
387            return false;
388        }
389        return mValues.equals(((BasePreviewProgram) other).mValues);
390    }
391
392    /**
393     * @return The fields of the BasePreviewProgram in {@link ContentValues} format to be easily
394     * inserted into the TV Input Framework database.
395     */
396    @Override
397    public ContentValues toContentValues() {
398        return toContentValues(false);
399    }
400
401    /**
402     * Returns fields of the BasePreviewProgram in the ContentValues format to be easily inserted
403     * into the TV Input Framework database.
404     *
405     * @param includeProtectedFields Whether the fields protected by system is included or not.
406     * @hide
407     */
408    @RestrictTo(LIBRARY_GROUP)
409    public ContentValues toContentValues(boolean includeProtectedFields) {
410        ContentValues values = super.toContentValues();
411        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
412            values.remove(PreviewProgramColumns.COLUMN_INTERNAL_PROVIDER_ID);
413            values.remove(PreviewProgramColumns.COLUMN_PREVIEW_VIDEO_URI);
414            values.remove(PreviewProgramColumns.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
415            values.remove(PreviewProgramColumns.COLUMN_DURATION_MILLIS);
416            values.remove(PreviewProgramColumns.COLUMN_INTENT_URI);
417            values.remove(PreviewProgramColumns.COLUMN_TRANSIENT);
418            values.remove(PreviewProgramColumns.COLUMN_TYPE);
419            values.remove(PreviewProgramColumns.COLUMN_POSTER_ART_ASPECT_RATIO);
420            values.remove(PreviewProgramColumns.COLUMN_THUMBNAIL_ASPECT_RATIO);
421            values.remove(PreviewProgramColumns.COLUMN_LOGO_URI);
422            values.remove(PreviewProgramColumns.COLUMN_AVAILABILITY);
423            values.remove(PreviewProgramColumns.COLUMN_STARTING_PRICE);
424            values.remove(PreviewProgramColumns.COLUMN_OFFER_PRICE);
425            values.remove(PreviewProgramColumns.COLUMN_RELEASE_DATE);
426            values.remove(PreviewProgramColumns.COLUMN_ITEM_COUNT);
427            values.remove(PreviewProgramColumns.COLUMN_LIVE);
428            values.remove(PreviewProgramColumns.COLUMN_INTERACTION_COUNT);
429            values.remove(PreviewProgramColumns.COLUMN_AUTHOR);
430            values.remove(PreviewProgramColumns.COLUMN_CONTENT_ID);
431            values.remove(PreviewProgramColumns.COLUMN_LOGO_CONTENT_DESCRIPTION);
432            values.remove(PreviewProgramColumns.COLUMN_GENRE);
433            values.remove(PreviewProgramColumns.COLUMN_START_TIME_UTC_MILLIS);
434            values.remove(PreviewProgramColumns.COLUMN_END_TIME_UTC_MILLIS);
435            values.remove(PreviewProgramColumns.COLUMN_PREVIEW_AUDIO_URI);
436        }
437        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !includeProtectedFields) {
438            values.remove(PreviewProgramColumns.COLUMN_BROWSABLE);
439        }
440        return values;
441    }
442
443    /**
444     * Sets the fields in the cursor to the given builder instance.
445     *
446     * @param cursor A row from the TV Input Framework database.
447     * @param builder A Builder to set the fields.
448     */
449    static void setFieldsFromCursor(Cursor cursor, Builder builder) {
450        // TODO: Add additional API which does not use costly getColumnIndex().
451        BaseProgram.setFieldsFromCursor(cursor, builder);
452        int index;
453        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
454            if ((index =
455                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTERNAL_PROVIDER_ID)) >= 0
456                    && !cursor.isNull(index)) {
457                builder.setInternalProviderId(cursor.getString(index));
458            }
459            if ((index =
460                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_PREVIEW_VIDEO_URI)) >= 0
461                    && !cursor.isNull(index)) {
462                builder.setPreviewVideoUri(Uri.parse(cursor.getString(index)));
463            }
464            if ((index = cursor.getColumnIndex(
465                    PreviewProgramColumns.COLUMN_LAST_PLAYBACK_POSITION_MILLIS)) >= 0
466                    && !cursor.isNull(index)) {
467                builder.setLastPlaybackPositionMillis(cursor.getInt(index));
468            }
469            if ((index =
470                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_DURATION_MILLIS)) >= 0
471                    && !cursor.isNull(index)) {
472                builder.setDurationMillis(cursor.getInt(index));
473            }
474            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTENT_URI)) >= 0
475                    && !cursor.isNull(index)) {
476                builder.setIntentUri(Uri.parse(cursor.getString(index)));
477            }
478            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_TRANSIENT)) >= 0
479                    && !cursor.isNull(index)) {
480                builder.setTransient(cursor.getInt(index) == IS_TRANSIENT);
481            }
482            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_TYPE)) >= 0
483                    && !cursor.isNull(index)) {
484                builder.setType(cursor.getInt(index));
485            }
486            if ((index = cursor.getColumnIndex(
487                    PreviewProgramColumns.COLUMN_POSTER_ART_ASPECT_RATIO)) >= 0
488                    && !cursor.isNull(index)) {
489                builder.setPosterArtAspectRatio(cursor.getInt(index));
490            }
491            if ((index =
492                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_THUMBNAIL_ASPECT_RATIO)) >= 0
493                    && !cursor.isNull(index)) {
494                builder.setThumbnailAspectRatio(cursor.getInt(index));
495            }
496            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_LOGO_URI)) >= 0
497                    && !cursor.isNull(index)) {
498                builder.setLogoUri(Uri.parse(cursor.getString(index)));
499            }
500            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_AVAILABILITY)) >= 0
501                    && !cursor.isNull(index)) {
502                builder.setAvailability(cursor.getInt(index));
503            }
504            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_STARTING_PRICE)) >= 0
505                    && !cursor.isNull(index)) {
506                builder.setStartingPrice(cursor.getString(index));
507            }
508            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_OFFER_PRICE)) >= 0
509                    && !cursor.isNull(index)) {
510                builder.setOfferPrice(cursor.getString(index));
511            }
512            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_RELEASE_DATE)) >= 0
513                    && !cursor.isNull(index)) {
514                builder.setReleaseDate(cursor.getString(index));
515            }
516            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_ITEM_COUNT)) >= 0
517                    && !cursor.isNull(index)) {
518                builder.setItemCount(cursor.getInt(index));
519            }
520            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_LIVE)) >= 0
521                    && !cursor.isNull(index)) {
522                builder.setLive(cursor.getInt(index) == IS_LIVE);
523            }
524            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTERACTION_TYPE)) >= 0
525                    && !cursor.isNull(index)) {
526                builder.setInteractionType(cursor.getInt(index));
527            }
528            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTERACTION_COUNT)) >= 0
529                    && !cursor.isNull(index)) {
530                builder.setInteractionCount(cursor.getInt(index));
531            }
532            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_AUTHOR)) >= 0
533                    && !cursor.isNull(index)) {
534                builder.setAuthor(cursor.getString(index));
535            }
536            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_BROWSABLE)) >= 0
537                    && !cursor.isNull(index)) {
538                builder.setBrowsable(cursor.getInt(index) == IS_BROWSABLE);
539            }
540            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_CONTENT_ID)) >= 0
541                    && !cursor.isNull(index)) {
542                builder.setContentId(cursor.getString(index));
543            }
544            if ((index = cursor.getColumnIndex(
545                    PreviewProgramColumns.COLUMN_LOGO_CONTENT_DESCRIPTION)) >= 0
546                    && !cursor.isNull(index)) {
547                builder.setLogoContentDescription(cursor.getString(index));
548            }
549            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_GENRE)) >= 0
550                    && !cursor.isNull(index)) {
551                builder.setGenre(cursor.getString(index));
552            }
553            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_START_TIME_UTC_MILLIS))
554                    >= 0 && !cursor.isNull(index)) {
555                builder.setStartTimeUtcMillis(cursor.getLong(index));
556            }
557            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_END_TIME_UTC_MILLIS))
558                    >= 0 && !cursor.isNull(index)) {
559                builder.setEndTimeUtcMillis(cursor.getLong(index));
560            }
561            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_PREVIEW_AUDIO_URI)) >= 0
562                    && !cursor.isNull(index)) {
563                builder.setPreviewAudioUri(Uri.parse(cursor.getString(index)));
564            }
565        }
566    }
567
568    private static String[] getProjection() {
569        String[] oColumns = new String[] {
570                PreviewProgramColumns.COLUMN_INTERNAL_PROVIDER_ID,
571                PreviewProgramColumns.COLUMN_PREVIEW_VIDEO_URI,
572                PreviewProgramColumns.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
573                PreviewProgramColumns.COLUMN_DURATION_MILLIS,
574                PreviewProgramColumns.COLUMN_INTENT_URI,
575                PreviewProgramColumns.COLUMN_TRANSIENT,
576                PreviewProgramColumns.COLUMN_TYPE,
577                PreviewProgramColumns.COLUMN_POSTER_ART_ASPECT_RATIO,
578                PreviewProgramColumns.COLUMN_THUMBNAIL_ASPECT_RATIO,
579                PreviewProgramColumns.COLUMN_LOGO_URI,
580                PreviewProgramColumns.COLUMN_AVAILABILITY,
581                PreviewProgramColumns.COLUMN_STARTING_PRICE,
582                PreviewProgramColumns.COLUMN_OFFER_PRICE,
583                PreviewProgramColumns.COLUMN_RELEASE_DATE,
584                PreviewProgramColumns.COLUMN_ITEM_COUNT,
585                PreviewProgramColumns.COLUMN_LIVE,
586                PreviewProgramColumns.COLUMN_INTERACTION_TYPE,
587                PreviewProgramColumns.COLUMN_INTERACTION_COUNT,
588                PreviewProgramColumns.COLUMN_AUTHOR,
589                PreviewProgramColumns.COLUMN_BROWSABLE,
590                PreviewProgramColumns.COLUMN_CONTENT_ID,
591                PreviewProgramColumns.COLUMN_LOGO_CONTENT_DESCRIPTION,
592                PreviewProgramColumns.COLUMN_GENRE,
593                PreviewProgramColumns.COLUMN_START_TIME_UTC_MILLIS,
594                PreviewProgramColumns.COLUMN_END_TIME_UTC_MILLIS,
595                PreviewProgramColumns.COLUMN_PREVIEW_AUDIO_URI,
596        };
597        return CollectionUtils.concatAll(BaseProgram.PROJECTION, oColumns);
598    }
599
600    /**
601     * This Builder class simplifies the creation of a {@link BasePreviewProgram} object.
602     *
603     * @param <T> The Builder of the derived classe.
604     */
605    public abstract static class Builder<T extends Builder> extends BaseProgram.Builder<T> {
606        private static final SimpleDateFormat sFormat =
607                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
608
609        static {
610            sFormat.setTimeZone(TimeZone.getTimeZone("GMT-0"));
611        }
612
613        /**
614         * Creates a new Builder object.
615         */
616        public Builder() {
617        }
618
619        /**
620         * Creates a new Builder object with values copied from another Program.
621         *
622         * @param other The Program you're copying from.
623         */
624        public Builder(BasePreviewProgram other) {
625            mValues = new ContentValues(other.mValues);
626        }
627
628        /**
629         * Sets external ID for the program.
630         *
631         * @param externalId The internal provider ID for the program.
632         * @return This Builder object to allow for chaining of calls to builder methods.
633         * @see androidx.tvprovider.media.tv.TvContractCompat
634         * .PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
635         */
636        public T setInternalProviderId(String externalId) {
637            mValues.put(PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID, externalId);
638            return (T) this;
639        }
640
641        /**
642         * Sets a URI for the preview video.
643         *
644         * @param previewVideoUri The preview video URI for the program.
645         * @return This Builder object to allow for chaining of calls to builder methods.
646         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
647         */
648        public T setPreviewVideoUri(Uri previewVideoUri) {
649            mValues.put(PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI,
650                    previewVideoUri == null ? null : previewVideoUri.toString());
651            return (T) this;
652        }
653
654        /**
655         * Sets the last playback position (in milliseconds) of the preview video.
656         *
657         * @param position The last playback posirion for the program in millis.
658         * @return This Builder object to allow for chaining of calls to builder methods.
659         * @see androidx.tvprovider.media.tv.TvContractCompat
660         * .PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
661         */
662        public T setLastPlaybackPositionMillis(int position) {
663            mValues.put(PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, position);
664            return (T) this;
665        }
666
667        /**
668         * Sets the last playback duration (in milliseconds) of the preview video.
669         *
670         * @param duration The duration the program in millis.
671         * @return This Builder object to allow for chaining of calls to builder methods.
672         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_DURATION_MILLIS
673         */
674        public T setDurationMillis(int duration) {
675            mValues.put(PreviewPrograms.COLUMN_DURATION_MILLIS, duration);
676            return (T) this;
677        }
678
679        /**
680         * Sets the intent URI which is launched when the program is selected.
681         *
682         * @param intentUri The intent URI for the program.
683         * @return This Builder object to allow for chaining of calls to builder methods.
684         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTENT_URI
685         */
686        public T setIntentUri(Uri intentUri) {
687            mValues.put(PreviewPrograms.COLUMN_INTENT_URI,
688                    intentUri == null ? null : intentUri.toString());
689            return (T) this;
690        }
691
692        /**
693         * Sets the intent which is launched when the program is selected.
694         *
695         * @param intent The Intent to be executed when the preview program is selected
696         * @return This Builder object to allow for chaining of calls to builder methods.
697         */
698        public T setIntent(Intent intent) {
699            return setIntentUri(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
700        }
701
702        /**
703         * Sets whether this program is transient or not.
704         *
705         * @param transientValue Whether the program is transient or not.
706         * @return This Builder object to allow for chaining of calls to builder methods.
707         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TRANSIENT
708         */
709        public T setTransient(boolean transientValue) {
710            mValues.put(PreviewPrograms.COLUMN_TRANSIENT, transientValue ? IS_TRANSIENT : 0);
711            return (T) this;
712        }
713
714        /**
715         * Sets the type of this program content.
716         *
717         * <p>The value should match one of the followings:
718         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_MOVIE},
719         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_TV_SERIES},
720         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_TV_SEASON},
721         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_TV_EPISODE},
722         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_CLIP},
723         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_EVENT},
724         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_CHANNEL},
725         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_TRACK},
726         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_ALBUM},
727         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_ARTIST},
728         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_PLAYLIST},
729         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_STATION}, and
730         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#TYPE_GAME}.
731         *
732         * @param type The type of the program.
733         * @return This Builder object to allow for chaining of calls to builder methods.
734         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_TYPE
735         */
736        public T setType(@Type int type) {
737            mValues.put(PreviewPrograms.COLUMN_TYPE, type);
738            return (T) this;
739        }
740
741        /**
742         * Sets the aspect ratio of the poster art for this TV program.
743         *
744         * <p>The value should match one of the followings:
745         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_16_9},
746         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_3_2},
747         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_4_3},
748         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_1_1},
749         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_2_3}, and
750         * {@link androidx.tvprovider.media.tv.TvContractCompat
751         * .PreviewPrograms#ASPECT_RATIO_MOVIE_POSTER}.
752         *
753         * @param ratio The poster art aspect ratio for the program.
754         * @return This Builder object to allow for chaining of calls to builder methods.
755         * @see androidx.tvprovider.media.tv.TvContractCompat
756         * .PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
757         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_POSTER_ART_URI
758         */
759        public T setPosterArtAspectRatio(@AspectRatio int ratio) {
760            mValues.put(PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, ratio);
761            return (T) this;
762        }
763
764        /**
765         * Sets the aspect ratio of the thumbnail for this TV program.
766         *
767         * <p>The value should match one of the followings:
768         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_16_9},
769         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_3_2},
770         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_4_3},
771         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_1_1},
772         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#ASPECT_RATIO_2_3}, and
773         * {@link androidx.tvprovider.media.tv.TvContractCompat
774         * .PreviewPrograms#ASPECT_RATIO_MOVIE_POSTER}.
775         *
776         * @param ratio The thumbnail aspect ratio of the program.
777         * @return This Builder object to allow for chaining of calls to builder methods.
778         * @see androidx.tvprovider.media.tv.TvContractCompat
779         * .PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
780         */
781        public T setThumbnailAspectRatio(@AspectRatio int ratio) {
782            mValues.put(PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, ratio);
783            return (T) this;
784        }
785
786        /**
787         * Sets the URI for the logo of this TV program.
788         *
789         * @param logoUri The logo URI for the program.
790         * @return This Builder object to allow for chaining of calls to builder methods.
791         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
792         */
793        public T setLogoUri(Uri logoUri) {
794            mValues.put(PreviewPrograms.COLUMN_LOGO_URI,
795                    logoUri == null ? null : logoUri.toString());
796            return (T) this;
797        }
798
799        /**
800         * Sets the availability of this TV program.
801         *
802         * <p>The value should match one of the followings:
803         * {@link androidx.tvprovider.media.tv.TvContractCompat
804         * .PreviewPrograms#AVAILABILITY_AVAILABLE},
805         * {@link androidx.tvprovider.media.tv.TvContractCompat
806         * .PreviewPrograms#AVAILABILITY_FREE_WITH_SUBSCRIPTION},
807         * {@link androidx.tvprovider.media.tv.TvContractCompat
808         * .PreviewPrograms#AVAILABILITY_PAID_CONTENT},
809         * {@link androidx.tvprovider.media.tv.TvContractCompat
810         * .PreviewPrograms#AVAILABILITY_PURCHASED}, and
811         * {@link androidx.tvprovider.media.tv.TvContractCompat
812         * .PreviewPrograms#AVAILABILITY_FREE}.
813         *
814         * @param availability The availability of the program.
815         * @return This Builder object to allow for chaining of calls to builder methods.
816         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AVAILABILITY
817         */
818        public T setAvailability(@Availability int availability) {
819            mValues.put(PreviewPrograms.COLUMN_AVAILABILITY, availability);
820            return (T) this;
821        }
822
823        /**
824         * Sets the starting price of this TV program.
825         *
826         * @param price The starting price of the program.
827         * @return This Builder object to allow for chaining of calls to builder methods.
828         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_STARTING_PRICE
829         */
830        public T setStartingPrice(String price) {
831            mValues.put(PreviewPrograms.COLUMN_STARTING_PRICE, price);
832            return (T) this;
833        }
834
835        /**
836         * Sets the offer price of this TV program.
837         *
838         * @param price The offer price of the program.
839         * @return This Builder object to allow for chaining of calls to builder methods.
840         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_OFFER_PRICE
841         */
842        public T setOfferPrice(String price) {
843            mValues.put(PreviewPrograms.COLUMN_OFFER_PRICE, price);
844            return (T) this;
845        }
846
847        /**
848         * Sets the release date of this TV program.
849         *
850         * <p>The value should be in one of the following formats:
851         * "yyyy", "yyyy-MM-dd", and "yyyy-MM-ddTHH:mm:ssZ" (UTC in ISO 8601).
852         *
853         * @param releaseDate The release date of the program.
854         * @return This Builder object to allow for chaining of calls to builder methods.
855         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_RELEASE_DATE
856         */
857        public T setReleaseDate(String releaseDate) {
858            mValues.put(PreviewPrograms.COLUMN_RELEASE_DATE, releaseDate);
859            return (T) this;
860        }
861
862        /**
863         * Sets the release date of this TV program.
864         *
865         * @param releaseDate The release date of the program.
866         * @return This Builder object to allow for chaining of calls to builder methods.
867         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_RELEASE_DATE
868         */
869        public T setReleaseDate(Date releaseDate) {
870            mValues.put(PreviewPrograms.COLUMN_RELEASE_DATE, sFormat.format(releaseDate));
871            return (T) this;
872        }
873
874        /**
875         * Sets the count of the items included in this TV program.
876         *
877         * @param itemCount The item count for the program.
878         * @return This Builder object to allow for chaining of calls to builder methods.
879         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_ITEM_COUNT
880         */
881        public T setItemCount(int itemCount) {
882            mValues.put(PreviewPrograms.COLUMN_ITEM_COUNT, itemCount);
883            return (T) this;
884        }
885
886        /**
887         * Sets whether this TV program is live or not.
888         *
889         * @param live Whether the program is live or not.
890         * @return This Builder object to allow for chaining of calls to builder methods.
891         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LIVE
892         */
893        public T setLive(boolean live) {
894            mValues.put(PreviewPrograms.COLUMN_LIVE, live ? IS_LIVE : 0);
895            return (T) this;
896        }
897
898        /**
899         * Sets the type of interaction for this TV program.
900         *
901         * <p> The value should match one of the followings:
902         * {@link androidx.tvprovider.media.tv.TvContractCompat
903         * .PreviewPrograms#INTERACTION_TYPE_LISTENS},
904         * {@link androidx.tvprovider.media.tv.TvContractCompat
905         * .PreviewPrograms#INTERACTION_TYPE_FOLLOWERS},
906         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#INTERACTION_TYPE_FANS},
907         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#INTERACTION_TYPE_LIKES},
908         * {@link androidx.tvprovider.media.tv.TvContractCompat
909         * .PreviewPrograms#INTERACTION_TYPE_THUMBS},
910         * {@link androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#INTERACTION_TYPE_VIEWS},
911         * and
912         * {@link androidx.tvprovider.media.tv.TvContractCompat
913         * .PreviewPrograms#INTERACTION_TYPE_VIEWERS}.
914         *
915         * @param interactionType The interaction type of the program.
916         * @return This Builder object to allow for chaining of calls to builder methods.
917         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_TYPE
918         */
919        public T setInteractionType(@InteractionType int interactionType) {
920            mValues.put(PreviewPrograms.COLUMN_INTERACTION_TYPE, interactionType);
921            return (T) this;
922        }
923
924        /**
925         * Sets the interaction count for this program.
926         *
927         * @param interactionCount The interaction count for the program.
928         * @return This Builder object to allow for chaining of calls to builder methods.
929         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_INTERACTION_COUNT
930         */
931        public T setInteractionCount(long interactionCount) {
932            mValues.put(PreviewPrograms.COLUMN_INTERACTION_COUNT, interactionCount);
933            return (T) this;
934        }
935
936        /**
937         * Sets the author or artist of this content.
938         *
939         * @param author The author of the program.
940         * @return This Builder object to allow for chaining of calls to builder methods.
941         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_AUTHOR
942         */
943        public T setAuthor(String author) {
944            mValues.put(PreviewPrograms.COLUMN_AUTHOR, author);
945            return (T) this;
946        }
947
948        /**
949         * Sets whether this TV program is browsable or not.
950         *
951         * @param browsable Whether the program is browsable or not.
952         * @return This Builder object to allow for chaining of calls to builder methods.
953         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_BROWSABLE
954         * @hide
955         */
956        @RestrictTo(LIBRARY_GROUP)
957        public T setBrowsable(boolean browsable) {
958            mValues.put(PreviewPrograms.COLUMN_BROWSABLE, browsable ? IS_BROWSABLE : 0);
959            return (T) this;
960        }
961
962        /**
963         * Sets the content ID for this program.
964         *
965         * @param contentId The content ID for the program.
966         * @return This Builder object to allow for chaining of calls to builder methods.
967         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_CONTENT_ID
968         */
969        public T setContentId(String contentId) {
970            mValues.put(PreviewPrograms.COLUMN_CONTENT_ID, contentId);
971            return (T) this;
972        }
973
974        /**
975         * Sets the logo's content description for this program.
976         *
977         * @param logoContentDescription The content description for the logo displayed in the
978         *                               program.
979         * @return This Builder object to allow for chaining of calls to builder methods.
980         * @see androidx.tvprovider.media.tv.TvContractCompat
981         * .PreviewPrograms#COLUMN_LOGO_CONTENT_DESCRIPTION
982         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_LOGO_URI
983         */
984        public T setLogoContentDescription(String logoContentDescription) {
985            mValues.put(PreviewPrograms.COLUMN_LOGO_CONTENT_DESCRIPTION, logoContentDescription);
986            return (T) this;
987        }
988
989        /**
990         * Sets the genre for this program.
991         *
992         * @param genre The genre for the program.
993         * @return This Builder object to allow for chaining of calls to builder methods.
994         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_GENRE
995         */
996        public T setGenre(String genre) {
997            mValues.put(PreviewPrograms.COLUMN_GENRE, genre);
998            return (T) this;
999        }
1000
1001        /**
1002         * Sets the start time of the program (for live programs).
1003         *
1004         * @param startTime The start time for the program.
1005         * @return This Builder object to allow for chaining of calls to builder methods.
1006         * @see androidx.tvprovider.media.tv.TvContractCompat
1007         * .PreviewPrograms#COLUMN_START_TIME_UTC_MILLIS
1008         */
1009        public T setStartTimeUtcMillis(long startTime) {
1010            mValues.put(PreviewPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
1011            return (T) this;
1012        }
1013
1014        /**
1015         * Sets the end time of the program (for live programs).
1016         *
1017         * @param endTime The end time for the program.
1018         * @return This Builder object to allow for chaining of calls to builder methods.
1019         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_END_TIME_UTC_MILLIS
1020         */
1021        public T setEndTimeUtcMillis(long endTime) {
1022            mValues.put(PreviewPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
1023            return (T) this;
1024        }
1025
1026        /**
1027         * Sets a URI for the preview audio.
1028         *
1029         * @param previewAudioUri The preview audio URI for the program.
1030         * @return This Builder object to allow for chaining of calls to builder methods.
1031         * @see androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms#COLUMN_PREVIEW_AUDIO_URI
1032         */
1033        public T setPreviewAudioUri(Uri previewAudioUri) {
1034            mValues.put(PreviewPrograms.COLUMN_PREVIEW_AUDIO_URI,
1035                    previewAudioUri == null ? null : previewAudioUri.toString());
1036            return (T) this;
1037        }
1038    }
1039}
1040