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.os.Build;
24import android.support.annotation.RestrictTo;
25import android.support.media.tv.TvContractCompat.PreviewPrograms;
26
27/**
28 * A convenience class to access {@link PreviewPrograms} entries in the system content
29 * provider.
30 *
31 * <p>This class makes it easy to insert or retrieve a preview program from the system content
32 * provider, which is defined in {@link TvContractCompat}.
33 *
34 * <p>Usage example when inserting a preview program:
35 * <pre>
36 * PreviewProgram previewProgram = new PreviewProgram.Builder()
37 *         .setChannelId(channel.getId())
38 *         .setType(PreviewPrograms.TYPE_MOVIE)
39 *         .setTitle("Program Title")
40 *         .setDescription("Program Description")
41 *         .setPosterArtUri(Uri.parse("http://example.com/poster_art.png"))
42 *         // Set more attributes...
43 *         .build();
44 * Uri previewProgramUri = getContentResolver().insert(PreviewPrograms.CONTENT_URI,
45 *         previewProgram.toContentValues());
46 * </pre>
47 *
48 * <p>Usage example when retrieving a preview program:
49 * <pre>
50 * PreviewProgram previewProgram;
51 * try (Cursor cursor = resolver.query(previewProgramUri, null, null, null, null)) {
52 *     if (cursor != null && cursor.getCount() != 0) {
53 *         cursor.moveToNext();
54 *         previewProgram = PreviewProgram.fromCursor(cursor);
55 *     }
56 * }
57 * </pre>
58 *
59 * <p>Usage example when updating an existing preview program:
60 * <pre>
61 * PreviewProgram updatedProgram = new PreviewProgram.Builder(previewProgram)
62 *         .setWeight(20)
63 *         .build();
64 * getContentResolver().update(TvContractCompat.buildPreviewProgramUri(updatedProgram.getId()),
65 *         updatedProgram.toContentValues(), null, null);
66 * </pre>
67 *
68 * <p>Usage example when deleting a preview program:
69 * <pre>
70 * getContentResolver().delete(TvContractCompat.buildPreviewProgramUri(existingProgram.getId()),
71 *         null, null);
72 * </pre>
73 */
74@TargetApi(26)
75public final class PreviewProgram extends BasePreviewProgram {
76    /**
77     * @hide
78     */
79    @RestrictTo(LIBRARY_GROUP)
80    public static final String[] PROJECTION = getProjection();
81
82    private static final long INVALID_LONG_VALUE = -1;
83    private static final int INVALID_INT_VALUE = -1;
84
85    private PreviewProgram(Builder builder) {
86        super(builder);
87    }
88
89    /**
90     * @return The value of {@link PreviewPrograms#COLUMN_CHANNEL_ID} for the program.
91     */
92    public long getChannelId() {
93        Long l = mValues.getAsLong(PreviewPrograms.COLUMN_CHANNEL_ID);
94        return l == null ? INVALID_LONG_VALUE : l;
95    }
96
97    /**
98     * @return The value of {@link PreviewPrograms#COLUMN_WEIGHT} for the program.
99     */
100    public int getWeight() {
101        Integer i = mValues.getAsInteger(PreviewPrograms.COLUMN_WEIGHT);
102        return i == null ? INVALID_INT_VALUE : i;
103    }
104
105    @Override
106    public boolean equals(Object other) {
107        if (!(other instanceof PreviewProgram)) {
108            return false;
109        }
110        return mValues.equals(((PreviewProgram) other).mValues);
111    }
112
113    @Override
114    public String toString() {
115        return "PreviewProgram{" + mValues.toString() + "}";
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 PreviewProgram 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 (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
139            values.remove(PreviewPrograms.COLUMN_CHANNEL_ID);
140            values.remove(PreviewPrograms.COLUMN_WEIGHT);
141        }
142        return values;
143    }
144
145    /**
146     * Creates a Program object from a cursor including the fields defined in
147     * {@link PreviewPrograms}.
148     *
149     * @param cursor A row from the TV Input Framework database.
150     * @return A Program with the values taken from the cursor.
151     */
152    public static PreviewProgram fromCursor(Cursor cursor) {
153        // TODO: Add additional API which does not use costly getColumnIndex().
154        Builder builder = new Builder();
155        BasePreviewProgram.setFieldsFromCursor(cursor, builder);
156        int index;
157        if ((index = cursor.getColumnIndex(PreviewPrograms.COLUMN_CHANNEL_ID)) >= 0
158                && !cursor.isNull(index)) {
159            builder.setChannelId(cursor.getLong(index));
160        }
161        if ((index = cursor.getColumnIndex(PreviewPrograms.COLUMN_WEIGHT)) >= 0
162                && !cursor.isNull(index)) {
163            builder.setWeight(cursor.getInt(index));
164        }
165        return builder.build();
166    }
167
168    private static String[] getProjection() {
169        String[] oColumns = new String[] {
170                PreviewPrograms.COLUMN_CHANNEL_ID,
171                PreviewPrograms.COLUMN_WEIGHT,
172        };
173        return CollectionUtils.concatAll(BasePreviewProgram.PROJECTION, oColumns);
174    }
175
176    /**
177     * This Builder class simplifies the creation of a {@link PreviewProgram} object.
178     */
179    public static final class Builder extends BasePreviewProgram.Builder<Builder> {
180
181        /**
182         * Creates a new Builder object.
183         */
184        public Builder() {
185        }
186
187        /**
188         * Creates a new Builder object with values copied from another Program.
189         * @param other The Program you're copying from.
190         */
191        public Builder(PreviewProgram other) {
192            mValues = new ContentValues(other.mValues);
193        }
194
195        /**
196         * Sets the ID of the {@link Channel} that contains this program.
197         *
198         * @param channelId The value of {@link PreviewPrograms#COLUMN_CHANNEL_ID for the program.
199         * @return This Builder object to allow for chaining of calls to builder methods.
200         */
201        public Builder setChannelId(long channelId) {
202            mValues.put(PreviewPrograms.COLUMN_CHANNEL_ID, channelId);
203            return this;
204        }
205
206        /**
207         * Sets the weight of the preview program within the channel.
208         *
209         * @param weight The value of {@link PreviewPrograms#COLUMN_WEIGHT} for the program.
210         * @return This Builder object to allow for chaining of calls to builder methods.
211         */
212        public Builder setWeight(int weight) {
213            mValues.put(PreviewPrograms.COLUMN_WEIGHT, weight);
214            return this;
215        }
216
217        /**
218         * @return A new Program with values supplied by the Builder.
219         */
220        public PreviewProgram build() {
221            return new PreviewProgram(this);
222        }
223    }
224}
225