WatchNextProgram.java revision 98ec0d5b378c8417156037af6389e90f0074a26e
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.database.Cursor;
23import android.support.annotation.RestrictTo;
24import android.support.media.tv.TvContractCompat.WatchNextPrograms;
25import android.support.media.tv.TvContractCompat.WatchNextPrograms.WatchNextType;
26import android.text.TextUtils;
27
28import java.util.Objects;
29
30/**
31 * A convenience class to access {@link WatchNextPrograms} entries in the system content
32 * provider.
33 *
34 * <p>This class makes it easy to insert or retrieve a program from the system content provider,
35 * which is defined in {@link TvContractCompat}.
36 *
37 * <p>Usage example when inserting a "watch next" program:
38 * <pre>
39 * WatchNextProgram watchNextProgram = new WatchNextProgram.Builder()
40 *         .setWatchNextType(WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
41 *         .setType(PreviewPrograms.TYPE_MOVIE)
42 *         .setTitle("Program Title")
43 *         .setDescription("Program Description")
44 *         .setPosterArtUri(Uri.parse("http://example.com/poster_art.png"))
45 *         // Set more attributes...
46 *         .build();
47 * Uri watchNextProgramUri = getContentResolver().insert(WatchNextPrograms.CONTENT_URI,
48 *         watchNextProgram.toContentValues());
49 * </pre>
50 *
51 * <p>Usage example when retrieving a "watch next" program:
52 * <pre>
53 * WatchNextProgram watchNextProgram;
54 * try (Cursor cursor = resolver.query(watchNextProgramUri, null, null, null, null)) {
55 *     if (cursor != null && cursor.getCount() != 0) {
56 *         cursor.moveToNext();
57 *         watchNextProgram = WatchNextProgram.fromCursor(cursor);
58 *     }
59 * }
60 * </pre>
61 */
62@TargetApi(26)
63public final class WatchNextProgram extends BasePreviewProgram {
64    /**
65     * @hide
66     */
67    @RestrictTo(LIBRARY_GROUP)
68    public static final String[] PROJECTION = getProjection();
69
70    private static final long INVALID_LONG_VALUE = -1;
71    private static final int INVALID_INT_VALUE = -1;
72
73    private final String mWatchNextType;
74    private final long mLastEngagementTimeUtcMillis;
75
76    private WatchNextProgram(Builder builder) {
77        super(builder);
78        mWatchNextType = builder.mWatchNextType;
79        mLastEngagementTimeUtcMillis = builder.mLastEngagementTimeUtcMillis;
80    }
81
82    /**
83     * @return The value of {@link WatchNextPrograms#COLUMN_WATCH_NEXT_TYPE} for the program.
84     */
85    public @WatchNextType String getWatchNextType() {
86        return mWatchNextType;
87    }
88
89    /**
90     * @return The value of {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS} for the
91     * program.
92     */
93    public long getLastEngagementTimeUtcMillis() {
94        return mLastEngagementTimeUtcMillis;
95    }
96
97    @Override
98    public boolean equals(Object other) {
99        if (!(other instanceof WatchNextProgram)) {
100            return false;
101        }
102        if (!super.equals(other)) {
103            return false;
104        }
105        WatchNextProgram program = (WatchNextProgram) other;
106        return Objects.equals(mWatchNextType, program.mWatchNextType)
107                && mLastEngagementTimeUtcMillis == program.mLastEngagementTimeUtcMillis;
108    }
109
110    @Override
111    public String toString() {
112        return "Program{"
113                + ", watchNextType=" + mWatchNextType
114                + ", lastEngagementTimeUtcMillis=" + mLastEngagementTimeUtcMillis
115                + "}";
116    }
117
118    /**
119     * @return The fields of the Program in the ContentValues format to be easily inserted into the
120     * TV Input Framework database.
121     */
122    @Override
123    public ContentValues toContentValues() {
124        return toContentValues(false);
125    }
126
127    /**
128     * Returns fields of the WatchNextProgram in the ContentValues format to be easily inserted
129     * into the TV Input Framework database.
130     *
131     * @param includeProtectedFields Whether the fields protected by system is included or not.
132     * @hide
133     */
134    @RestrictTo(LIBRARY_GROUP)
135    @Override
136    public ContentValues toContentValues(boolean includeProtectedFields) {
137        ContentValues values = super.toContentValues(includeProtectedFields);
138        if (!TextUtils.isEmpty(mWatchNextType)) {
139            values.put(WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE, mWatchNextType);
140        }
141        if (mLastEngagementTimeUtcMillis != INVALID_LONG_VALUE) {
142            values.put(WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
143                    mLastEngagementTimeUtcMillis);
144        }
145        return values;
146    }
147
148    /**
149     * Creates a WatchNextProgram object from a cursor including the fields defined in
150     * {@link WatchNextPrograms}.
151     *
152     * @param cursor A row from the TV Input Framework database.
153     * @return A Program with the values taken from the cursor.
154     */
155    public static WatchNextProgram fromCursor(Cursor cursor) {
156        // TODO: Add additional API which does not use costly getColumnIndex().
157        Builder builder = new Builder();
158        BasePreviewProgram.setFieldsFromCursor(cursor, builder);
159        int index;
160        if ((index = cursor.getColumnIndex(WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE)) >= 0
161                && !cursor.isNull(index)) {
162            builder.setWatchNextType(cursor.getString(index));
163        }
164        if ((index = cursor.getColumnIndex(
165                WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS)) >= 0
166                && !cursor.isNull(index)) {
167            builder.setLastEngagementTimeUtcMillis(cursor.getLong(index));
168        }
169        return builder.build();
170    }
171
172    private static String[] getProjection() {
173        String[] oColumns = new String[] {
174                WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE,
175                WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
176        };
177        return CollectionUtils.concatAll(BasePreviewProgram.PROJECTION, oColumns);
178    }
179
180    /**
181     * This Builder class simplifies the creation of a {@link WatchNextProgram} object.
182     */
183    public static final class Builder extends BasePreviewProgram.Builder<Builder> {
184        private String mWatchNextType;
185        private long mLastEngagementTimeUtcMillis = INVALID_LONG_VALUE;
186
187        /**
188         * Creates a new Builder object.
189         */
190        public Builder() {
191        }
192
193        /**
194         * Creates a new Builder object with values copied from another Program.
195         * @param other The Program you're copying from.
196         */
197        public Builder(WatchNextProgram other) {
198            super(other);
199            mWatchNextType = other.mWatchNextType;
200            mLastEngagementTimeUtcMillis = other.mLastEngagementTimeUtcMillis;
201        }
202
203        /**
204         * Sets the "watch next" type of this program content.
205         *
206         * <p>The value should match one of the followings:
207         * {@link WatchNextPrograms#WATCH_NEXT_TYPE_CONTINUE},
208         * {@link WatchNextPrograms#WATCH_NEXT_TYPE_NEXT}, and
209         * {@link WatchNextPrograms#WATCH_NEXT_TYPE_NEW}.
210         *
211         * @param watchNextType The value of {@link WatchNextPrograms#COLUMN_WATCH_NEXT_TYPE} for
212         *                      the program.
213         * @return This Builder object to allow for chaining of calls to builder methods.
214         */
215        public Builder setWatchNextType(@WatchNextType String watchNextType) {
216            mWatchNextType = watchNextType;
217            return this;
218        }
219
220        /**
221         * Sets the time when the program is going to begin in milliseconds since the epoch.
222         *
223         * @param lastEngagementTimeUtcMillis The value of
224         * {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS} for the program.
225         * @return This Builder object to allow for chaining of calls to builder methods.
226         */
227        public Builder setLastEngagementTimeUtcMillis(long lastEngagementTimeUtcMillis) {
228            mLastEngagementTimeUtcMillis = lastEngagementTimeUtcMillis;
229            return this;
230        }
231
232        /**
233         * @return A new Program with values supplied by the Builder.
234         */
235        public WatchNextProgram build() {
236            return new WatchNextProgram(this);
237        }
238    }
239}
240