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 android.support.media.tv;
17
18import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
19
20import android.annotation.TargetApi;
21import android.content.ContentValues;
22import android.content.Intent;
23import android.database.Cursor;
24import android.net.Uri;
25import android.os.Build;
26import android.support.annotation.RestrictTo;
27import android.support.media.tv.TvContractCompat.PreviewProgramColumns;
28import android.support.media.tv.TvContractCompat.PreviewProgramColumns.AspectRatio;
29import android.support.media.tv.TvContractCompat.PreviewProgramColumns.Availability;
30import android.support.media.tv.TvContractCompat.PreviewProgramColumns.InteractionType;
31import android.support.media.tv.TvContractCompat.PreviewProgramColumns.Type;
32import android.support.media.tv.TvContractCompat.PreviewPrograms;
33
34import java.net.URISyntaxException;
35import java.text.SimpleDateFormat;
36import java.util.Date;
37import java.util.TimeZone;
38
39/**
40 * Base class for derived classes that want to have common fields for preview programs.
41 */
42@TargetApi(26)
43public abstract class BasePreviewProgram extends BaseProgram {
44    /**
45     * @hide
46     */
47    @RestrictTo(LIBRARY_GROUP)
48    public static final String[] PROJECTION = getProjection();
49
50    private static final int INVALID_INT_VALUE = -1;
51    private static final long INVALID_LONG_VALUE = -1;
52    private static final int IS_TRANSIENT = 1;
53    private static final int IS_LIVE = 1;
54    private static final int IS_BROWSABLE = 1;
55
56    BasePreviewProgram(Builder builder) {
57        super(builder);
58    }
59
60    /**
61     * @return The internal provider ID for the program.
62     * @see PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
63     */
64    public String getInternalProviderId() {
65        return mValues.getAsString(PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID);
66    }
67
68    /**
69     * @return The preview video URI for the program.
70     * @see PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
71     */
72    public Uri getPreviewVideoUri() {
73        String uri = mValues.getAsString(PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI);
74        return uri == null ? null : Uri.parse(uri);
75    }
76
77    /**
78     * @return The last playback position of the program in millis.
79     * @see PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
80     */
81    public int getLastPlaybackPositionMillis() {
82        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
83        return i == null ? INVALID_INT_VALUE : i;
84    }
85
86    /**
87     * @return The duration of the program in millis.
88     * @see PreviewPrograms#COLUMN_DURATION_MILLIS
89     */
90    public int getDurationMillis() {
91        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_DURATION_MILLIS);
92        return i == null ? INVALID_INT_VALUE : i;
93    }
94
95    /**
96     * @return The intent URI which is launched when the program is selected.
97     * @see PreviewPrograms#COLUMN_INTENT_URI
98     */
99    public Uri getIntentUri() {
100        String uri = mValues.getAsString(PreviewPrograms.COLUMN_INTENT_URI);
101        return uri == null ? null : Uri.parse(uri);
102    }
103
104    /**
105     * @return The intent which is launched when the program is selected.
106     * @see PreviewPrograms#COLUMN_INTENT_URI
107     */
108    public Intent getIntent() throws URISyntaxException {
109        String uri = mValues.getAsString(PreviewPrograms.COLUMN_INTENT_URI);
110        return uri == null ? null : Intent.parseUri(uri, Intent.URI_INTENT_SCHEME);
111    }
112
113    /**
114     * @return Whether the program is transient or not.
115     * @see PreviewPrograms#COLUMN_TRANSIENT
116     */
117    public boolean isTransient() {
118        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_TRANSIENT);
119        return i != null && i == IS_TRANSIENT;
120    }
121
122    /**
123     * @return The type of the program.
124     * @see PreviewPrograms#COLUMN_TYPE
125     */
126    public @Type int getType() {
127        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_TYPE);
128        return i == null ? INVALID_INT_VALUE : i;
129    }
130
131    /**
132     * @return The poster art aspect ratio for the program.
133     * @see PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
134     * @see PreviewPrograms#COLUMN_POSTER_ART_URI
135     */
136    public @AspectRatio int getPosterArtAspectRatio() {
137        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO);
138        return i == null ? INVALID_INT_VALUE : i;
139    }
140
141    /**
142     * @return The thumbnail aspect ratio for the program.
143     * @see PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
144     * @see PreviewPrograms#COLUMN_THUMBNAIL_URI
145     */
146    public @AspectRatio int getThumbnailAspectRatio() {
147        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO);
148        return i == null ? INVALID_INT_VALUE : i;
149    }
150
151    /**
152     * @return The logo URI for the program.
153     * @see PreviewPrograms#COLUMN_LOGO_URI
154     */
155    public Uri getLogoUri() {
156        String uri = mValues.getAsString(PreviewPrograms.COLUMN_LOGO_URI);
157        return uri == null ? null : Uri.parse(uri);
158    }
159
160    /**
161     * @return The availability of the program.
162     * @see PreviewPrograms#COLUMN_AVAILABILITY
163     */
164    public @Availability int getAvailability() {
165        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_AVAILABILITY);
166        return i == null ? INVALID_INT_VALUE : i;
167    }
168
169    /**
170     * @return The starting price of the program.
171     * @see PreviewPrograms#COLUMN_STARTING_PRICE
172     */
173    public String getStartingPrice() {
174        return mValues.getAsString(PreviewPrograms.COLUMN_STARTING_PRICE);
175    }
176
177    /**
178     * @return The offer price of the program.
179     * @see PreviewPrograms#COLUMN_OFFER_PRICE
180     */
181    public String getOfferPrice() {
182        return mValues.getAsString(PreviewPrograms.COLUMN_OFFER_PRICE);
183    }
184
185    /**
186     * @return The release date of the program.
187     * @see PreviewPrograms#COLUMN_RELEASE_DATE
188     */
189    public String getReleaseDate() {
190        return mValues.getAsString(PreviewPrograms.COLUMN_RELEASE_DATE);
191    }
192
193    /**
194     * @return The item count for the program.
195     * @see PreviewPrograms#COLUMN_ITEM_COUNT
196     */
197    public int getItemCount() {
198        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_ITEM_COUNT);
199        return i == null ? INVALID_INT_VALUE : i;
200    }
201
202    /**
203     * @return Whether the program is live or not.
204     * @see PreviewPrograms#COLUMN_LIVE
205     */
206    public boolean isLive() {
207        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_LIVE);
208        return i != null && i == IS_LIVE;
209    }
210
211    /**
212     * @return The interaction type for the program.
213     * @see PreviewPrograms#COLUMN_INTERACTION_TYPE
214     */
215    public @InteractionType int getInteractionType() {
216        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_INTERACTION_TYPE);
217        return i == null ? INVALID_INT_VALUE : i;
218    }
219
220    /**
221     * @return The interaction count for the program.
222     * @see PreviewPrograms#COLUMN_INTERACTION_COUNT
223     */
224    public long getInteractionCount() {
225        Long l = mValues.getAsLong(PreviewPrograms.COLUMN_INTERACTION_COUNT);
226        return l == null ? INVALID_LONG_VALUE : l;
227    }
228
229    /**
230     * @return The author for the program.
231     * @see PreviewPrograms#COLUMN_AUTHOR
232     */
233    public String getAuthor() {
234        return mValues.getAsString(PreviewPrograms.COLUMN_AUTHOR);
235    }
236
237    /**
238     * @return Whether the program is browsable or not.
239     * @see PreviewPrograms#COLUMN_BROWSABLE;
240     */
241    public boolean isBrowsable() {
242        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_BROWSABLE);
243        return i != null && i == IS_BROWSABLE;
244    }
245
246    /**
247     * @return The content ID for the program.
248     * @see PreviewPrograms#COLUMN_CONTENT_ID
249     */
250    public String getContentId() {
251        return mValues.getAsString(PreviewPrograms.COLUMN_CONTENT_ID);
252    }
253
254    @Override
255    public boolean equals(Object other) {
256        if (!(other instanceof BasePreviewProgram)) {
257            return false;
258        }
259        return mValues.equals(((BasePreviewProgram) other).mValues);
260    }
261
262    /**
263     * @return The fields of the BasePreviewProgram in {@link ContentValues} format to be easily
264     * inserted into the TV Input Framework database.
265     */
266    @Override
267    public ContentValues toContentValues() {
268        return toContentValues(false);
269    }
270
271    /**
272     * Returns fields of the BasePreviewProgram in the ContentValues format to be easily inserted
273     * into the TV Input Framework database.
274     *
275     * @param includeProtectedFields Whether the fields protected by system is included or not.
276     * @hide
277     */
278    @RestrictTo(LIBRARY_GROUP)
279    public ContentValues toContentValues(boolean includeProtectedFields) {
280        ContentValues values = super.toContentValues();
281        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
282            values.remove(PreviewProgramColumns.COLUMN_INTERNAL_PROVIDER_ID);
283            values.remove(PreviewProgramColumns.COLUMN_PREVIEW_VIDEO_URI);
284            values.remove(PreviewProgramColumns.COLUMN_LAST_PLAYBACK_POSITION_MILLIS);
285            values.remove(PreviewProgramColumns.COLUMN_DURATION_MILLIS);
286            values.remove(PreviewProgramColumns.COLUMN_INTENT_URI);
287            values.remove(PreviewProgramColumns.COLUMN_TRANSIENT);
288            values.remove(PreviewProgramColumns.COLUMN_TYPE);
289            values.remove(PreviewProgramColumns.COLUMN_POSTER_ART_ASPECT_RATIO);
290            values.remove(PreviewProgramColumns.COLUMN_THUMBNAIL_ASPECT_RATIO);
291            values.remove(PreviewProgramColumns.COLUMN_LOGO_URI);
292            values.remove(PreviewProgramColumns.COLUMN_AVAILABILITY);
293            values.remove(PreviewProgramColumns.COLUMN_STARTING_PRICE);
294            values.remove(PreviewProgramColumns.COLUMN_OFFER_PRICE);
295            values.remove(PreviewProgramColumns.COLUMN_RELEASE_DATE);
296            values.remove(PreviewProgramColumns.COLUMN_ITEM_COUNT);
297            values.remove(PreviewProgramColumns.COLUMN_LIVE);
298            values.remove(PreviewProgramColumns.COLUMN_INTERACTION_COUNT);
299            values.remove(PreviewProgramColumns.COLUMN_AUTHOR);
300            values.remove(PreviewProgramColumns.COLUMN_CONTENT_ID);
301        }
302        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !includeProtectedFields) {
303            values.remove(PreviewProgramColumns.COLUMN_BROWSABLE);
304        }
305        return values;
306    }
307
308    /**
309     * Sets the fields in the cursor to the given builder instance.
310     *
311     * @param cursor A row from the TV Input Framework database.
312     * @param builder A Builder to set the fields.
313     */
314    static void setFieldsFromCursor(Cursor cursor, Builder builder) {
315        // TODO: Add additional API which does not use costly getColumnIndex().
316        BaseProgram.setFieldsFromCursor(cursor, builder);
317        int index;
318        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
319            if ((index =
320                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTERNAL_PROVIDER_ID)) >= 0
321                    && !cursor.isNull(index)) {
322                builder.setInternalProviderId(cursor.getString(index));
323            }
324            if ((index =
325                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_PREVIEW_VIDEO_URI)) >= 0
326                    && !cursor.isNull(index)) {
327                builder.setPreviewVideoUri(Uri.parse(cursor.getString(index)));
328            }
329            if ((index = cursor.getColumnIndex(
330                    PreviewProgramColumns.COLUMN_LAST_PLAYBACK_POSITION_MILLIS)) >= 0
331                    && !cursor.isNull(index)) {
332                builder.setLastPlaybackPositionMillis(cursor.getInt(index));
333            }
334            if ((index =
335                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_DURATION_MILLIS)) >= 0
336                    && !cursor.isNull(index)) {
337                builder.setDurationMillis(cursor.getInt(index));
338            }
339            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTENT_URI)) >= 0
340                    && !cursor.isNull(index)) {
341                builder.setIntentUri(Uri.parse(cursor.getString(index)));
342            }
343            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_TRANSIENT)) >= 0
344                    && !cursor.isNull(index)) {
345                builder.setTransient(cursor.getInt(index) == IS_TRANSIENT);
346            }
347            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_TYPE)) >= 0
348                    && !cursor.isNull(index)) {
349                builder.setType(cursor.getInt(index));
350            }
351            if ((index = cursor.getColumnIndex(
352                    PreviewProgramColumns.COLUMN_POSTER_ART_ASPECT_RATIO)) >= 0
353                    && !cursor.isNull(index)) {
354                builder.setPosterArtAspectRatio(cursor.getInt(index));
355            }
356            if ((index =
357                    cursor.getColumnIndex(PreviewProgramColumns.COLUMN_THUMBNAIL_ASPECT_RATIO)) >= 0
358                    && !cursor.isNull(index)) {
359                builder.setThumbnailAspectRatio(cursor.getInt(index));
360            }
361            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_LOGO_URI)) >= 0
362                    && !cursor.isNull(index)) {
363                builder.setLogoUri(Uri.parse(cursor.getString(index)));
364            }
365            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_AVAILABILITY)) >= 0
366                    && !cursor.isNull(index)) {
367                builder.setAvailability(cursor.getInt(index));
368            }
369            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_STARTING_PRICE)) >= 0
370                    && !cursor.isNull(index)) {
371                builder.setStartingPrice(cursor.getString(index));
372            }
373            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_OFFER_PRICE)) >= 0
374                    && !cursor.isNull(index)) {
375                builder.setOfferPrice(cursor.getString(index));
376            }
377            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_RELEASE_DATE)) >= 0
378                    && !cursor.isNull(index)) {
379                builder.setReleaseDate(cursor.getString(index));
380            }
381            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_ITEM_COUNT)) >= 0
382                    && !cursor.isNull(index)) {
383                builder.setItemCount(cursor.getInt(index));
384            }
385            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_LIVE)) >= 0
386                    && !cursor.isNull(index)) {
387                builder.setLive(cursor.getInt(index) == IS_LIVE);
388            }
389            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTERACTION_TYPE)) >= 0
390                    && !cursor.isNull(index)) {
391                builder.setInteractionType(cursor.getInt(index));
392            }
393            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_INTERACTION_COUNT)) >= 0
394                    && !cursor.isNull(index)) {
395                builder.setInteractionCount(cursor.getInt(index));
396            }
397            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_AUTHOR)) >= 0
398                    && !cursor.isNull(index)) {
399                builder.setAuthor(cursor.getString(index));
400            }
401            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_BROWSABLE)) >= 0
402                    && !cursor.isNull(index)) {
403                builder.setBrowsable(cursor.getInt(index) == IS_BROWSABLE);
404            }
405            if ((index = cursor.getColumnIndex(PreviewProgramColumns.COLUMN_CONTENT_ID)) >= 0
406                    && !cursor.isNull(index)) {
407                builder.setContentId(cursor.getString(index));
408            }
409        }
410    }
411
412    private static String[] getProjection() {
413        String[] oColumns = new String[] {
414                PreviewProgramColumns.COLUMN_INTERNAL_PROVIDER_ID,
415                PreviewProgramColumns.COLUMN_PREVIEW_VIDEO_URI,
416                PreviewProgramColumns.COLUMN_LAST_PLAYBACK_POSITION_MILLIS,
417                PreviewProgramColumns.COLUMN_DURATION_MILLIS,
418                PreviewProgramColumns.COLUMN_INTENT_URI,
419                PreviewProgramColumns.COLUMN_TRANSIENT,
420                PreviewProgramColumns.COLUMN_TYPE,
421                PreviewProgramColumns.COLUMN_POSTER_ART_ASPECT_RATIO,
422                PreviewProgramColumns.COLUMN_THUMBNAIL_ASPECT_RATIO,
423                PreviewProgramColumns.COLUMN_LOGO_URI,
424                PreviewProgramColumns.COLUMN_AVAILABILITY,
425                PreviewProgramColumns.COLUMN_STARTING_PRICE,
426                PreviewProgramColumns.COLUMN_OFFER_PRICE,
427                PreviewProgramColumns.COLUMN_RELEASE_DATE,
428                PreviewProgramColumns.COLUMN_ITEM_COUNT,
429                PreviewProgramColumns.COLUMN_LIVE,
430                PreviewProgramColumns.COLUMN_INTERACTION_TYPE,
431                PreviewProgramColumns.COLUMN_INTERACTION_COUNT,
432                PreviewProgramColumns.COLUMN_AUTHOR,
433                PreviewProgramColumns.COLUMN_BROWSABLE,
434                PreviewProgramColumns.COLUMN_CONTENT_ID,
435        };
436        return CollectionUtils.concatAll(BaseProgram.PROJECTION, oColumns);
437    }
438
439    /**
440     * This Builder class simplifies the creation of a {@link BasePreviewProgram} object.
441     *
442     * @param <T> The Builder of the derived classe.
443     */
444    public abstract static class Builder<T extends Builder> extends BaseProgram.Builder<T> {
445        private static final SimpleDateFormat sFormat =
446                new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
447
448        static {
449            sFormat.setTimeZone(TimeZone.getTimeZone("GMT-0"));
450        }
451
452        /**
453         * Creates a new Builder object.
454         */
455        public Builder() {
456        }
457
458        /**
459         * Creates a new Builder object with values copied from another Program.
460         * @param other The Program you're copying from.
461         */
462        public Builder(BasePreviewProgram other) {
463            mValues = new ContentValues(other.mValues);
464        }
465
466        /**
467         * Sets external ID for the program.
468         *
469         * @param externalId The internal provider ID for the program.
470         * @return This Builder object to allow for chaining of calls to builder methods.
471         * @see PreviewPrograms#COLUMN_INTERNAL_PROVIDER_ID
472         */
473        public T setInternalProviderId(String externalId) {
474            mValues.put(PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID, externalId);
475            return (T) this;
476        }
477
478        /**
479         * Sets a URI for the preview video.
480         *
481         * @param previewVideoUri The preview video URI for the program.
482         * @return This Builder object to allow for chaining of calls to builder methods.
483         * @see PreviewPrograms#COLUMN_PREVIEW_VIDEO_URI
484         */
485        public T setPreviewVideoUri(Uri previewVideoUri) {
486            mValues.put(PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI,
487                    previewVideoUri == null ? null : previewVideoUri.toString());
488            return (T) this;
489        }
490
491        /**
492         * Sets the last playback position (in milliseconds) of the preview video.
493         *
494         * @param position The last playback posirion for the program in millis.
495         * @return This Builder object to allow for chaining of calls to builder methods.
496         * @see PreviewPrograms#COLUMN_LAST_PLAYBACK_POSITION_MILLIS
497         */
498        public T setLastPlaybackPositionMillis(int position) {
499            mValues.put(PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, position);
500            return (T) this;
501        }
502
503        /**
504         * Sets the last playback duration (in milliseconds) of the preview video.
505         *
506         * @param duration The duration the program in millis.
507         * @return This Builder object to allow for chaining of calls to builder methods.
508         * @see PreviewPrograms#COLUMN_DURATION_MILLIS
509         */
510        public T setDurationMillis(int duration) {
511            mValues.put(PreviewPrograms.COLUMN_DURATION_MILLIS, duration);
512            return (T) this;
513        }
514
515        /**
516         * Sets the intent URI which is launched when the program is selected.
517         *
518         * @param intentUri The intent URI for the program.
519         * @return This Builder object to allow for chaining of calls to builder methods.
520         * @see PreviewPrograms#COLUMN_INTENT_URI
521         */
522        public T setIntentUri(Uri intentUri) {
523            mValues.put(PreviewPrograms.COLUMN_INTENT_URI,
524                    intentUri == null ? null : intentUri.toString());
525            return (T) this;
526        }
527
528        /**
529         * Sets the intent which is launched when the program is selected.
530         *
531         * @param intent The Intent to be executed when the preview program is selected
532         * @return This Builder object to allow for chaining of calls to builder methods.
533         */
534        public T setIntent(Intent intent) {
535            return setIntentUri(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
536        }
537
538        /**
539         * Sets whether this program is transient or not.
540         *
541         * @param transientValue Whether the program is transient or not.
542         * @return This Builder object to allow for chaining of calls to builder methods.
543         * @see PreviewPrograms#COLUMN_TRANSIENT
544         */
545        public T setTransient(boolean transientValue) {
546            mValues.put(PreviewPrograms.COLUMN_TRANSIENT, transientValue ? IS_TRANSIENT : 0);
547            return (T) this;
548        }
549
550        /**
551         * Sets the type of this program content.
552         *
553         * <p>The value should match one of the followings:
554         * {@link PreviewPrograms#TYPE_MOVIE},
555         * {@link PreviewPrograms#TYPE_TV_SERIES},
556         * {@link PreviewPrograms#TYPE_TV_SEASON},
557         * {@link PreviewPrograms#TYPE_TV_EPISODE},
558         * {@link PreviewPrograms#TYPE_CLIP},
559         * {@link PreviewPrograms#TYPE_EVENT},
560         * {@link PreviewPrograms#TYPE_CHANNEL},
561         * {@link PreviewPrograms#TYPE_TRACK},
562         * {@link PreviewPrograms#TYPE_ALBUM},
563         * {@link PreviewPrograms#TYPE_ARTIST},
564         * {@link PreviewPrograms#TYPE_PLAYLIST}, and
565         * {@link PreviewPrograms#TYPE_STATION}.
566         *
567         * @param type The type of the program.
568         * @return This Builder object to allow for chaining of calls to builder methods.
569         * @see PreviewPrograms#COLUMN_TYPE
570         */
571        public T setType(@Type int type) {
572            mValues.put(PreviewPrograms.COLUMN_TYPE, type);
573            return (T) this;
574        }
575
576        /**
577         * Sets the aspect ratio of the poster art for this TV program.
578         *
579         * <p>The value should match one of the followings:
580         * {@link PreviewPrograms#ASPECT_RATIO_16_9},
581         * {@link PreviewPrograms#ASPECT_RATIO_3_2},
582         * {@link PreviewPrograms#ASPECT_RATIO_4_3},
583         * {@link PreviewPrograms#ASPECT_RATIO_1_1}, and
584         * {@link PreviewPrograms#ASPECT_RATIO_2_3}.
585         *
586         * @param ratio The poster art aspect ratio for the program.
587         * @return This Builder object to allow for chaining of calls to builder methods.
588         * @see PreviewPrograms#COLUMN_POSTER_ART_ASPECT_RATIO
589         * @see PreviewPrograms#COLUMN_POSTER_ART_URI
590         */
591        public T setPosterArtAspectRatio(@AspectRatio int ratio) {
592            mValues.put(PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, ratio);
593            return (T) this;
594        }
595
596        /**
597         * Sets the aspect ratio of the thumbnail for this TV program.
598         *
599         * <p>The value should match one of the followings:
600         * {@link PreviewPrograms#ASPECT_RATIO_16_9},
601         * {@link PreviewPrograms#ASPECT_RATIO_3_2},
602         * {@link PreviewPrograms#ASPECT_RATIO_4_3},
603         * {@link PreviewPrograms#ASPECT_RATIO_1_1}, and
604         * {@link PreviewPrograms#ASPECT_RATIO_2_3}.
605         *
606         * @param ratio The thumbnail aspect ratio of the program.
607         * @return This Builder object to allow for chaining of calls to builder methods.
608         * @see PreviewPrograms#COLUMN_THUMBNAIL_ASPECT_RATIO
609         */
610        public T setThumbnailAspectRatio(@AspectRatio int ratio) {
611            mValues.put(PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, ratio);
612            return (T) this;
613        }
614
615        /**
616         * Sets the URI for the logo of this TV program.
617         *
618         * @param logoUri The logo URI for the program.
619         * @return This Builder object to allow for chaining of calls to builder methods.
620         * @see PreviewPrograms#COLUMN_LOGO_URI
621         */
622        public T setLogoUri(Uri logoUri) {
623            mValues.put(PreviewPrograms.COLUMN_LOGO_URI,
624                    logoUri == null ? null : logoUri.toString());
625            return (T) this;
626        }
627
628        /**
629         * Sets the availability of this TV program.
630         *
631         * <p>The value should match one of the followings:
632         * {@link PreviewPrograms#AVAILABILITY_AVAILABLE},
633         * {@link PreviewPrograms#AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
634         * {@link PreviewPrograms#AVAILABILITY_PAID_CONTENT}.
635         *
636         * @param availability The availability of the program.
637         * @return This Builder object to allow for chaining of calls to builder methods.
638         * @see PreviewPrograms#COLUMN_AVAILABILITY
639         */
640        public T setAvailability(@Availability int availability) {
641            mValues.put(PreviewPrograms.COLUMN_AVAILABILITY, availability);
642            return (T) this;
643        }
644
645        /**
646         * Sets the starting price of this TV program.
647         *
648         * @param price The starting price of the program.
649         * @return This Builder object to allow for chaining of calls to builder methods.
650         * @see PreviewPrograms#COLUMN_STARTING_PRICE
651         */
652        public T setStartingPrice(String price) {
653            mValues.put(PreviewPrograms.COLUMN_STARTING_PRICE, price);
654            return (T) this;
655        }
656
657        /**
658         * Sets the offer price of this TV program.
659         *
660         * @param price The offer price of the program.
661         * @return This Builder object to allow for chaining of calls to builder methods.
662         * @see PreviewPrograms#COLUMN_OFFER_PRICE
663         */
664        public T setOfferPrice(String price) {
665            mValues.put(PreviewPrograms.COLUMN_OFFER_PRICE, price);
666            return (T) this;
667        }
668
669        /**
670         * Sets the release date of this TV program.
671         *
672         * <p>The value should be in one of the following formats:
673         * "yyyy", "yyyy-MM-dd", and "yyyy-MM-ddTHH:mm:ssZ" (UTC in ISO 8601).
674         *
675         * @param releaseDate The release date of the program.
676         * @return This Builder object to allow for chaining of calls to builder methods.
677         * @see PreviewPrograms#COLUMN_RELEASE_DATE
678         */
679        public T setReleaseDate(String releaseDate) {
680            mValues.put(PreviewPrograms.COLUMN_RELEASE_DATE, releaseDate);
681            return (T) this;
682        }
683
684        /**
685         * Sets the release date of this TV program.
686         *
687         * @param releaseDate The release date of the program.
688         * @return This Builder object to allow for chaining of calls to builder methods.
689         * @see PreviewPrograms#COLUMN_RELEASE_DATE
690         */
691        public T setReleaseDate(Date releaseDate) {
692            mValues.put(PreviewPrograms.COLUMN_RELEASE_DATE, sFormat.format(releaseDate));
693            return (T) this;
694        }
695
696        /**
697         * Sets the count of the items included in this TV program.
698         *
699         * @param itemCount The item count for the program.
700         * @return This Builder object to allow for chaining of calls to builder methods.
701         * @see PreviewPrograms#COLUMN_ITEM_COUNT
702         */
703        public T setItemCount(int itemCount) {
704            mValues.put(PreviewPrograms.COLUMN_ITEM_COUNT, itemCount);
705            return (T) this;
706        }
707
708        /**
709         * Sets whether this TV program is live or not.
710         *
711         * @param live Whether the program is live or not.
712         * @return This Builder object to allow for chaining of calls to builder methods.
713         * @see PreviewPrograms#COLUMN_LIVE
714         */
715        public T setLive(boolean live) {
716            mValues.put(PreviewPrograms.COLUMN_LIVE, live ? IS_LIVE : 0);
717            return (T) this;
718        }
719
720        /**
721         * Sets the type of interaction for this TV program.
722         *
723         * <p> The value should match one of the followings:
724         * {@link PreviewPrograms#INTERACTION_TYPE_LISTENS},
725         * {@link PreviewPrograms#INTERACTION_TYPE_FOLLOWERS},
726         * {@link PreviewPrograms#INTERACTION_TYPE_FANS},
727         * {@link PreviewPrograms#INTERACTION_TYPE_LIKES},
728         * {@link PreviewPrograms#INTERACTION_TYPE_THUMBS},
729         * {@link PreviewPrograms#INTERACTION_TYPE_VIEWS}, and
730         * {@link PreviewPrograms#INTERACTION_TYPE_VIEWERS}.
731         *
732         * @param interactionType The interaction type of the program.
733         * @return This Builder object to allow for chaining of calls to builder methods.
734         * @see PreviewPrograms#COLUMN_INTERACTION_TYPE
735         */
736        public T setInteractionType(@InteractionType int interactionType) {
737            mValues.put(PreviewPrograms.COLUMN_INTERACTION_TYPE, interactionType);
738            return (T) this;
739        }
740
741        /**
742         * Sets the interaction count for this program.
743         *
744         * @param interactionCount The interaction count for the program.
745         * @return This Builder object to allow for chaining of calls to builder methods.
746         * @see PreviewPrograms#COLUMN_INTERACTION_COUNT
747         */
748        public T setInteractionCount(long interactionCount) {
749            mValues.put(PreviewPrograms.COLUMN_INTERACTION_COUNT, interactionCount);
750            return (T) this;
751        }
752
753        /**
754         * Sets the author or artist of this content.
755         *
756         * @param author The author of the program.
757         * @return This Builder object to allow for chaining of calls to builder methods.
758         * @see PreviewPrograms#COLUMN_AUTHOR
759         */
760        public T setAuthor(String author) {
761            mValues.put(PreviewPrograms.COLUMN_AUTHOR, author);
762            return (T) this;
763        }
764
765        /**
766         * Sets whether this TV program is browsable or not.
767         *
768         * @param browsable Whether the program is browsable or not.
769         * @return This Builder object to allow for chaining of calls to builder methods.
770         * @see PreviewPrograms#COLUMN_BROWSABLE
771         * @hide
772         */
773        @RestrictTo(LIBRARY_GROUP)
774        public T setBrowsable(boolean browsable) {
775            mValues.put(PreviewPrograms.COLUMN_BROWSABLE, browsable ? IS_BROWSABLE : 0);
776            return (T) this;
777        }
778
779        /**
780         * Sets the content ID for this program.
781         *
782         * @param contentId The content ID for the program.
783         * @return This Builder object to allow for chaining of calls to builder methods.
784         * @see PreviewPrograms#COLUMN_CONTENT_ID
785         */
786        public T setContentId(String contentId) {
787            mValues.put(PreviewPrograms.COLUMN_CONTENT_ID, contentId);
788            return (T) this;
789        }
790    }
791}
792