1/*
2 * Copyright (C) 2014 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 */
16
17package android.media.tv;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.SdkConstant;
23import android.annotation.StringDef;
24import android.annotation.SystemApi;
25import android.annotation.SdkConstant.SdkConstantType;
26import android.app.Activity;
27import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.ContentUris;
30import android.content.Context;
31import android.content.Intent;
32import android.net.Uri;
33import android.os.Bundle;
34import android.os.IBinder;
35import android.provider.BaseColumns;
36import android.text.TextUtils;
37import android.util.ArraySet;
38
39import java.lang.annotation.Retention;
40import java.lang.annotation.RetentionPolicy;
41import java.util.ArrayList;
42import java.util.HashMap;
43import java.util.List;
44import java.util.Map;
45
46/**
47 * The contract between the TV provider and applications. Contains definitions for the supported
48 * URIs and columns.
49 * <h3>Overview</h3>
50 *
51 * <p>TvContract defines a basic database of TV content metadata such as channel and program
52 * information. The information is stored in {@link Channels} and {@link Programs} tables.
53 *
54 * <ul>
55 *     <li>A row in the {@link Channels} table represents information about a TV channel. The data
56 *         format can vary greatly from standard to standard or according to service provider, thus
57 *         the columns here are mostly comprised of basic entities that are usually seen to users
58 *         regardless of standard such as channel number and name.</li>
59 *     <li>A row in the {@link Programs} table represents a set of data describing a TV program such
60 *         as program title and start time.</li>
61 * </ul>
62 */
63public final class TvContract {
64    /** The authority for the TV provider. */
65    public static final String AUTHORITY = "android.media.tv";
66
67    /**
68     * Permission to read TV listings. This is required to read all the TV channel and program
69     * information available on the system.
70     * @hide
71     */
72    public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
73
74    private static final String PATH_CHANNEL = "channel";
75    private static final String PATH_PROGRAM = "program";
76    private static final String PATH_RECORDED_PROGRAM = "recorded_program";
77    private static final String PATH_PREVIEW_PROGRAM = "preview_program";
78    private static final String PATH_WATCH_NEXT_PROGRAM = "watch_next_program";
79    private static final String PATH_PASSTHROUGH = "passthrough";
80
81    /**
82     * Broadcast Action: sent when an application requests the system to make the given channel
83     * browsable.  The operation is performed in the background without user interaction. This
84     * is only relevant to channels with {@link Channels#TYPE_PREVIEW} type.
85     *
86     * <p>The intent must contain the following bundle parameters:
87     * <ul>
88     *     <li>{@link #EXTRA_CHANNEL_ID}: ID for the {@link Channels#TYPE_PREVIEW} channel as a long
89     *     integer.</li>
90     *     <li>{@link #EXTRA_PACKAGE_NAME}: the package name of the requesting application.</li>
91     * </ul>
92     * @hide
93     */
94    @SystemApi
95    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
96    public static final String ACTION_CHANNEL_BROWSABLE_REQUESTED =
97            "android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED";
98
99    /**
100     * Activity Action: sent by an application telling the system to make the given channel
101     * browsable with user interaction. The system may show UI to ask user to approve the channel.
102     * This is only relevant to channels with {@link Channels#TYPE_PREVIEW} type. Use
103     * {@link Activity#startActivityForResult} to get the result of the request.
104     *
105     * <p>The intent must contain the following bundle parameters:
106     * <ul>
107     *     <li>{@link #EXTRA_CHANNEL_ID}: ID for the {@link Channels#TYPE_PREVIEW} channel as a long
108     *     integer.</li>
109     * </ul>
110     */
111    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
112    public static final String ACTION_REQUEST_CHANNEL_BROWSABLE =
113            "android.media.tv.action.REQUEST_CHANNEL_BROWSABLE";
114
115    /**
116     * Broadcast Action: sent by the system to tell the target TV input that one of its preview
117     * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
118     * example, might be a result of users' interaction with UI. The input is expected to delete the
119     * preview program from the content provider.
120     *
121     * <p>The intent must contain the following bundle parameter:
122     * <ul>
123     *     <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the disabled preview program ID.</li>
124     * </ul>
125     */
126    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
127    public static final String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED =
128            "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
129
130    /**
131     * Broadcast Action: sent by the system to tell the target TV input that one of its "watch next"
132     * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
133     * example, might be a result of users' interaction with UI. The input is expected to delete the
134     * "watch next" program from the content provider.
135     *
136     * <p>The intent must contain the following bundle parameter:
137     * <ul>
138     *     <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the disabled "watch next" program ID.</li>
139     * </ul>
140     */
141    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
142    public static final String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED =
143            "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
144
145    /**
146     * Broadcast Action: sent by the system to tell the target TV input that one of its existing
147     * preview programs is added to the watch next programs table by user.
148     *
149     * <p>The intent must contain the following bundle parameters:
150     * <ul>
151     *     <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the ID of the existing preview program.</li>
152     *     <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the ID of the new watch next program.</li>
153     * </ul>
154     */
155    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
156    public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT =
157            "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
158
159    /**
160     * Broadcast Action: sent to the target TV input after it is first installed to notify the input
161     * to initialize its channels and programs to the system content provider.
162     *
163     * <p>Note that this intent is sent only on devices with
164     * {@link android.content.pm.PackageManager#FEATURE_LEANBACK} enabled. Besides that, in order
165     * to receive this intent, the target TV input must:
166     * <ul>
167     *     <li>Declare a broadcast receiver for this intent in its
168     *         <code>AndroidManifest.xml</code>.</li>
169     *     <li>Declare appropriate permissions to write channel and program data in its
170     *         <code>AndroidManifest.xml</code>.</li>
171     * </ul>
172     */
173    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
174    public static final String ACTION_INITIALIZE_PROGRAMS =
175            "android.media.tv.action.INITIALIZE_PROGRAMS";
176
177    /**
178     * The key for a bundle parameter containing a channel ID as a long integer
179     */
180    public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
181
182    /**
183     * The key for a bundle parameter containing a package name as a string.
184     * @hide
185     */
186    @SystemApi
187    public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
188
189    /** The key for a bundle parameter containing a program ID as a long integer. */
190    public static final String EXTRA_PREVIEW_PROGRAM_ID =
191            "android.media.tv.extra.PREVIEW_PROGRAM_ID";
192
193    /** The key for a bundle parameter containing a watch next program ID as a long integer. */
194    public static final String EXTRA_WATCH_NEXT_PROGRAM_ID =
195            "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
196
197    /**
198     * The key for a bundle parameter containing the result code of a method call as an integer.
199     *
200     * @see #RESULT_OK
201     * @see #RESULT_ERROR_IO
202     * @see #RESULT_ERROR_INVALID_ARGUMENT
203     * @hide
204     */
205    @SystemApi
206    public static final String EXTRA_RESULT_CODE = "android.media.tv.extra.RESULT_CODE";
207
208    /**
209     * The result code for a successful execution without error.
210     * @hide
211     */
212    @SystemApi
213    public static final int RESULT_OK = 0;
214
215    /**
216     * The result code for a failure from I/O operation.
217     * @hide
218     */
219    @SystemApi
220    public static final int RESULT_ERROR_IO = 1;
221
222    /**
223     * The result code for a failure from invalid argument.
224     * @hide
225     */
226    @SystemApi
227    public static final int RESULT_ERROR_INVALID_ARGUMENT = 2;
228
229    /**
230     * The method name to get existing columns in the given table of the specified content provider.
231     *
232     * <p>The method caller must provide the following parameter:
233     * <ul>
234     *     <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
235     * </ul>
236
237     * <p>On success, the returned {@link android.os.Bundle} will include existing column names
238     * with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the return value will be {@code null}.
239     *
240     * @see ContentResolver#call(Uri, String, String, Bundle)
241     * @see #EXTRA_EXISTING_COLUMN_NAMES
242     * @hide
243     */
244    @SystemApi
245    public static final String METHOD_GET_COLUMNS = "get_columns";
246
247    /**
248     * The method name to add a new column in the given table of the specified content provider.
249     *
250     * <p>The method caller must provide the following parameter:
251     * <ul>
252     *     <li>{@code arg}: The content URI of the target table as a {@link String}.</li>
253     *     <li>{@code extra}: Name, data type, and default value of the new column in a Bundle:
254     *         <ul>
255     *             <li>{@link #EXTRA_COLUMN_NAME} the column name as a {@link String}.</li>
256     *             <li>{@link #EXTRA_DATA_TYPE} the data type as a {@link String}.</li>
257     *             <li>{@link #EXTRA_DEFAULT_VALUE} the default value as a {@link String}.
258     *                 (optional)</li>
259     *         </ul>
260     *     </li>
261     * </ul>
262     *
263     * <p>On success, the returned {@link android.os.Bundle} will include current colum names after
264     * the addition operation with the key {@link #EXTRA_EXISTING_COLUMN_NAMES}. Otherwise, the
265     * return value will be {@code null}.
266     *
267     * @see ContentResolver#call(Uri, String, String, Bundle)
268     * @see #EXTRA_COLUMN_NAME
269     * @see #EXTRA_DATA_TYPE
270     * @see #EXTRA_DEFAULT_VALUE
271     * @see #EXTRA_EXISTING_COLUMN_NAMES
272     * @hide
273     */
274    @SystemApi
275    public static final String METHOD_ADD_COLUMN = "add_column";
276
277    /**
278     * The method name to get all the blocked packages. When a package is blocked, all the data for
279     * preview programs/channels and watch next programs belonging to this package in the content
280     * provider will be cleared. Once a package is blocked, {@link SecurityException} will be thrown
281     * for all the requests to preview programs/channels and watch next programs via
282     * {@link android.content.ContentProvider} from it.
283     *
284     * <p>The returned {@link android.os.Bundle} will include all the blocked package names with the
285     * key {@link #EXTRA_BLOCKED_PACKAGES}.
286     *
287     * @see ContentResolver#call(Uri, String, String, Bundle)
288     * @see #EXTRA_BLOCKED_PACKAGES
289     * @see #METHOD_BLOCK_PACKAGE
290     * @see #METHOD_UNBLOCK_PACKAGE
291     * @hide
292     */
293    @SystemApi
294    public static final String METHOD_GET_BLOCKED_PACKAGES = "get_blocked_packages";
295
296    /**
297     * The method name to block the access from the given package. When a package is blocked, all
298     * the data for preview programs/channels and watch next programs belonging to this package in
299     * the content provider will be cleared. Once a package is blocked, {@link SecurityException}
300     * will be thrown for all the requests to preview programs/channels and watch next programs via
301     * {@link android.content.ContentProvider} from it.
302     *
303     * <p>The method caller must provide the following parameter:
304     * <ul>
305     *     <li>{@code arg}: The package name to be added as blocked package {@link String}.</li>
306     * </ul>
307     *
308     * <p>The returned {@link android.os.Bundle} will include an integer code denoting whether the
309     * execution is successful or not with the key {@link #EXTRA_RESULT_CODE}. If {@code arg} is
310     * empty, the result code will be {@link #RESULT_ERROR_INVALID_ARGUMENT}. If success, the result
311     * code will be {@link #RESULT_OK}. Otherwise, the result code will be {@link #RESULT_ERROR_IO}.
312     *
313     * @see ContentResolver#call(Uri, String, String, Bundle)
314     * @see #EXTRA_RESULT_CODE
315     * @see #METHOD_GET_BLOCKED_PACKAGES
316     * @see #METHOD_UNBLOCK_PACKAGE
317     * @hide
318     */
319    @SystemApi
320    public static final String METHOD_BLOCK_PACKAGE = "block_package";
321
322    /**
323     * The method name to unblock the access from the given package. When a package is blocked, all
324     * the data for preview programs/channels and watch next programs belonging to this package in
325     * the content provider will be cleared. Once a package is blocked, {@link SecurityException}
326     * will be thrown for all the requests to preview programs/channels and watch next programs via
327     * {@link android.content.ContentProvider} from it.
328     *
329     * <p>The method caller must provide the following parameter:
330     * <ul>
331     *     <li>{@code arg}: The package name to be removed from blocked list as a {@link String}.
332     *     </li>
333     * </ul>
334     *
335     * <p>The returned {@link android.os.Bundle} will include an integer code denoting whether the
336     * execution is successful or not with the key {@link #EXTRA_RESULT_CODE}. If {@code arg} is
337     * empty, the result code will be {@link #RESULT_ERROR_INVALID_ARGUMENT}. If success, the result
338     * code will be {@link #RESULT_OK}. Otherwise, the result code will be {@link #RESULT_ERROR_IO}.
339     *
340     * @see ContentResolver#call(Uri, String, String, Bundle)
341     * @see #EXTRA_RESULT_CODE
342     * @see #METHOD_GET_BLOCKED_PACKAGES
343     * @see #METHOD_BLOCK_PACKAGE
344     * @hide
345     */
346    @SystemApi
347    public static final String METHOD_UNBLOCK_PACKAGE = "unblock_package";
348
349    /**
350     * The key for a returned {@link Bundle} value containing existing column names in the given
351     * table as an {@link ArrayList} of {@link String}.
352     *
353     * @see #METHOD_GET_COLUMNS
354     * @see #METHOD_ADD_COLUMN
355     * @hide
356     */
357    @SystemApi
358    public static final String EXTRA_EXISTING_COLUMN_NAMES =
359            "android.media.tv.extra.EXISTING_COLUMN_NAMES";
360
361    /**
362     * The key for a {@link Bundle} parameter containing the new column name to be added in the
363     * given table as a non-empty {@link CharSequence}.
364     *
365     * @see #METHOD_ADD_COLUMN
366     * @hide
367     */
368    @SystemApi
369    public static final String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
370
371    /**
372     * The key for a {@link Bundle} parameter containing the data type of the new column to be added
373     * in the given table as a non-empty {@link CharSequence}, which should be one of the following
374     * values: {@code "TEXT"}, {@code "INTEGER"}, {@code "REAL"}, or {@code "BLOB"}.
375     *
376     * @see #METHOD_ADD_COLUMN
377     * @hide
378     */
379    @SystemApi
380    public static final String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
381
382    /**
383     * The key for a {@link Bundle} parameter containing the default value of the new column to be
384     * added in the given table as a {@link CharSequence}, which represents a valid default value
385     * according to the data type provided with {@link #EXTRA_DATA_TYPE}.
386     *
387     * @see #METHOD_ADD_COLUMN
388     * @hide
389     */
390    @SystemApi
391    public static final String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
392
393    /**
394     * The key for a returned {@link Bundle} value containing all the blocked package names as an
395     * {@link ArrayList} of {@link String}.
396     *
397     * @see #METHOD_GET_BLOCKED_PACKAGES
398     * @hide
399     */
400    @SystemApi
401    public static final String EXTRA_BLOCKED_PACKAGES = "android.media.tv.extra.BLOCKED_PACKAGES";
402
403    /**
404     * An optional query, update or delete URI parameter that allows the caller to specify TV input
405     * ID to filter channels.
406     * @hide
407     */
408    public static final String PARAM_INPUT = "input";
409
410    /**
411     * An optional query, update or delete URI parameter that allows the caller to specify channel
412     * ID to filter programs.
413     * @hide
414     */
415    public static final String PARAM_CHANNEL = "channel";
416
417    /**
418     * An optional query, update or delete URI parameter that allows the caller to specify start
419     * time (in milliseconds since the epoch) to filter programs.
420     * @hide
421     */
422    public static final String PARAM_START_TIME = "start_time";
423
424    /**
425     * An optional query, update or delete URI parameter that allows the caller to specify end time
426     * (in milliseconds since the epoch) to filter programs.
427     * @hide
428     */
429    public static final String PARAM_END_TIME = "end_time";
430
431    /**
432     * A query, update or delete URI parameter that allows the caller to operate on all or
433     * browsable-only channels. If set to "true", the rows that contain non-browsable channels are
434     * not affected.
435     * @hide
436     */
437    public static final String PARAM_BROWSABLE_ONLY = "browsable_only";
438
439    /**
440     * An optional query, update or delete URI parameter that allows the caller to specify canonical
441     * genre to filter programs.
442     * @hide
443     */
444    public static final String PARAM_CANONICAL_GENRE = "canonical_genre";
445
446    /**
447     * A query, update or delete URI parameter that allows the caller to operate only on preview or
448     * non-preview channels. If set to "true", the operation affects the rows for preview channels
449     * only. If set to "false", the operation affects the rows for non-preview channels only.
450     * @hide
451     */
452    public static final String PARAM_PREVIEW = "preview";
453
454    /**
455     * An optional query, update or delete URI parameter that allows the caller to specify package
456     * name to filter channels.
457     * @hide
458     */
459    public static final String PARAM_PACKAGE = "package";
460
461    /**
462     * Builds an ID that uniquely identifies a TV input service.
463     *
464     * @param name The {@link ComponentName} of the TV input service to build ID for.
465     * @return the ID for the given TV input service.
466     */
467    public static String buildInputId(ComponentName name) {
468        return name.flattenToShortString();
469    }
470
471    /**
472     * Builds a URI that points to a specific channel.
473     *
474     * @param channelId The ID of the channel to point to.
475     */
476    public static Uri buildChannelUri(long channelId) {
477        return ContentUris.withAppendedId(Channels.CONTENT_URI, channelId);
478    }
479
480    /**
481     * Build a special channel URI intended to be used with pass-through inputs. (e.g. HDMI)
482     *
483     * @param inputId The ID of the pass-through input to build a channels URI for.
484     * @see TvInputInfo#isPassthroughInput()
485     */
486    public static Uri buildChannelUriForPassthroughInput(String inputId) {
487        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
488                .appendPath(PATH_PASSTHROUGH).appendPath(inputId).build();
489    }
490
491    /**
492     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
493     *
494     * @param channelId The ID of the channel whose logo is pointed to.
495     */
496    public static Uri buildChannelLogoUri(long channelId) {
497        return buildChannelLogoUri(buildChannelUri(channelId));
498    }
499
500    /**
501     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
502     *
503     * @param channelUri The URI of the channel whose logo is pointed to.
504     */
505    public static Uri buildChannelLogoUri(Uri channelUri) {
506        if (!isChannelUriForTunerInput(channelUri)) {
507            throw new IllegalArgumentException("Not a channel: " + channelUri);
508        }
509        return Uri.withAppendedPath(channelUri, Channels.Logo.CONTENT_DIRECTORY);
510    }
511
512    /**
513     * Builds a URI that points to all channels from a given TV input.
514     *
515     * @param inputId The ID of the TV input to build a channels URI for. If {@code null}, builds a
516     *            URI for all the TV inputs.
517     */
518    public static Uri buildChannelsUriForInput(@Nullable String inputId) {
519        return buildChannelsUriForInput(inputId, false);
520    }
521
522    /**
523     * Builds a URI that points to all or browsable-only channels from a given TV input.
524     *
525     * @param inputId The ID of the TV input to build a channels URI for. If {@code null}, builds a
526     *            URI for all the TV inputs.
527     * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set
528     *            to {@code false} the URI points to all channels regardless of whether they are
529     *            browsable or not.
530     * @hide
531     */
532    @SystemApi
533    public static Uri buildChannelsUriForInput(@Nullable String inputId,
534            boolean browsableOnly) {
535        Uri.Builder builder = Channels.CONTENT_URI.buildUpon();
536        if (inputId != null) {
537            builder.appendQueryParameter(PARAM_INPUT, inputId);
538        }
539        return builder.appendQueryParameter(PARAM_BROWSABLE_ONLY, String.valueOf(browsableOnly))
540                .build();
541    }
542
543    /**
544     * Builds a URI that points to all or browsable-only channels which have programs with the given
545     * genre from the given TV input.
546     *
547     * @param inputId The ID of the TV input to build a channels URI for. If {@code null}, builds a
548     *            URI for all the TV inputs.
549     * @param genre {@link Programs.Genres} to search. If {@code null}, builds a URI for all genres.
550     * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set
551     *            to {@code false} the URI points to all channels regardless of whether they are
552     *            browsable or not.
553     * @hide
554     */
555    @SystemApi
556    public static Uri buildChannelsUriForInput(@Nullable String inputId,
557            @Nullable String genre, boolean browsableOnly) {
558        if (genre == null) {
559            return buildChannelsUriForInput(inputId, browsableOnly);
560        }
561        if (!Programs.Genres.isCanonical(genre)) {
562            throw new IllegalArgumentException("Not a canonical genre: '" + genre + "'");
563        }
564        return buildChannelsUriForInput(inputId, browsableOnly).buildUpon()
565                .appendQueryParameter(PARAM_CANONICAL_GENRE, genre).build();
566    }
567
568    /**
569     * Builds a URI that points to a specific program.
570     *
571     * @param programId The ID of the program to point to.
572     */
573    public static Uri buildProgramUri(long programId) {
574        return ContentUris.withAppendedId(Programs.CONTENT_URI, programId);
575    }
576
577    /**
578     * Builds a URI that points to all programs on a given channel.
579     *
580     * @param channelId The ID of the channel to return programs for.
581     */
582    public static Uri buildProgramsUriForChannel(long channelId) {
583        return Programs.CONTENT_URI.buildUpon()
584                .appendQueryParameter(PARAM_CHANNEL, String.valueOf(channelId)).build();
585    }
586
587    /**
588     * Builds a URI that points to all programs on a given channel.
589     *
590     * @param channelUri The URI of the channel to return programs for.
591     */
592    public static Uri buildProgramsUriForChannel(Uri channelUri) {
593        if (!isChannelUriForTunerInput(channelUri)) {
594            throw new IllegalArgumentException("Not a channel: " + channelUri);
595        }
596        return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
597    }
598
599    /**
600     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
601     * given time frame.
602     *
603     * @param channelId The ID of the channel to return programs for.
604     * @param startTime The start time used to filter programs. The returned programs should have
605     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
606     * @param endTime The end time used to filter programs. The returned programs should have
607     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
608     */
609    public static Uri buildProgramsUriForChannel(long channelId, long startTime,
610            long endTime) {
611        Uri uri = buildProgramsUriForChannel(channelId);
612        return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
613                .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
614    }
615
616    /**
617     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
618     * given time frame.
619     *
620     * @param channelUri The URI of the channel to return programs for.
621     * @param startTime The start time used to filter programs. The returned programs should have
622     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
623     * @param endTime The end time used to filter programs. The returned programs should have
624     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
625     */
626    public static Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
627            long endTime) {
628        if (!isChannelUriForTunerInput(channelUri)) {
629            throw new IllegalArgumentException("Not a channel: " + channelUri);
630        }
631        return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
632    }
633
634    /**
635     * Builds a URI that points to a specific recorded program.
636     *
637     * @param recordedProgramId The ID of the recorded program to point to.
638     */
639    public static Uri buildRecordedProgramUri(long recordedProgramId) {
640        return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, recordedProgramId);
641    }
642
643    /**
644     * Builds a URI that points to a specific preview program.
645     *
646     * @param previewProgramId The ID of the preview program to point to.
647     */
648    public static Uri buildPreviewProgramUri(long previewProgramId) {
649        return ContentUris.withAppendedId(PreviewPrograms.CONTENT_URI, previewProgramId);
650    }
651
652    /**
653     * Builds a URI that points to all preview programs on a given channel.
654     *
655     * @param channelId The ID of the channel to return preview programs for.
656     */
657    public static Uri buildPreviewProgramsUriForChannel(long channelId) {
658        return PreviewPrograms.CONTENT_URI.buildUpon()
659                .appendQueryParameter(PARAM_CHANNEL, String.valueOf(channelId)).build();
660    }
661
662    /**
663     * Builds a URI that points to all preview programs on a given channel.
664     *
665     * @param channelUri The URI of the channel to return preview programs for.
666     */
667    public static Uri buildPreviewProgramsUriForChannel(Uri channelUri) {
668        if (!isChannelUriForTunerInput(channelUri)) {
669            throw new IllegalArgumentException("Not a channel: " + channelUri);
670        }
671        return buildPreviewProgramsUriForChannel(ContentUris.parseId(channelUri));
672    }
673
674    /**
675     * Builds a URI that points to a specific watch next program.
676     *
677     * @param watchNextProgramId The ID of the watch next program to point to.
678     */
679    public static Uri buildWatchNextProgramUri(long watchNextProgramId) {
680        return ContentUris.withAppendedId(WatchNextPrograms.CONTENT_URI, watchNextProgramId);
681    }
682
683    /**
684     * Builds a URI that points to a specific program the user watched.
685     *
686     * @param watchedProgramId The ID of the watched program to point to.
687     * @hide
688     */
689    public static Uri buildWatchedProgramUri(long watchedProgramId) {
690        return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId);
691    }
692
693    private static boolean isTvUri(Uri uri) {
694        return uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())
695                && AUTHORITY.equals(uri.getAuthority());
696    }
697
698    private static boolean isTwoSegmentUriStartingWith(Uri uri, String pathSegment) {
699        List<String> pathSegments = uri.getPathSegments();
700        return pathSegments.size() == 2 && pathSegment.equals(pathSegments.get(0));
701    }
702
703    /**
704     * Returns {@code true}, if {@code uri} is a channel URI.
705     */
706    public static boolean isChannelUri(Uri uri) {
707        return isChannelUriForTunerInput(uri) || isChannelUriForPassthroughInput(uri);
708    }
709
710    /**
711     * Returns {@code true}, if {@code uri} is a channel URI for a tuner input.
712     */
713    public static boolean isChannelUriForTunerInput(Uri uri) {
714        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_CHANNEL);
715    }
716
717    /**
718     * Returns {@code true}, if {@code uri} is a channel URI for a pass-through input.
719     */
720    public static boolean isChannelUriForPassthroughInput(Uri uri) {
721        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PASSTHROUGH);
722    }
723
724    /**
725     * Returns {@code true}, if {@code uri} is a program URI.
726     */
727    public static boolean isProgramUri(Uri uri) {
728        return isTvUri(uri) && isTwoSegmentUriStartingWith(uri, PATH_PROGRAM);
729    }
730
731    /**
732     * Requests to make a channel browsable.
733     *
734     * <p>Once called, the system will review the request and make the channel browsable based on
735     * its policy. The first request from a package is guaranteed to be approved. This is only
736     * relevant to channels with {@link Channels#TYPE_PREVIEW} type.
737     *
738     * @param context The context for accessing content provider.
739     * @param channelId The channel ID to be browsable.
740     * @see Channels#COLUMN_BROWSABLE
741     */
742    public static void requestChannelBrowsable(Context context, long channelId) {
743        TvInputManager manager = (TvInputManager) context.getSystemService(
744            Context.TV_INPUT_SERVICE);
745        if (manager != null) {
746            manager.requestChannelBrowsable(buildChannelUri(channelId));
747        }
748    }
749
750    private TvContract() {}
751
752    /**
753     * Common base for the tables of TV channels/programs.
754     */
755    public interface BaseTvColumns extends BaseColumns {
756        /**
757         * The name of the package that owns the current row.
758         *
759         * <p>The TV provider fills in this column with the name of the package that provides the
760         * initial data of the row. If the package is later uninstalled, the rows it owns are
761         * automatically removed from the tables.
762         *
763         * <p>Type: TEXT
764         */
765        String COLUMN_PACKAGE_NAME = "package_name";
766    }
767
768    /**
769     * Common columns for the tables of TV programs.
770     * @hide
771     */
772    interface ProgramColumns {
773        /** @hide */
774        @IntDef({
775                REVIEW_RATING_STYLE_STARS,
776                REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
777                REVIEW_RATING_STYLE_PERCENTAGE,
778        })
779        @Retention(RetentionPolicy.SOURCE)
780        @interface ReviewRatingStyle {}
781
782        /**
783         * The review rating style for five star rating.
784         *
785         * @see #COLUMN_REVIEW_RATING_STYLE
786         */
787        int REVIEW_RATING_STYLE_STARS = 0;
788
789        /**
790         * The review rating style for thumbs-up and thumbs-down rating.
791         *
792         * @see #COLUMN_REVIEW_RATING_STYLE
793         */
794        int REVIEW_RATING_STYLE_THUMBS_UP_DOWN = 1;
795
796        /**
797         * The review rating style for 0 to 100 point system.
798         *
799         * @see #COLUMN_REVIEW_RATING_STYLE
800         */
801        int REVIEW_RATING_STYLE_PERCENTAGE = 2;
802
803        /**
804         * The title of this TV program.
805         *
806         * <p>If this program is an episodic TV show, it is recommended that the title is the series
807         * title and its related fields ({@link #COLUMN_SEASON_TITLE} and/or
808         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, {@link #COLUMN_SEASON_DISPLAY_NUMBER},
809         * {@link #COLUMN_EPISODE_DISPLAY_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
810         *
811         * <p>Type: TEXT
812         */
813        String COLUMN_TITLE = "title";
814
815        /**
816         * The season display number of this TV program for episodic TV shows.
817         *
818         * <p>This is used to indicate the season number. (e.g. 1, 2 or 3) Note that the value
819         * does not necessarily be numeric. (e.g. 12B)
820         *
821         * <p>Can be empty.
822         *
823         * <p>Type: TEXT
824         */
825        String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
826
827        /**
828         * The title of the season for this TV program for episodic TV shows.
829         *
830         * <p>This is an optional field supplied only when the season has a special title
831         * (e.g. The Final Season). If provided, the applications should display it instead of
832         * {@link #COLUMN_SEASON_DISPLAY_NUMBER}, and should display it without alterations.
833         * (e.g. for "The Final Season", displayed string should be "The Final Season", not
834         * "Season The Final Season"). When displaying multiple programs, the order should be based
835         * on {@link #COLUMN_SEASON_DISPLAY_NUMBER}, even when {@link #COLUMN_SEASON_TITLE} exists.
836         *
837         * <p>Can be empty.
838         *
839         * <p>Type: TEXT
840         */
841        String COLUMN_SEASON_TITLE = "season_title";
842
843        /**
844         * The episode display number of this TV program for episodic TV shows.
845         *
846         * <p>This is used to indicate the episode number. (e.g. 1, 2 or 3) Note that the value
847         * does not necessarily be numeric. (e.g. 12B)
848         *
849         * <p>Can be empty.
850         *
851         * <p>Type: TEXT
852         */
853        String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
854
855        /**
856         * The episode title of this TV program for episodic TV shows.
857         *
858         * <p>Can be empty.
859         *
860         * <p>Type: TEXT
861         */
862        String COLUMN_EPISODE_TITLE = "episode_title";
863
864        /**
865         * The comma-separated canonical genre string of this TV program.
866         *
867         * <p>Canonical genres are defined in {@link Genres}. Use {@link Genres#encode} to create a
868         * text that can be stored in this column. Use {@link Genres#decode} to get the canonical
869         * genre strings from the text stored in the column.
870         *
871         * <p>Type: TEXT
872         * @see Genres
873         * @see Genres#encode
874         * @see Genres#decode
875         */
876        String COLUMN_CANONICAL_GENRE = "canonical_genre";
877
878        /**
879         * The short description of this TV program that is displayed to the user by default.
880         *
881         * <p>It is recommended to limit the length of the descriptions to 256 characters.
882         *
883         * <p>Type: TEXT
884         */
885        String COLUMN_SHORT_DESCRIPTION = "short_description";
886
887        /**
888         * The detailed, lengthy description of this TV program that is displayed only when the user
889         * wants to see more information.
890         *
891         * <p>TV input services should leave this field empty if they have no additional details
892         * beyond {@link #COLUMN_SHORT_DESCRIPTION}.
893         *
894         * <p>Type: TEXT
895         */
896        String COLUMN_LONG_DESCRIPTION = "long_description";
897
898        /**
899         * The width of the video for this TV program, in the unit of pixels.
900         *
901         * <p>Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video
902         * resolution of the current TV program. Can be empty if it is not known initially or the
903         * program does not convey any video such as the programs from type
904         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
905         *
906         * <p>Type: INTEGER
907         */
908        String COLUMN_VIDEO_WIDTH = "video_width";
909
910        /**
911         * The height of the video for this TV program, in the unit of pixels.
912         *
913         * <p>Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video
914         * resolution of the current TV program. Can be empty if it is not known initially or the
915         * program does not convey any video such as the programs from type
916         * {@link Channels#SERVICE_TYPE_AUDIO} channels.
917         *
918         * <p>Type: INTEGER
919         */
920        String COLUMN_VIDEO_HEIGHT = "video_height";
921
922        /**
923         * The comma-separated audio languages of this TV program.
924         *
925         * <p>This is used to describe available audio languages included in the program. Use either
926         * ISO 639-1 or 639-2/T codes.
927         *
928         * <p>Type: TEXT
929         */
930        String COLUMN_AUDIO_LANGUAGE = "audio_language";
931
932        /**
933         * The comma-separated content ratings of this TV program.
934         *
935         * <p>This is used to describe the content rating(s) of this program. Each comma-separated
936         * content rating sub-string should be generated by calling
937         * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
938         * rated by a single rating system, thus resulting in a corresponding single sub-string that
939         * does not require comma separation and multiple sub-strings appear only when the program
940         * content is rated by two or more content rating systems. If any of those ratings is
941         * specified as "blocked rating" in the user's parental control settings, the TV input
942         * service should block the current content and wait for the signal that it is okay to
943         * unblock.
944         *
945         * <p>Type: TEXT
946         */
947        String COLUMN_CONTENT_RATING = "content_rating";
948
949        /**
950         * The URI for the poster art of this TV program.
951         *
952         * <p>The data in the column must be a URL, or a URI in one of the following formats:
953         *
954         * <ul>
955         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
956         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
957         * </li>
958         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
959         * </ul>
960         *
961         * <p>Can be empty.
962         *
963         * <p>Type: TEXT
964         */
965        String COLUMN_POSTER_ART_URI = "poster_art_uri";
966
967        /**
968         * The URI for the thumbnail of this TV program.
969         *
970         * <p>The system can generate a thumbnail from the poster art if this column is not
971         * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
972         * just a scaled image of the poster art.
973         *
974         * <p>The data in the column must be a URL, or a URI in one of the following formats:
975         *
976         * <ul>
977         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
978         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
979         * </li>
980         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
981         * </ul>
982         *
983         * <p>Can be empty.
984         *
985         * <p>Type: TEXT
986         */
987        String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
988
989        /**
990         * The flag indicating whether this TV program is searchable or not.
991         *
992         * <p>The columns of searchable programs can be read by other applications that have proper
993         * permission. Care must be taken not to open sensitive data.
994         *
995         * <p>A value of 1 indicates that the program is searchable and its columns can be read by
996         * other applications, a value of 0 indicates that the program is hidden and its columns can
997         * be read only by the package that owns the program and the system. If not specified, this
998         * value is set to 1 (searchable) by default.
999         *
1000         * <p>Type: INTEGER (boolean)
1001         */
1002        String COLUMN_SEARCHABLE = "searchable";
1003
1004        /**
1005         * Internal data used by individual TV input services.
1006         *
1007         * <p>This is internal to the provider that inserted it, and should not be decoded by other
1008         * apps.
1009         *
1010         * <p>Type: BLOB
1011         */
1012        String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
1013
1014        /**
1015         * Internal integer flag used by individual TV input services.
1016         *
1017         * <p>This is internal to the provider that inserted it, and should not be decoded by other
1018         * apps.
1019         *
1020         * <p>Type: INTEGER
1021         */
1022        String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
1023
1024        /**
1025         * Internal integer flag used by individual TV input services.
1026         *
1027         * <p>This is internal to the provider that inserted it, and should not be decoded by other
1028         * apps.
1029         *
1030         * <p>Type: INTEGER
1031         */
1032        String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
1033
1034        /**
1035         * Internal integer flag used by individual TV input services.
1036         *
1037         * <p>This is internal to the provider that inserted it, and should not be decoded by other
1038         * apps.
1039         *
1040         * <p>Type: INTEGER
1041         */
1042        String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
1043
1044        /**
1045         * Internal integer flag used by individual TV input services.
1046         *
1047         * <p>This is internal to the provider that inserted it, and should not be decoded by other
1048         * apps.
1049         *
1050         * <p>Type: INTEGER
1051         */
1052        String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
1053
1054        /**
1055         * The version number of this row entry used by TV input services.
1056         *
1057         * <p>This is best used by sync adapters to identify the rows to update. The number can be
1058         * defined by individual TV input services. One may assign the same value as
1059         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
1060         * broadcast.
1061         *
1062         * <p>Type: INTEGER
1063         */
1064        String COLUMN_VERSION_NUMBER = "version_number";
1065
1066        /**
1067         * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
1068         *
1069         * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
1070         * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
1071         *
1072         * <p>Type: INTEGER
1073         * @see #COLUMN_REVIEW_RATING
1074         */
1075        String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
1076
1077        /**
1078         * The review rating score for this program.
1079         *
1080         * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
1081         * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
1082         * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
1083         * the value should be two integers, one for thumbs-up count and the other for thumbs-down
1084         * count, with a comma between them. (e.g. "200,40") If the style is
1085         * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
1086         * 100. (e.g. "99.9")
1087         *
1088         * <p>Type: TEXT
1089         * @see #COLUMN_REVIEW_RATING_STYLE
1090         */
1091        String COLUMN_REVIEW_RATING = "review_rating";
1092    }
1093
1094    /**
1095     * Common columns for the tables of preview programs.
1096     * @hide
1097     */
1098    interface PreviewProgramColumns {
1099
1100        /** @hide */
1101        @IntDef({
1102                TYPE_MOVIE,
1103                TYPE_TV_SERIES,
1104                TYPE_TV_SEASON,
1105                TYPE_TV_EPISODE,
1106                TYPE_CLIP,
1107                TYPE_EVENT,
1108                TYPE_CHANNEL,
1109                TYPE_TRACK,
1110                TYPE_ALBUM,
1111                TYPE_ARTIST,
1112                TYPE_PLAYLIST,
1113                TYPE_STATION,
1114        })
1115        @Retention(RetentionPolicy.SOURCE)
1116        public @interface Type {}
1117
1118        /**
1119         * The program type for movie.
1120         *
1121         * @see #COLUMN_TYPE
1122         */
1123        int TYPE_MOVIE = 0;
1124
1125        /**
1126         * The program type for TV series.
1127         *
1128         * @see #COLUMN_TYPE
1129         */
1130        int TYPE_TV_SERIES = 1;
1131
1132        /**
1133         * The program type for TV season.
1134         *
1135         * @see #COLUMN_TYPE
1136         */
1137        int TYPE_TV_SEASON = 2;
1138
1139        /**
1140         * The program type for TV episode.
1141         *
1142         * @see #COLUMN_TYPE
1143         */
1144        int TYPE_TV_EPISODE = 3;
1145
1146        /**
1147         * The program type for clip.
1148         *
1149         * @see #COLUMN_TYPE
1150         */
1151        int TYPE_CLIP = 4;
1152
1153        /**
1154         * The program type for event.
1155         *
1156         * @see #COLUMN_TYPE
1157         */
1158        int TYPE_EVENT = 5;
1159
1160        /**
1161         * The program type for channel.
1162         *
1163         * @see #COLUMN_TYPE
1164         */
1165        int TYPE_CHANNEL = 6;
1166
1167        /**
1168         * The program type for track.
1169         *
1170         * @see #COLUMN_TYPE
1171         */
1172        int TYPE_TRACK = 7;
1173
1174        /**
1175         * The program type for album.
1176         *
1177         * @see #COLUMN_TYPE
1178         */
1179        int TYPE_ALBUM = 8;
1180
1181        /**
1182         * The program type for artist.
1183         *
1184         * @see #COLUMN_TYPE
1185         */
1186        int TYPE_ARTIST = 9;
1187
1188        /**
1189         * The program type for playlist.
1190         *
1191         * @see #COLUMN_TYPE
1192         */
1193        int TYPE_PLAYLIST = 10;
1194
1195        /**
1196         * The program type for station.
1197         *
1198         * @see #COLUMN_TYPE
1199         */
1200        int TYPE_STATION = 11;
1201
1202        /** @hide */
1203        @IntDef({
1204                ASPECT_RATIO_16_9,
1205                ASPECT_RATIO_3_2,
1206                ASPECT_RATIO_1_1,
1207                ASPECT_RATIO_2_3,
1208                ASPECT_RATIO_4_3,
1209        })
1210        @Retention(RetentionPolicy.SOURCE)
1211        public @interface AspectRatio {}
1212
1213        /**
1214         * The aspect ratio for 16:9.
1215         *
1216         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
1217         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
1218         */
1219        int ASPECT_RATIO_16_9 = 0;
1220
1221        /**
1222         * The aspect ratio for 3:2.
1223         *
1224         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
1225         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
1226         */
1227        int ASPECT_RATIO_3_2 = 1;
1228
1229        /**
1230         * The aspect ratio for 4:3.
1231         *
1232         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
1233         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
1234         */
1235        int ASPECT_RATIO_4_3 = 2;
1236
1237        /**
1238         * The aspect ratio for 1:1.
1239         *
1240         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
1241         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
1242         */
1243        int ASPECT_RATIO_1_1 = 3;
1244
1245        /**
1246         * The aspect ratio for 2:3.
1247         *
1248         * @see #COLUMN_POSTER_ART_ASPECT_RATIO
1249         * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
1250         */
1251        int ASPECT_RATIO_2_3 = 4;
1252
1253        /** @hide */
1254        @IntDef({
1255                AVAILABILITY_AVAILABLE,
1256                AVAILABILITY_FREE_WITH_SUBSCRIPTION,
1257                AVAILABILITY_PAID_CONTENT,
1258        })
1259        @Retention(RetentionPolicy.SOURCE)
1260        public @interface Availability {}
1261
1262        /**
1263         * The availability for "available to this user".
1264         *
1265         * @see #COLUMN_AVAILABILITY
1266         */
1267        int AVAILABILITY_AVAILABLE = 0;
1268
1269        /**
1270         * The availability for "free with subscription".
1271         *
1272         * @see #COLUMN_AVAILABILITY
1273         */
1274        int AVAILABILITY_FREE_WITH_SUBSCRIPTION = 1;
1275
1276        /**
1277         * The availability for "paid content, either to-own or rental
1278         * (user has not purchased/rented).
1279         *
1280         * @see #COLUMN_AVAILABILITY
1281         */
1282        int AVAILABILITY_PAID_CONTENT = 2;
1283
1284        /** @hide */
1285        @IntDef({
1286                INTERACTION_TYPE_VIEWS,
1287                INTERACTION_TYPE_LISTENS,
1288                INTERACTION_TYPE_FOLLOWERS,
1289                INTERACTION_TYPE_FANS,
1290                INTERACTION_TYPE_LIKES,
1291                INTERACTION_TYPE_THUMBS,
1292                INTERACTION_TYPE_VIEWERS,
1293        })
1294        @Retention(RetentionPolicy.SOURCE)
1295        public @interface InteractionType {}
1296
1297        /**
1298         * The interaction type for "views".
1299         *
1300         * @see #COLUMN_INTERACTION_TYPE
1301         */
1302        int INTERACTION_TYPE_VIEWS = 0;
1303
1304        /**
1305         * The interaction type for "listens".
1306         *
1307         * @see #COLUMN_INTERACTION_TYPE
1308         */
1309        int INTERACTION_TYPE_LISTENS = 1;
1310
1311        /**
1312         * The interaction type for "followers".
1313         *
1314         * @see #COLUMN_INTERACTION_TYPE
1315         */
1316        int INTERACTION_TYPE_FOLLOWERS = 2;
1317
1318        /**
1319         * The interaction type for "fans".
1320         *
1321         * @see #COLUMN_INTERACTION_TYPE
1322         */
1323        int INTERACTION_TYPE_FANS = 3;
1324
1325        /**
1326         * The interaction type for "likes".
1327         *
1328         * @see #COLUMN_INTERACTION_TYPE
1329         */
1330        int INTERACTION_TYPE_LIKES = 4;
1331
1332        /**
1333         * The interaction type for "thumbs".
1334         *
1335         * @see #COLUMN_INTERACTION_TYPE
1336         */
1337        int INTERACTION_TYPE_THUMBS = 5;
1338
1339        /**
1340         * The interaction type for "viewers".
1341         *
1342         * @see #COLUMN_INTERACTION_TYPE
1343         */
1344        int INTERACTION_TYPE_VIEWERS = 6;
1345
1346        /**
1347         * The type of this program content.
1348         *
1349         * <p>The value should match one of the followings:
1350         * {@link #TYPE_MOVIE},
1351         * {@link #TYPE_TV_SERIES},
1352         * {@link #TYPE_TV_SEASON},
1353         * {@link #TYPE_TV_EPISODE},
1354         * {@link #TYPE_CLIP},
1355         * {@link #TYPE_EVENT},
1356         * {@link #TYPE_CHANNEL},
1357         * {@link #TYPE_TRACK},
1358         * {@link #TYPE_ALBUM},
1359         * {@link #TYPE_ARTIST},
1360         * {@link #TYPE_PLAYLIST}, and
1361         * {@link #TYPE_STATION}.
1362         *
1363         * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
1364         * channel.
1365         *
1366         * <p>Type: INTEGER
1367         */
1368        String COLUMN_TYPE = "type";
1369
1370        /**
1371         * The aspect ratio of the poster art for this TV program.
1372         *
1373         * <p>The value should match one of the followings:
1374         * {@link #ASPECT_RATIO_16_9},
1375         * {@link #ASPECT_RATIO_3_2},
1376         * {@link #ASPECT_RATIO_4_3},
1377         * {@link #ASPECT_RATIO_1_1}, and
1378         * {@link #ASPECT_RATIO_2_3}.
1379         *
1380         * <p>Type: INTEGER
1381         */
1382        String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
1383
1384        /**
1385         * The aspect ratio of the thumbnail for this TV program.
1386         *
1387         * <p>The value should match one of the followings:
1388         * {@link #ASPECT_RATIO_16_9},
1389         * {@link #ASPECT_RATIO_3_2},
1390         * {@link #ASPECT_RATIO_4_3},
1391         * {@link #ASPECT_RATIO_1_1}, and
1392         * {@link #ASPECT_RATIO_2_3}.
1393         *
1394         * <p>Type: INTEGER
1395         */
1396        String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
1397
1398        /**
1399         * The URI for the logo of this TV program.
1400         *
1401         * <p>This is a small badge shown on top of the poster art or thumbnail representing the
1402         * source of the content.
1403         *
1404         * <p>The data in the column must be a URL, or a URI in one of the following formats:
1405         *
1406         * <ul>
1407         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
1408         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
1409         * </li>
1410         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
1411         * </ul>
1412         *
1413         * <p>Can be empty.
1414         *
1415         * <p>Type: TEXT
1416         */
1417        String COLUMN_LOGO_URI = "logo_uri";
1418
1419        /**
1420         * The availability of this TV program.
1421         *
1422         * <p>The value should match one of the followings:
1423         * {@link #AVAILABILITY_AVAILABLE},
1424         * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
1425         * {@link #AVAILABILITY_PAID_CONTENT}.
1426         *
1427         * <p>Type: INTEGER
1428         */
1429        String COLUMN_AVAILABILITY = "availability";
1430
1431        /**
1432         * The starting price of this TV program.
1433         *
1434         * <p>This indicates the lowest regular acquisition cost of the content. It is only used
1435         * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
1436         *
1437         * <p>Type: TEXT
1438         * @see #COLUMN_OFFER_PRICE
1439         */
1440        String COLUMN_STARTING_PRICE = "starting_price";
1441
1442        /**
1443         * The offer price of this TV program.
1444         *
1445         * <p>This is the promotional cost of the content. It is only used if the availability of
1446         * the program is {@link #AVAILABILITY_PAID_CONTENT}.
1447         *
1448         * <p>Type: TEXT
1449         * @see #COLUMN_STARTING_PRICE
1450         */
1451        String COLUMN_OFFER_PRICE = "offer_price";
1452
1453        /**
1454         * The release date of this TV program.
1455         *
1456         * <p>The value should be in one of the following formats:
1457         * "yyyy", "yyyy-MM-dd", and "yyyy-MM-ddTHH:mm:ssZ" (UTC in ISO 8601).
1458         *
1459         * <p>Type: TEXT
1460         */
1461        String COLUMN_RELEASE_DATE = "release_date";
1462
1463        /**
1464         * The count of the items included in this TV program.
1465         *
1466         * <p>This is only relevant if the program represents a collection of items such as series,
1467         * episodes, or music tracks.
1468         *
1469         * <p>Type: INTEGER
1470         */
1471        String COLUMN_ITEM_COUNT = "item_count";
1472
1473        /**
1474         * The flag indicating whether this TV program is live or not.
1475         *
1476         * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
1477         * of 0 indicates that the content is off the air and does not need to be consumed at the
1478         * present time. If not specified, the value is set to 0 (not live) by default.
1479         *
1480         * <p>Type: INTEGER (boolean)
1481         */
1482        String COLUMN_LIVE = "live";
1483
1484        /**
1485         * The internal ID used by individual TV input services.
1486         *
1487         * <p>This is internal to the provider that inserted it, and should not be decoded by other
1488         * apps.
1489         *
1490         * <p>Can be empty.
1491         *
1492         * <p>Type: TEXT
1493         */
1494        String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
1495
1496        /**
1497         * The URI for the preview video.
1498         *
1499         * <p>The data in the column must be a URL, or a URI in one of the following formats:
1500         *
1501         * <ul>
1502         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
1503         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
1504         * </li>
1505         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
1506         * </ul>
1507         *
1508         * <p>Can be empty.
1509         *
1510         * <p>Type: TEXT
1511         */
1512        String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
1513
1514        /**
1515         * The last playback position (in milliseconds) of the original content of this preview
1516         * program.
1517         *
1518         * <p>Can be empty.
1519         *
1520         * <p>Type: INTEGER
1521         */
1522        String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
1523                "last_playback_position_millis";
1524
1525        /**
1526         * The duration (in milliseconds) of the original content of this preview program.
1527         *
1528         * <p>Can be empty.
1529         *
1530         * <p>Type: INTEGER
1531         */
1532        String COLUMN_DURATION_MILLIS = "duration_millis";
1533
1534        /**
1535         * The intent URI which is launched when the preview program is selected.
1536         *
1537         * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
1538         * and converted back to the original intent with {@link Intent#parseUri}. The intent is
1539         * launched when the user selects the preview program item.
1540         *
1541         * <p>Can be empty.
1542         *
1543         * <p>Type: TEXT
1544         */
1545        String COLUMN_INTENT_URI = "intent_uri";
1546
1547        /**
1548         * The flag indicating whether this program is transient or not.
1549         *
1550         * <p>A value of 1 indicates that the channel will be automatically removed by the system on
1551         * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
1552         * specified, this value is set to 0 (not transient) by default.
1553         *
1554         * <p>Type: INTEGER (boolean)
1555         * @see Channels#COLUMN_TRANSIENT
1556         */
1557        String COLUMN_TRANSIENT = "transient";
1558
1559        /**
1560         * The type of interaction for this TV program.
1561         *
1562         * <p> The value should match one of the followings:
1563         * {@link #INTERACTION_TYPE_VIEWS},
1564         * {@link #INTERACTION_TYPE_LISTENS},
1565         * {@link #INTERACTION_TYPE_FOLLOWERS},
1566         * {@link #INTERACTION_TYPE_FANS},
1567         * {@link #INTERACTION_TYPE_LIKES},
1568         * {@link #INTERACTION_TYPE_THUMBS}, and
1569         * {@link #INTERACTION_TYPE_VIEWERS}.
1570         *
1571         * <p>Type: INTEGER
1572         * @see #COLUMN_INTERACTION_COUNT
1573         */
1574        String COLUMN_INTERACTION_TYPE = "interaction_type";
1575
1576        /**
1577         * The interaction count for this program.
1578         *
1579         * <p>This indicates the number of times interaction has happened.
1580         *
1581         * <p>Type: INTEGER (long)
1582         * @see #COLUMN_INTERACTION_TYPE
1583         */
1584        String COLUMN_INTERACTION_COUNT = "interaction_count";
1585
1586        /**
1587         * The author or artist of this content.
1588         *
1589         * <p>Type: TEXT
1590         */
1591        String COLUMN_AUTHOR = "author";
1592
1593        /**
1594         * The flag indicating whether this TV program is browsable or not.
1595         *
1596         * <p>This column can only be set by applications having proper system permission. For
1597         * other applications, this is a read-only column.
1598         *
1599         * <p>A value of 1 indicates that the program is browsable and can be shown to users in
1600         * the UI. A value of 0 indicates that the program should be hidden from users and the
1601         * application who changes this value to 0 should send
1602         * {@link #ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
1603         * to notify this change.
1604         *
1605         * <p>This value is set to 1 (browsable) by default.
1606         *
1607         * <p>Type: INTEGER (boolean)
1608         */
1609        String COLUMN_BROWSABLE = "browsable";
1610
1611        /**
1612         * The content ID of this TV program.
1613         *
1614         * <p>A public ID of the content which allows the application to apply the same operation to
1615         * all the program copies in different channels.
1616         *
1617         * <p>Can be empty.
1618         *
1619         * <p>Type: TEXT
1620         */
1621        String COLUMN_CONTENT_ID = "content_id";
1622
1623    }
1624
1625    /** Column definitions for the TV channels table. */
1626    public static final class Channels implements BaseTvColumns {
1627
1628        /**
1629         * The content:// style URI for this table.
1630         *
1631         * <p>SQL selection is not supported for {@link ContentResolver#query},
1632         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
1633         */
1634        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
1635                + PATH_CHANNEL);
1636
1637        /** The MIME type of a directory of TV channels. */
1638        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
1639
1640        /** The MIME type of a single TV channel. */
1641        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
1642
1643        /** @hide */
1644        @StringDef({
1645                TYPE_OTHER,
1646                TYPE_NTSC,
1647                TYPE_PAL,
1648                TYPE_SECAM,
1649                TYPE_DVB_T,
1650                TYPE_DVB_T2,
1651                TYPE_DVB_S,
1652                TYPE_DVB_S2,
1653                TYPE_DVB_C,
1654                TYPE_DVB_C2,
1655                TYPE_DVB_H,
1656                TYPE_DVB_SH,
1657                TYPE_ATSC_T,
1658                TYPE_ATSC_C,
1659                TYPE_ATSC_M_H,
1660                TYPE_ISDB_T,
1661                TYPE_ISDB_TB,
1662                TYPE_ISDB_S,
1663                TYPE_ISDB_C,
1664                TYPE_1SEG,
1665                TYPE_DTMB,
1666                TYPE_CMMB,
1667                TYPE_T_DMB,
1668                TYPE_S_DMB,
1669                TYPE_PREVIEW,
1670        })
1671        @Retention(RetentionPolicy.SOURCE)
1672        public @interface Type {}
1673
1674        /**
1675         * A generic channel type.
1676         *
1677         * Use this if the current channel is streaming-based or its broadcast system type does not
1678         * fit under any other types. This is the default channel type.
1679         *
1680         * @see #COLUMN_TYPE
1681         */
1682        public static final String TYPE_OTHER = "TYPE_OTHER";
1683
1684        /**
1685         * The channel type for NTSC.
1686         *
1687         * @see #COLUMN_TYPE
1688         */
1689        public static final String TYPE_NTSC = "TYPE_NTSC";
1690
1691        /**
1692         * The channel type for PAL.
1693         *
1694         * @see #COLUMN_TYPE
1695         */
1696        public static final String TYPE_PAL = "TYPE_PAL";
1697
1698        /**
1699         * The channel type for SECAM.
1700         *
1701         * @see #COLUMN_TYPE
1702         */
1703        public static final String TYPE_SECAM = "TYPE_SECAM";
1704
1705        /**
1706         * The channel type for DVB-T (terrestrial).
1707         *
1708         * @see #COLUMN_TYPE
1709         */
1710        public static final String TYPE_DVB_T = "TYPE_DVB_T";
1711
1712        /**
1713         * The channel type for DVB-T2 (terrestrial).
1714         *
1715         * @see #COLUMN_TYPE
1716         */
1717        public static final String TYPE_DVB_T2 = "TYPE_DVB_T2";
1718
1719        /**
1720         * The channel type for DVB-S (satellite).
1721         *
1722         * @see #COLUMN_TYPE
1723         */
1724        public static final String TYPE_DVB_S = "TYPE_DVB_S";
1725
1726        /**
1727         * The channel type for DVB-S2 (satellite).
1728         *
1729         * @see #COLUMN_TYPE
1730         */
1731        public static final String TYPE_DVB_S2 = "TYPE_DVB_S2";
1732
1733        /**
1734         * The channel type for DVB-C (cable).
1735         *
1736         * @see #COLUMN_TYPE
1737         */
1738        public static final String TYPE_DVB_C = "TYPE_DVB_C";
1739
1740        /**
1741         * The channel type for DVB-C2 (cable).
1742         *
1743         * @see #COLUMN_TYPE
1744         */
1745        public static final String TYPE_DVB_C2 = "TYPE_DVB_C2";
1746
1747        /**
1748         * The channel type for DVB-H (handheld).
1749         *
1750         * @see #COLUMN_TYPE
1751         */
1752        public static final String TYPE_DVB_H = "TYPE_DVB_H";
1753
1754        /**
1755         * The channel type for DVB-SH (satellite).
1756         *
1757         * @see #COLUMN_TYPE
1758         */
1759        public static final String TYPE_DVB_SH = "TYPE_DVB_SH";
1760
1761        /**
1762         * The channel type for ATSC (terrestrial).
1763         *
1764         * @see #COLUMN_TYPE
1765         */
1766        public static final String TYPE_ATSC_T = "TYPE_ATSC_T";
1767
1768        /**
1769         * The channel type for ATSC (cable).
1770         *
1771         * @see #COLUMN_TYPE
1772         */
1773        public static final String TYPE_ATSC_C = "TYPE_ATSC_C";
1774
1775        /**
1776         * The channel type for ATSC-M/H (mobile/handheld).
1777         *
1778         * @see #COLUMN_TYPE
1779         */
1780        public static final String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
1781
1782        /**
1783         * The channel type for ISDB-T (terrestrial).
1784         *
1785         * @see #COLUMN_TYPE
1786         */
1787        public static final String TYPE_ISDB_T = "TYPE_ISDB_T";
1788
1789        /**
1790         * The channel type for ISDB-Tb (Brazil).
1791         *
1792         * @see #COLUMN_TYPE
1793         */
1794        public static final String TYPE_ISDB_TB = "TYPE_ISDB_TB";
1795
1796        /**
1797         * The channel type for ISDB-S (satellite).
1798         *
1799         * @see #COLUMN_TYPE
1800         */
1801        public static final String TYPE_ISDB_S = "TYPE_ISDB_S";
1802
1803        /**
1804         * The channel type for ISDB-C (cable).
1805         *
1806         * @see #COLUMN_TYPE
1807         */
1808        public static final String TYPE_ISDB_C = "TYPE_ISDB_C";
1809
1810        /**
1811         * The channel type for 1seg (handheld).
1812         *
1813         * @see #COLUMN_TYPE
1814         */
1815        public static final String TYPE_1SEG = "TYPE_1SEG";
1816
1817        /**
1818         * The channel type for DTMB (terrestrial).
1819         *
1820         * @see #COLUMN_TYPE
1821         */
1822        public static final String TYPE_DTMB = "TYPE_DTMB";
1823
1824        /**
1825         * The channel type for CMMB (handheld).
1826         *
1827         * @see #COLUMN_TYPE
1828         */
1829        public static final String TYPE_CMMB = "TYPE_CMMB";
1830
1831        /**
1832         * The channel type for T-DMB (terrestrial).
1833         *
1834         * @see #COLUMN_TYPE
1835         */
1836        public static final String TYPE_T_DMB = "TYPE_T_DMB";
1837
1838        /**
1839         * The channel type for S-DMB (satellite).
1840         *
1841         * @see #COLUMN_TYPE
1842         */
1843        public static final String TYPE_S_DMB = "TYPE_S_DMB";
1844
1845        /**
1846         * The channel type for preview videos.
1847         *
1848         * <P>Unlike other broadcast TV channel types, the programs in the preview channel usually
1849         * are promotional videos. The UI may treat the preview channels differently from the other
1850         * broadcast channels.
1851         *
1852         * @see #COLUMN_TYPE
1853         */
1854        public static final String TYPE_PREVIEW = "TYPE_PREVIEW";
1855
1856        /** @hide */
1857        @StringDef({
1858                SERVICE_TYPE_OTHER,
1859                SERVICE_TYPE_AUDIO_VIDEO,
1860                SERVICE_TYPE_AUDIO,
1861        })
1862        @Retention(RetentionPolicy.SOURCE)
1863        public @interface ServiceType {}
1864
1865        /** A generic service type. */
1866        public static final String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
1867
1868        /** The service type for regular TV channels that have both audio and video. */
1869        public static final String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
1870
1871        /** The service type for radio channels that have audio only. */
1872        public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
1873
1874        /** @hide */
1875        @StringDef({
1876                VIDEO_FORMAT_240P,
1877                VIDEO_FORMAT_360P,
1878                VIDEO_FORMAT_480I,
1879                VIDEO_FORMAT_576I,
1880                VIDEO_FORMAT_576P,
1881                VIDEO_FORMAT_720P,
1882                VIDEO_FORMAT_1080I,
1883                VIDEO_FORMAT_1080P,
1884                VIDEO_FORMAT_2160P,
1885                VIDEO_FORMAT_4320P,
1886        })
1887        @Retention(RetentionPolicy.SOURCE)
1888        public @interface VideoFormat {}
1889
1890        /** The video format for 240p. */
1891        public static final String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
1892
1893        /** The video format for 360p. */
1894        public static final String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
1895
1896        /** The video format for 480i. */
1897        public static final String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
1898
1899        /** The video format for 480p. */
1900        public static final String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
1901
1902        /** The video format for 576i. */
1903        public static final String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
1904
1905        /** The video format for 576p. */
1906        public static final String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
1907
1908        /** The video format for 720p. */
1909        public static final String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
1910
1911        /** The video format for 1080i. */
1912        public static final String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
1913
1914        /** The video format for 1080p. */
1915        public static final String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
1916
1917        /** The video format for 2160p. */
1918        public static final String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
1919
1920        /** The video format for 4320p. */
1921        public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
1922
1923        /** @hide */
1924        @StringDef({
1925                VIDEO_RESOLUTION_SD,
1926                VIDEO_RESOLUTION_ED,
1927                VIDEO_RESOLUTION_HD,
1928                VIDEO_RESOLUTION_FHD,
1929                VIDEO_RESOLUTION_UHD,
1930        })
1931        @Retention(RetentionPolicy.SOURCE)
1932        public @interface VideoResolution {}
1933
1934        /** The video resolution for standard-definition. */
1935        public static final String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
1936
1937        /** The video resolution for enhanced-definition. */
1938        public static final String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
1939
1940        /** The video resolution for high-definition. */
1941        public static final String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
1942
1943        /** The video resolution for full high-definition. */
1944        public static final String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
1945
1946        /** The video resolution for ultra high-definition. */
1947        public static final String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
1948
1949        private static final Map<String, String> VIDEO_FORMAT_TO_RESOLUTION_MAP = new HashMap<>();
1950
1951        static {
1952            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_480I, VIDEO_RESOLUTION_SD);
1953            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_480P, VIDEO_RESOLUTION_ED);
1954            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_576I, VIDEO_RESOLUTION_SD);
1955            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_576P, VIDEO_RESOLUTION_ED);
1956            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_720P, VIDEO_RESOLUTION_HD);
1957            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_1080I, VIDEO_RESOLUTION_HD);
1958            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_1080P, VIDEO_RESOLUTION_FHD);
1959            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_2160P, VIDEO_RESOLUTION_UHD);
1960            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_4320P, VIDEO_RESOLUTION_UHD);
1961        }
1962
1963        /**
1964         * Returns the video resolution (definition) for a given video format.
1965         *
1966         * @param videoFormat The video format defined in {@link Channels}.
1967         * @return the corresponding video resolution string. {@code null} if the resolution string
1968         *         is not defined for the given video format.
1969         * @see #COLUMN_VIDEO_FORMAT
1970         */
1971        @Nullable
1972        public static final String getVideoResolution(@VideoFormat String videoFormat) {
1973            return VIDEO_FORMAT_TO_RESOLUTION_MAP.get(videoFormat);
1974        }
1975
1976        /**
1977         * The ID of the TV input service that provides this TV channel.
1978         *
1979         * <p>Use {@link #buildInputId} to build the ID.
1980         *
1981         * <p>This is a required field.
1982         *
1983         * <p>Type: TEXT
1984         */
1985        public static final String COLUMN_INPUT_ID = "input_id";
1986
1987        /**
1988         * The broadcast system type of this TV channel.
1989         *
1990         * <p>This is used to indicate the broadcast standard (e.g. ATSC, DVB or ISDB) the current
1991         * channel conforms to. Use {@link #TYPE_OTHER} for streaming-based channels, which is the
1992         * default channel type. The value should match one of the followings:
1993         * {@link #TYPE_1SEG},
1994         * {@link #TYPE_ATSC_C},
1995         * {@link #TYPE_ATSC_M_H},
1996         * {@link #TYPE_ATSC_T},
1997         * {@link #TYPE_CMMB},
1998         * {@link #TYPE_DTMB},
1999         * {@link #TYPE_DVB_C},
2000         * {@link #TYPE_DVB_C2},
2001         * {@link #TYPE_DVB_H},
2002         * {@link #TYPE_DVB_S},
2003         * {@link #TYPE_DVB_S2},
2004         * {@link #TYPE_DVB_SH},
2005         * {@link #TYPE_DVB_T},
2006         * {@link #TYPE_DVB_T2},
2007         * {@link #TYPE_ISDB_C},
2008         * {@link #TYPE_ISDB_S},
2009         * {@link #TYPE_ISDB_T},
2010         * {@link #TYPE_ISDB_TB},
2011         * {@link #TYPE_NTSC},
2012         * {@link #TYPE_OTHER},
2013         * {@link #TYPE_PAL},
2014         * {@link #TYPE_SECAM},
2015         * {@link #TYPE_S_DMB},
2016         * {@link #TYPE_T_DMB}, and
2017         * {@link #TYPE_PREVIEW}.
2018         *
2019         * <p>This value cannot be changed once it's set. Trying to modify it will make the update
2020         * fail.
2021         *
2022         * <p>This is a required field.
2023         *
2024         * <p>Type: TEXT
2025         */
2026        public static final String COLUMN_TYPE = "type";
2027
2028        /**
2029         * The predefined service type of this TV channel.
2030         *
2031         * <p>This is primarily used to indicate whether the current channel is a regular TV channel
2032         * or a radio-like channel. Use the same coding for {@code service_type} in the underlying
2033         * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB
2034         * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER},
2035         * {@link #SERVICE_TYPE_AUDIO_VIDEO}, {@link #SERVICE_TYPE_AUDIO}
2036         *
2037         * <p>This is a required field.
2038         *
2039         * <p>Type: TEXT
2040         */
2041        public static final String COLUMN_SERVICE_TYPE = "service_type";
2042
2043        /**
2044         * The original network ID of this TV channel.
2045         *
2046         * <p>It is used to identify the originating delivery system, if applicable. Use the same
2047         * coding for {@code original_network_id} for ETSI EN 300 468/TR 101 211 and ARIB STD-B10.
2048         *
2049         * <p>This is a required field only if the underlying broadcast standard defines the same
2050         * name field. Otherwise, leave empty.
2051         *
2052         * <p>Type: INTEGER
2053         */
2054        public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
2055
2056        /**
2057         * The transport stream ID of this channel.
2058         *
2059         * <p>It is used to identify the Transport Stream that contains the current channel from any
2060         * other multiplex within a network, if applicable. Use the same coding for
2061         * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
2062         * the MPEG Transport Stream.
2063         *
2064         * <p>This is a required field only if the current channel is transmitted via the MPEG
2065         * Transport Stream. Leave empty otherwise.
2066         *
2067         * <p>Type: INTEGER
2068         */
2069        public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
2070
2071        /**
2072         * The service ID of this channel.
2073         *
2074         * <p>It is used to identify the current service, or channel from any other services within
2075         * a given Transport Stream, if applicable. Use the same coding for {@code service_id} in
2076         * ETSI EN 300 468 and ARIB STD-B10 or {@code program_number} in ISO/IEC 13818-1.
2077         *
2078         * <p>This is a required field only if the underlying broadcast standard defines the same
2079         * name field, or the current channel is transmitted via the MPEG Transport Stream. Leave
2080         * empty otherwise.
2081         *
2082         * <p>Type: INTEGER
2083         */
2084        public static final String COLUMN_SERVICE_ID = "service_id";
2085
2086        /**
2087         * The channel number that is displayed to the user.
2088         *
2089         * <p>The format can vary depending on broadcast standard and product specification.
2090         *
2091         * <p>Type: TEXT
2092         */
2093        public static final String COLUMN_DISPLAY_NUMBER = "display_number";
2094
2095        /**
2096         * The channel name that is displayed to the user.
2097         *
2098         * <p>A call sign is a good candidate to use for this purpose but any name that helps the
2099         * user recognize the current channel will be enough. Can also be empty depending on
2100         * broadcast standard.
2101         *
2102         * <p> Type: TEXT
2103         */
2104        public static final String COLUMN_DISPLAY_NAME = "display_name";
2105
2106        /**
2107         * The network affiliation for this TV channel.
2108         *
2109         * <p>This is used to identify a channel that is commonly called by its network affiliation
2110         * instead of the display name. Examples include ABC for the channel KGO-HD, FOX for the
2111         * channel KTVU-HD and NBC for the channel KNTV-HD. Can be empty if not applicable.
2112         *
2113         * <p>Type: TEXT
2114         */
2115        public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
2116
2117        /**
2118         * The description of this TV channel.
2119         *
2120         * <p>Can be empty initially.
2121         *
2122         * <p>Type: TEXT
2123         */
2124        public static final String COLUMN_DESCRIPTION = "description";
2125
2126        /**
2127         * The typical video format for programs from this TV channel.
2128         *
2129         * <p>This is primarily used to filter out channels based on video format by applications.
2130         * The value should match one of the followings: {@link #VIDEO_FORMAT_240P},
2131         * {@link #VIDEO_FORMAT_360P}, {@link #VIDEO_FORMAT_480I}, {@link #VIDEO_FORMAT_480P},
2132         * {@link #VIDEO_FORMAT_576I}, {@link #VIDEO_FORMAT_576P}, {@link #VIDEO_FORMAT_720P},
2133         * {@link #VIDEO_FORMAT_1080I}, {@link #VIDEO_FORMAT_1080P}, {@link #VIDEO_FORMAT_2160P},
2134         * {@link #VIDEO_FORMAT_4320P}. Note that the actual video resolution of each program from a
2135         * given channel can vary thus one should use {@link Programs#COLUMN_VIDEO_WIDTH} and
2136         * {@link Programs#COLUMN_VIDEO_HEIGHT} to get more accurate video resolution.
2137         *
2138         * <p>Type: TEXT
2139         *
2140         * @see #getVideoResolution
2141         */
2142        public static final String COLUMN_VIDEO_FORMAT = "video_format";
2143
2144        /**
2145         * The flag indicating whether this TV channel is browsable or not.
2146         *
2147         * <p>This column can only be set by applications having proper system permission. For
2148         * other applications, this is a read-only column.
2149         *
2150         * <p>A value of 1 indicates the channel is included in the channel list that applications
2151         * use to browse channels, a value of 0 indicates the channel is not included in the list.
2152         * If not specified, this value is set to 0 (not browsable) by default.
2153         *
2154         * <p>Type: INTEGER (boolean)
2155         */
2156        public static final String COLUMN_BROWSABLE = "browsable";
2157
2158        /**
2159         * The flag indicating whether this TV channel is searchable or not.
2160         *
2161         * <p>The columns of searchable channels can be read by other applications that have proper
2162         * permission. Care must be taken not to open sensitive data.
2163         *
2164         * <p>A value of 1 indicates that the channel is searchable and its columns can be read by
2165         * other applications, a value of 0 indicates that the channel is hidden and its columns can
2166         * be read only by the package that owns the channel and the system. If not specified, this
2167         * value is set to 1 (searchable) by default.
2168         *
2169         * <p>Type: INTEGER (boolean)
2170         */
2171        public static final String COLUMN_SEARCHABLE = "searchable";
2172
2173        /**
2174         * The flag indicating whether this TV channel is locked or not.
2175         *
2176         * <p>This is primarily used for alternative parental control to prevent unauthorized users
2177         * from watching the current channel regardless of the content rating. A value of 1
2178         * indicates the channel is locked and the user is required to enter passcode to unlock it
2179         * in order to watch the current program from the channel, a value of 0 indicates the
2180         * channel is not locked thus the user is not prompted to enter passcode If not specified,
2181         * this value is set to 0 (not locked) by default.
2182         *
2183         * <p>This column can only be set by applications having proper system permission to
2184         * modify parental control settings. For other applications, this is a read-only column.
2185
2186         * <p>Type: INTEGER (boolean)
2187         */
2188        public static final String COLUMN_LOCKED = "locked";
2189
2190        /**
2191         * The URI for the app badge icon of the app link template for this channel.
2192         *
2193         * <p>This small icon is overlaid at the bottom of the poster art specified by
2194         * {@link #COLUMN_APP_LINK_POSTER_ART_URI}. The data in the column must be a URI in one of
2195         * the following formats:
2196         *
2197         * <ul>
2198         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
2199         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
2200         * </li>
2201         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
2202         * </ul>
2203         *
2204         * <p>The app-linking allows channel input sources to provide activity links from their live
2205         * channel programming to another activity. This enables content providers to increase user
2206         * engagement by offering the viewer other content or actions.
2207         *
2208         * <p>Type: TEXT
2209         * @see #COLUMN_APP_LINK_COLOR
2210         * @see #COLUMN_APP_LINK_INTENT_URI
2211         * @see #COLUMN_APP_LINK_POSTER_ART_URI
2212         * @see #COLUMN_APP_LINK_TEXT
2213         */
2214        public static final String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
2215
2216        /**
2217         * The URI for the poster art used as the background of the app link template for this
2218         * channel.
2219         *
2220         * <p>The data in the column must be a URL, or a URI in one of the following formats:
2221         *
2222         * <ul>
2223         * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
2224         * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
2225         * </li>
2226         * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
2227         * </ul>
2228         *
2229         * <p>The app-linking allows channel input sources to provide activity links from their live
2230         * channel programming to another activity. This enables content providers to increase user
2231         * engagement by offering the viewer other content or actions.
2232         *
2233         * <p>Type: TEXT
2234         * @see #COLUMN_APP_LINK_COLOR
2235         * @see #COLUMN_APP_LINK_ICON_URI
2236         * @see #COLUMN_APP_LINK_INTENT_URI
2237         * @see #COLUMN_APP_LINK_TEXT
2238         */
2239        public static final String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
2240
2241        /**
2242         * The link text of the app link template for this channel.
2243         *
2244         * <p>This provides a short description of the action that happens when the corresponding
2245         * app link is clicked.
2246         *
2247         * <p>The app-linking allows channel input sources to provide activity links from their live
2248         * channel programming to another activity. This enables content providers to increase user
2249         * engagement by offering the viewer other content or actions.
2250         *
2251         * <p>Type: TEXT
2252         * @see #COLUMN_APP_LINK_COLOR
2253         * @see #COLUMN_APP_LINK_ICON_URI
2254         * @see #COLUMN_APP_LINK_INTENT_URI
2255         * @see #COLUMN_APP_LINK_POSTER_ART_URI
2256         */
2257        public static final String COLUMN_APP_LINK_TEXT = "app_link_text";
2258
2259        /**
2260         * The accent color of the app link template for this channel. This is primarily used for
2261         * the background color of the text box in the template.
2262         *
2263         * <p>The app-linking allows channel input sources to provide activity links from their live
2264         * channel programming to another activity. This enables content providers to increase user
2265         * engagement by offering the viewer other content or actions.
2266         *
2267         * <p>Type: INTEGER (color value)
2268         * @see #COLUMN_APP_LINK_ICON_URI
2269         * @see #COLUMN_APP_LINK_INTENT_URI
2270         * @see #COLUMN_APP_LINK_POSTER_ART_URI
2271         * @see #COLUMN_APP_LINK_TEXT
2272         */
2273        public static final String COLUMN_APP_LINK_COLOR = "app_link_color";
2274
2275        /**
2276         * The intent URI of the app link for this channel.
2277         *
2278         * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
2279         * and converted back to the original intent with {@link Intent#parseUri}. The intent is
2280         * launched when the user clicks the corresponding app link for the current channel.
2281         *
2282         * <p>The app-linking allows channel input sources to provide activity links from their live
2283         * channel programming to another activity. This enables content providers to increase user
2284         * engagement by offering the viewer other content or actions.
2285         *
2286         * <p>Type: TEXT
2287         * @see #COLUMN_APP_LINK_COLOR
2288         * @see #COLUMN_APP_LINK_ICON_URI
2289         * @see #COLUMN_APP_LINK_POSTER_ART_URI
2290         * @see #COLUMN_APP_LINK_TEXT
2291         */
2292        public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
2293
2294        /**
2295         * The internal ID used by individual TV input services.
2296         *
2297         * <p>This is internal to the provider that inserted it, and should not be decoded by other
2298         * apps.
2299         *
2300         * <p>Can be empty.
2301         *
2302         * <p>Type: TEXT
2303         */
2304        public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
2305
2306        /**
2307         * Internal data used by individual TV input services.
2308         *
2309         * <p>This is internal to the provider that inserted it, and should not be decoded by other
2310         * apps.
2311         *
2312         * <p>Type: BLOB
2313         */
2314        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
2315
2316        /**
2317         * Internal integer flag used by individual TV input services.
2318         *
2319         * <p>This is internal to the provider that inserted it, and should not be decoded by other
2320         * apps.
2321         *
2322         * <p>Type: INTEGER
2323         */
2324        public static final String COLUMN_INTERNAL_PROVIDER_FLAG1 = "internal_provider_flag1";
2325
2326        /**
2327         * Internal integer flag used by individual TV input services.
2328         *
2329         * <p>This is internal to the provider that inserted it, and should not be decoded by other
2330         * apps.
2331         *
2332         * <p>Type: INTEGER
2333         */
2334        public static final String COLUMN_INTERNAL_PROVIDER_FLAG2 = "internal_provider_flag2";
2335
2336        /**
2337         * Internal integer flag used by individual TV input services.
2338         *
2339         * <p>This is internal to the provider that inserted it, and should not be decoded by other
2340         * apps.
2341         *
2342         * <p>Type: INTEGER
2343         */
2344        public static final String COLUMN_INTERNAL_PROVIDER_FLAG3 = "internal_provider_flag3";
2345
2346        /**
2347         * Internal integer flag used by individual TV input services.
2348         *
2349         * <p>This is internal to the provider that inserted it, and should not be decoded by other
2350         * apps.
2351         *
2352         * <p>Type: INTEGER
2353         */
2354        public static final String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
2355
2356        /**
2357         * The version number of this row entry used by TV input services.
2358         *
2359         * <p>This is best used by sync adapters to identify the rows to update. The number can be
2360         * defined by individual TV input services. One may assign the same value as
2361         * {@code version_number} that appears in ETSI EN 300 468 or ATSC A/65, if the data are
2362         * coming from a TV broadcast.
2363         *
2364         * <p>Type: INTEGER
2365         */
2366        public static final String COLUMN_VERSION_NUMBER = "version_number";
2367
2368        /**
2369         * The flag indicating whether this TV channel is transient or not.
2370         *
2371         * <p>A value of 1 indicates that the channel will be automatically removed by the system on
2372         * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
2373         * specified, this value is set to 0 (not transient) by default.
2374         *
2375         * <p>Type: INTEGER (boolean)
2376         * @see PreviewPrograms#COLUMN_TRANSIENT
2377         * @see WatchNextPrograms#COLUMN_TRANSIENT
2378         */
2379        public static final String COLUMN_TRANSIENT = "transient";
2380
2381        private Channels() {}
2382
2383        /**
2384         * A sub-directory of a single TV channel that represents its primary logo.
2385         *
2386         * <p>To access this directory, append {@link Channels.Logo#CONTENT_DIRECTORY} to the raw
2387         * channel URI.  The resulting URI represents an image file, and should be interacted
2388         * using ContentResolver.openAssetFileDescriptor.
2389         *
2390         * <p>Note that this sub-directory also supports opening the logo as an asset file in write
2391         * mode.  Callers can create or replace the primary logo associated with this channel by
2392         * opening the asset file and writing the full-size photo contents into it. (Make sure there
2393         * is no padding around the logo image.) When the file is closed, the image will be parsed,
2394         * sized down if necessary, and stored.
2395         *
2396         * <p>Usage example:
2397         * <pre>
2398         * public void writeChannelLogo(long channelId, byte[] logo) {
2399         *     Uri channelLogoUri = TvContract.buildChannelLogoUri(channelId);
2400         *     try {
2401         *         AssetFileDescriptor fd =
2402         *             getContentResolver().openAssetFileDescriptor(channelLogoUri, "rw");
2403         *         OutputStream os = fd.createOutputStream();
2404         *         os.write(logo);
2405         *         os.close();
2406         *         fd.close();
2407         *     } catch (IOException e) {
2408         *         // Handle error cases.
2409         *     }
2410         * }
2411         * </pre>
2412         */
2413        public static final class Logo {
2414
2415            /**
2416             * The directory twig for this sub-table.
2417             */
2418            public static final String CONTENT_DIRECTORY = "logo";
2419
2420            private Logo() {}
2421        }
2422    }
2423
2424    /**
2425     * Column definitions for the TV programs table.
2426     *
2427     * <p>By default, the query results will be sorted by
2428     * {@link Programs#COLUMN_START_TIME_UTC_MILLIS} in ascending order.
2429     */
2430    public static final class Programs implements BaseTvColumns, ProgramColumns {
2431
2432        /**
2433         * The content:// style URI for this table.
2434         *
2435         * <p>SQL selection is not supported for {@link ContentResolver#query},
2436         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
2437         */
2438        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
2439                + PATH_PROGRAM);
2440
2441        /** The MIME type of a directory of TV programs. */
2442        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/program";
2443
2444        /** The MIME type of a single TV program. */
2445        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
2446
2447        /**
2448         * The ID of the TV channel that provides this TV program.
2449         *
2450         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
2451         *
2452         * <p>This is a required field.
2453         *
2454         * <p>Type: INTEGER (long)
2455         */
2456        public static final String COLUMN_CHANNEL_ID = "channel_id";
2457
2458        /**
2459         * The season number of this TV program for episodic TV shows.
2460         *
2461         * <p>Can be empty.
2462         *
2463         * <p>Type: INTEGER
2464         *
2465         * @deprecated Use {@link #COLUMN_SEASON_DISPLAY_NUMBER} instead.
2466         */
2467        @Deprecated
2468        public static final String COLUMN_SEASON_NUMBER = "season_number";
2469
2470        /**
2471         * The episode number of this TV program for episodic TV shows.
2472         *
2473         * <p>Can be empty.
2474         *
2475         * <p>Type: INTEGER
2476         *
2477         * @deprecated Use {@link #COLUMN_EPISODE_DISPLAY_NUMBER} instead.
2478         */
2479        @Deprecated
2480        public static final String COLUMN_EPISODE_NUMBER = "episode_number";
2481
2482        /**
2483         * The start time of this TV program, in milliseconds since the epoch.
2484         *
2485         * <p>The value should be equal to or larger than {@link #COLUMN_END_TIME_UTC_MILLIS} of the
2486         * previous program in the same channel. In practice, start time will usually be the end
2487         * time of the previous program.
2488         *
2489         * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
2490         *
2491         * <p>Type: INTEGER (long)
2492         */
2493        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
2494
2495        /**
2496         * The end time of this TV program, in milliseconds since the epoch.
2497         *
2498         * <p>The value should be equal to or less than {@link #COLUMN_START_TIME_UTC_MILLIS} of the
2499         * next program in the same channel. In practice, end time will usually be the start time of
2500         * the next program.
2501         *
2502         * <p>Can be empty if this program belongs to a {@link Channels#TYPE_PREVIEW} channel.
2503         *
2504         * <p>Type: INTEGER (long)
2505         */
2506        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
2507
2508        /**
2509         * The comma-separated genre string of this TV program.
2510         *
2511         * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
2512         * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
2513         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
2514         * {@link Genres#encode} to create a text that can be stored in this column. Use
2515         * {@link Genres#decode} to get the broadcast genre strings from the text stored in the
2516         * column.
2517         *
2518         * <p>Type: TEXT
2519         * @see Genres#encode
2520         * @see Genres#decode
2521         */
2522        public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
2523
2524        /**
2525         * The flag indicating whether recording of this program is prohibited.
2526         *
2527         * <p>A value of 1 indicates that recording of this program is prohibited and application
2528         * will not schedule any recording for this program. A value of 0 indicates that the
2529         * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
2530         * default.
2531         *
2532         * <p>Type: INTEGER (boolean)
2533         */
2534        public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
2535
2536        private Programs() {}
2537
2538        /** Canonical genres for TV programs. */
2539        public static final class Genres {
2540            /** @hide */
2541            @StringDef({
2542                    FAMILY_KIDS,
2543                    SPORTS,
2544                    SHOPPING,
2545                    MOVIES,
2546                    COMEDY,
2547                    TRAVEL,
2548                    DRAMA,
2549                    EDUCATION,
2550                    ANIMAL_WILDLIFE,
2551                    NEWS,
2552                    GAMING,
2553                    ARTS,
2554                    ENTERTAINMENT,
2555                    LIFE_STYLE,
2556                    MUSIC,
2557                    PREMIER,
2558                    TECH_SCIENCE,
2559            })
2560            @Retention(RetentionPolicy.SOURCE)
2561            public @interface Genre {}
2562
2563            /** The genre for Family/Kids. */
2564            public static final String FAMILY_KIDS = "FAMILY_KIDS";
2565
2566            /** The genre for Sports. */
2567            public static final String SPORTS = "SPORTS";
2568
2569            /** The genre for Shopping. */
2570            public static final String SHOPPING = "SHOPPING";
2571
2572            /** The genre for Movies. */
2573            public static final String MOVIES = "MOVIES";
2574
2575            /** The genre for Comedy. */
2576            public static final String COMEDY = "COMEDY";
2577
2578            /** The genre for Travel. */
2579            public static final String TRAVEL = "TRAVEL";
2580
2581            /** The genre for Drama. */
2582            public static final String DRAMA = "DRAMA";
2583
2584            /** The genre for Education. */
2585            public static final String EDUCATION = "EDUCATION";
2586
2587            /** The genre for Animal/Wildlife. */
2588            public static final String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
2589
2590            /** The genre for News. */
2591            public static final String NEWS = "NEWS";
2592
2593            /** The genre for Gaming. */
2594            public static final String GAMING = "GAMING";
2595
2596            /** The genre for Arts. */
2597            public static final String ARTS = "ARTS";
2598
2599            /** The genre for Entertainment. */
2600            public static final String ENTERTAINMENT = "ENTERTAINMENT";
2601
2602            /** The genre for Life Style. */
2603            public static final String LIFE_STYLE = "LIFE_STYLE";
2604
2605            /** The genre for Music. */
2606            public static final String MUSIC = "MUSIC";
2607
2608            /** The genre for Premier. */
2609            public static final String PREMIER = "PREMIER";
2610
2611            /** The genre for Tech/Science. */
2612            public static final String TECH_SCIENCE = "TECH_SCIENCE";
2613
2614            private static final ArraySet<String> CANONICAL_GENRES = new ArraySet<>();
2615            static {
2616                CANONICAL_GENRES.add(FAMILY_KIDS);
2617                CANONICAL_GENRES.add(SPORTS);
2618                CANONICAL_GENRES.add(SHOPPING);
2619                CANONICAL_GENRES.add(MOVIES);
2620                CANONICAL_GENRES.add(COMEDY);
2621                CANONICAL_GENRES.add(TRAVEL);
2622                CANONICAL_GENRES.add(DRAMA);
2623                CANONICAL_GENRES.add(EDUCATION);
2624                CANONICAL_GENRES.add(ANIMAL_WILDLIFE);
2625                CANONICAL_GENRES.add(NEWS);
2626                CANONICAL_GENRES.add(GAMING);
2627                CANONICAL_GENRES.add(ARTS);
2628                CANONICAL_GENRES.add(ENTERTAINMENT);
2629                CANONICAL_GENRES.add(LIFE_STYLE);
2630                CANONICAL_GENRES.add(MUSIC);
2631                CANONICAL_GENRES.add(PREMIER);
2632                CANONICAL_GENRES.add(TECH_SCIENCE);
2633            }
2634
2635            private static final char DOUBLE_QUOTE = '"';
2636            private static final char COMMA = ',';
2637            private static final String DELIMITER = ",";
2638
2639            private static final String[] EMPTY_STRING_ARRAY = new String[0];
2640
2641            private Genres() {}
2642
2643            /**
2644             * Encodes genre strings to a text that can be put into the database.
2645             *
2646             * @param genres Genre strings.
2647             * @return an encoded genre string that can be inserted into the
2648             *         {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
2649             */
2650            public static String encode(@NonNull @Genre String... genres) {
2651                if (genres == null) {
2652                    // MNC and before will throw a NPE.
2653                    return null;
2654                }
2655                StringBuilder sb = new StringBuilder();
2656                String separator = "";
2657                for (String genre : genres) {
2658                    sb.append(separator).append(encodeToCsv(genre));
2659                    separator = DELIMITER;
2660                }
2661                return sb.toString();
2662            }
2663
2664            private static String encodeToCsv(String genre) {
2665                StringBuilder sb = new StringBuilder();
2666                int length = genre.length();
2667                for (int i = 0; i < length; ++i) {
2668                    char c = genre.charAt(i);
2669                    switch (c) {
2670                        case DOUBLE_QUOTE:
2671                            sb.append(DOUBLE_QUOTE);
2672                            break;
2673                        case COMMA:
2674                            sb.append(DOUBLE_QUOTE);
2675                            break;
2676                    }
2677                    sb.append(c);
2678                }
2679                return sb.toString();
2680            }
2681
2682            /**
2683             * Decodes the genre strings from the text stored in the database.
2684             *
2685             * @param genres The encoded genre string retrieved from the
2686             *            {@link #COLUMN_BROADCAST_GENRE} or {@link #COLUMN_CANONICAL_GENRE} column.
2687             * @return genre strings.
2688             */
2689            public static @Genre String[] decode(@NonNull String genres) {
2690                if (TextUtils.isEmpty(genres)) {
2691                    // MNC and before will throw a NPE for {@code null} genres.
2692                    return EMPTY_STRING_ARRAY;
2693                }
2694                if (genres.indexOf(COMMA) == -1 && genres.indexOf(DOUBLE_QUOTE) == -1) {
2695                    return new String[] {genres.trim()};
2696                }
2697                StringBuilder sb = new StringBuilder();
2698                List<String> results = new ArrayList<>();
2699                int length = genres.length();
2700                boolean escape = false;
2701                for (int i = 0; i < length; ++i) {
2702                    char c = genres.charAt(i);
2703                    switch (c) {
2704                        case DOUBLE_QUOTE:
2705                            if (!escape) {
2706                                escape = true;
2707                                continue;
2708                            }
2709                            break;
2710                        case COMMA:
2711                            if (!escape) {
2712                                String string = sb.toString().trim();
2713                                if (string.length() > 0) {
2714                                    results.add(string);
2715                                }
2716                                sb = new StringBuilder();
2717                                continue;
2718                            }
2719                            break;
2720                    }
2721                    sb.append(c);
2722                    escape = false;
2723                }
2724                String string = sb.toString().trim();
2725                if (string.length() > 0) {
2726                    results.add(string);
2727                }
2728                return results.toArray(new String[results.size()]);
2729            }
2730
2731            /**
2732             * Returns whether a given text is a canonical genre defined in {@link Genres}.
2733             *
2734             * @param genre The name of genre to be checked.
2735             * @return {@code true} if the genre is canonical, otherwise {@code false}.
2736             */
2737            public static boolean isCanonical(String genre) {
2738                return CANONICAL_GENRES.contains(genre);
2739            }
2740        }
2741    }
2742
2743    /**
2744     * Column definitions for the recorded TV programs table.
2745     *
2746     * <p>By default, the query results will be sorted by {@link #COLUMN_START_TIME_UTC_MILLIS} in
2747     * ascending order.
2748     */
2749    public static final class RecordedPrograms implements BaseTvColumns, ProgramColumns {
2750
2751        /**
2752         * The content:// style URI for this table.
2753         *
2754         * <p>SQL selection is not supported for {@link ContentResolver#query},
2755         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
2756         */
2757        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
2758                + PATH_RECORDED_PROGRAM);
2759
2760        /** The MIME type of a directory of recorded TV programs. */
2761        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/recorded_program";
2762
2763        /** The MIME type of a single recorded TV program. */
2764        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
2765
2766        /**
2767         * The ID of the TV channel that provides this recorded program.
2768         *
2769         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
2770         *
2771         * <p>Type: INTEGER (long)
2772         */
2773        public static final String COLUMN_CHANNEL_ID = "channel_id";
2774
2775        /**
2776         * The ID of the TV input service that is associated with this recorded program.
2777         *
2778         * <p>Use {@link #buildInputId} to build the ID.
2779         *
2780         * <p>This is a required field.
2781         *
2782         * <p>Type: TEXT
2783         */
2784        public static final String COLUMN_INPUT_ID = "input_id";
2785
2786        /**
2787         * The start time of the original TV program, in milliseconds since the epoch.
2788         *
2789         * <p>Type: INTEGER (long)
2790         * @see Programs#COLUMN_START_TIME_UTC_MILLIS
2791         */
2792        public static final String COLUMN_START_TIME_UTC_MILLIS =
2793                Programs.COLUMN_START_TIME_UTC_MILLIS;
2794
2795        /**
2796         * The end time of the original TV program, in milliseconds since the epoch.
2797         *
2798         * <p>Type: INTEGER (long)
2799         * @see Programs#COLUMN_END_TIME_UTC_MILLIS
2800         */
2801        public static final String COLUMN_END_TIME_UTC_MILLIS = Programs.COLUMN_END_TIME_UTC_MILLIS;
2802
2803        /**
2804         * The comma-separated genre string of this recorded TV program.
2805         *
2806         * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
2807         * (For example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
2808         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty. Use
2809         * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
2810         * Use {@link Genres#decode Genres.decode()} to get the broadcast genre strings from the
2811         * text stored in the column.
2812         *
2813         * <p>Type: TEXT
2814         * @see Programs#COLUMN_BROADCAST_GENRE
2815         */
2816        public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
2817
2818        /**
2819         * The URI of the recording data for this recorded program.
2820         *
2821         * <p>Together with {@link #COLUMN_RECORDING_DATA_BYTES}, applications can use this
2822         * information to manage recording storage. The URI should indicate a file or directory with
2823         * the scheme {@link android.content.ContentResolver#SCHEME_FILE}.
2824         *
2825         * <p>Type: TEXT
2826         * @see #COLUMN_RECORDING_DATA_BYTES
2827         */
2828        public static final String COLUMN_RECORDING_DATA_URI = "recording_data_uri";
2829
2830        /**
2831         * The data size (in bytes) for this recorded program.
2832         *
2833         * <p>Together with {@link #COLUMN_RECORDING_DATA_URI}, applications can use this
2834         * information to manage recording storage.
2835         *
2836         * <p>Type: INTEGER (long)
2837         * @see #COLUMN_RECORDING_DATA_URI
2838         */
2839        public static final String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
2840
2841        /**
2842         * The duration (in milliseconds) of this recorded program.
2843         *
2844         * <p>The actual duration of the recorded program can differ from the one calculated by
2845         * {@link #COLUMN_END_TIME_UTC_MILLIS} - {@link #COLUMN_START_TIME_UTC_MILLIS} as program
2846         * recording can be interrupted in the middle for some reason, resulting in a partially
2847         * recorded program, which is still playable.
2848         *
2849         * <p>Type: INTEGER
2850         */
2851        public static final String COLUMN_RECORDING_DURATION_MILLIS = "recording_duration_millis";
2852
2853        /**
2854         * The expiration time for this recorded program, in milliseconds since the epoch.
2855         *
2856         * <p>Recorded TV programs do not expire by default unless explicitly requested by the user
2857         * or the user allows applications to delete them in order to free up disk space for future
2858         * recording. However, some TV content can have expiration date set by the content provider
2859         * when recorded. This field is used to indicate such a restriction.
2860         *
2861         * <p>Can be empty.
2862         *
2863         * <p>Type: INTEGER (long)
2864         */
2865        public static final String COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS =
2866                "recording_expire_time_utc_millis";
2867
2868        private RecordedPrograms() {}
2869    }
2870
2871    /**
2872     * Column definitions for the preview TV programs table.
2873     */
2874    public static final class PreviewPrograms implements BaseTvColumns, ProgramColumns,
2875        PreviewProgramColumns {
2876
2877        /**
2878         * The content:// style URI for this table.
2879         *
2880         * <p>SQL selection is not supported for {@link ContentResolver#query},
2881         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
2882         */
2883        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
2884                + PATH_PREVIEW_PROGRAM);
2885
2886        /** The MIME type of a directory of preview TV programs. */
2887        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
2888
2889        /** The MIME type of a single preview TV program. */
2890        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
2891
2892        /**
2893         * The ID of the TV channel that provides this TV program.
2894         *
2895         * <p>This value cannot be changed once it's set. Trying to modify it will make the update
2896         * fail.
2897         *
2898         * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
2899         *
2900         * <p>This is a required field.
2901         *
2902         * <p>Type: INTEGER (long)
2903         */
2904        public static final String COLUMN_CHANNEL_ID = "channel_id";
2905
2906        /**
2907         * The weight of the preview program within the channel.
2908         *
2909         * <p>The UI may choose to show this item in a different position in the channel row.
2910         * A larger weight value means the program is more important than other programs having
2911         * smaller weight values. The value is relevant for the preview programs in the same
2912         * channel. This is only relevant to {@link Channels#TYPE_PREVIEW}.
2913         *
2914         * <p>Can be empty.
2915         *
2916         * <p>Type: INTEGER
2917         */
2918        public static final String COLUMN_WEIGHT = "weight";
2919
2920        private PreviewPrograms() {}
2921    }
2922
2923    /**
2924     * Column definitions for the "watch next" TV programs table.
2925     */
2926    public static final class WatchNextPrograms implements BaseTvColumns, ProgramColumns,
2927        PreviewProgramColumns {
2928
2929        /**
2930         * The content:// style URI for this table.
2931         *
2932         * <p>SQL selection is not supported for {@link ContentResolver#query},
2933         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
2934         */
2935        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
2936                + PATH_WATCH_NEXT_PROGRAM);
2937
2938        /** The MIME type of a directory of "watch next" TV programs. */
2939        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
2940
2941        /** The MIME type of a single preview TV program. */
2942        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
2943
2944        /** @hide */
2945        @IntDef({
2946                WATCH_NEXT_TYPE_CONTINUE,
2947                WATCH_NEXT_TYPE_NEXT,
2948                WATCH_NEXT_TYPE_NEW,
2949                WATCH_NEXT_TYPE_WATCHLIST,
2950        })
2951        @Retention(RetentionPolicy.SOURCE)
2952        public @interface WatchNextType {}
2953
2954        /**
2955         * The watch next type for CONTINUE. Use this type when the user has already watched more
2956         * than 1 minute of this content.
2957         *
2958         * @see #COLUMN_WATCH_NEXT_TYPE
2959         */
2960        public static final int WATCH_NEXT_TYPE_CONTINUE = 0;
2961
2962        /**
2963         * The watch next type for NEXT. Use this type when the user has watched one or more
2964         * complete episodes from some episodic content, but there remains more than one episode
2965         * remaining or there is one last episode remaining, but it is not “new” in that it was
2966         * released before the user started watching the show.
2967         *
2968         * @see #COLUMN_WATCH_NEXT_TYPE
2969         */
2970        public static final int WATCH_NEXT_TYPE_NEXT = 1;
2971
2972        /**
2973         * The watch next type for NEW. Use this type when the user had watched all of the available
2974         * episodes from some episodic content, but a new episode became available since the user
2975         * started watching the first episode and now there is exactly one unwatched episode. This
2976         * could also work for recorded events in a series e.g. soccer matches or football games.
2977         *
2978         * @see #COLUMN_WATCH_NEXT_TYPE
2979         */
2980        public static final int WATCH_NEXT_TYPE_NEW = 2;
2981
2982        /**
2983         * The watch next type for WATCHLIST. Use this type when the user has elected to explicitly
2984         * add a movie, event or series to a “watchlist” as a manual way of curating what they
2985         * want to watch next.
2986         *
2987         * @see #COLUMN_WATCH_NEXT_TYPE
2988         */
2989        public static final int WATCH_NEXT_TYPE_WATCHLIST = 3;
2990
2991        /**
2992         * The "watch next" type of this program content.
2993         *
2994         * <p>The value should match one of the followings:
2995         * {@link #WATCH_NEXT_TYPE_CONTINUE},
2996         * {@link #WATCH_NEXT_TYPE_NEXT},
2997         * {@link #WATCH_NEXT_TYPE_NEW}, and
2998         * {@link #WATCH_NEXT_TYPE_WATCHLIST}.
2999         *
3000         * <p>This is a required field.
3001         *
3002         * <p>Type: INTEGER
3003         */
3004        public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
3005
3006        /**
3007         * The last UTC time that the user engaged in this TV program, in milliseconds since the
3008         * epoch. This is a hint for the application that is used for ordering of "watch next"
3009         * programs.
3010         *
3011         * <p>The meaning of the value varies depending on the {@link #COLUMN_WATCH_NEXT_TYPE}:
3012         * <ul>
3013         *     <li>{@link #WATCH_NEXT_TYPE_CONTINUE}: the date that the user was last watching the
3014         *     content.</li>
3015         *     <li>{@link #WATCH_NEXT_TYPE_NEXT}: the date of the last episode watched.</li>
3016         *     <li>{@link #WATCH_NEXT_TYPE_NEW}: the release date of the new episode.</li>
3017         *     <li>{@link #WATCH_NEXT_TYPE_WATCHLIST}: the date the item was added to the Watchlist.
3018         *     </li>
3019         * </ul>
3020         *
3021         * <p>This is a required field.
3022         *
3023         * <p>Type: INTEGER (long)
3024         */
3025        public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS =
3026                "last_engagement_time_utc_millis";
3027
3028        private WatchNextPrograms() {}
3029    }
3030
3031    /**
3032     * Column definitions for the TV programs that the user watched. Applications do not have access
3033     * to this table.
3034     *
3035     * <p>By default, the query results will be sorted by
3036     * {@link WatchedPrograms#COLUMN_WATCH_START_TIME_UTC_MILLIS} in descending order.
3037     * @hide
3038     */
3039    @SystemApi
3040    public static final class WatchedPrograms implements BaseTvColumns {
3041
3042        /** The content:// style URI for this table. */
3043        public static final Uri CONTENT_URI =
3044                Uri.parse("content://" + AUTHORITY + "/watched_program");
3045
3046        /** The MIME type of a directory of watched programs. */
3047        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
3048
3049        /** The MIME type of a single item in this table. */
3050        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
3051
3052        /**
3053         * The UTC time that the user started watching this TV program, in milliseconds since the
3054         * epoch.
3055         *
3056         * <p>Type: INTEGER (long)
3057         */
3058        public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS =
3059                "watch_start_time_utc_millis";
3060
3061        /**
3062         * The UTC time that the user stopped watching this TV program, in milliseconds since the
3063         * epoch.
3064         *
3065         * <p>Type: INTEGER (long)
3066         */
3067        public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
3068
3069        /**
3070         * The ID of the TV channel that provides this TV program.
3071         *
3072         * <p>This is a required field.
3073         *
3074         * <p>Type: INTEGER (long)
3075         */
3076        public static final String COLUMN_CHANNEL_ID = "channel_id";
3077
3078        /**
3079         * The title of this TV program.
3080         *
3081         * <p>Type: TEXT
3082         */
3083        public static final String COLUMN_TITLE = "title";
3084
3085        /**
3086         * The start time of this TV program, in milliseconds since the epoch.
3087         *
3088         * <p>Type: INTEGER (long)
3089         */
3090        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
3091
3092        /**
3093         * The end time of this TV program, in milliseconds since the epoch.
3094         *
3095         * <p>Type: INTEGER (long)
3096         */
3097        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
3098
3099        /**
3100         * The description of this TV program.
3101         *
3102         * <p>Type: TEXT
3103         */
3104        public static final String COLUMN_DESCRIPTION = "description";
3105
3106        /**
3107         * Extra parameters given to {@link TvInputService.Session#tune(Uri, android.os.Bundle)
3108         * TvInputService.Session.tune(Uri, android.os.Bundle)} when tuning to the channel that
3109         * provides this TV program. (Used internally.)
3110         *
3111         * <p>This column contains an encoded string that represents comma-separated key-value pairs of
3112         * the tune parameters. (Ex. "[key1]=[value1], [key2]=[value2]"). '%' is used as an escape
3113         * character for '%', '=', and ','.
3114         *
3115         * <p>Type: TEXT
3116         */
3117        public static final String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params";
3118
3119        /**
3120         * The session token of this TV program. (Used internally.)
3121         *
3122         * <p>This contains a String representation of {@link IBinder} for
3123         * {@link TvInputService.Session} that provides the current TV program. It is used
3124         * internally to distinguish watched programs entries from different TV input sessions.
3125         *
3126         * <p>Type: TEXT
3127         */
3128        public static final String COLUMN_INTERNAL_SESSION_TOKEN = "session_token";
3129
3130        private WatchedPrograms() {}
3131    }
3132}
3133