TvContract.java revision 579befecb248162021929ab58ffd23f1724cc6be
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.SystemApi;
20import android.content.ComponentName;
21import android.content.ContentResolver;
22import android.content.ContentUris;
23import android.media.tv.TvContract.Programs;
24import android.net.Uri;
25import android.provider.BaseColumns;
26import android.util.ArraySet;
27
28import java.util.HashMap;
29import java.util.List;
30import java.util.Map;
31
32/**
33 * <p>
34 * The contract between the TV provider and applications. Contains definitions for the supported
35 * URIs and columns.
36 * </p>
37 * <h3>Overview</h3>
38 * <p>
39 * TvContract defines a basic database of TV content metadata such as channel and program
40 * information. The information is stored in {@link Channels} and {@link Programs} tables.
41 * </p>
42 * <ul>
43 *     <li>A row in the {@link Channels} table represents information about a TV channel. The data
44 *         format can vary greatly from standard to standard or according to service provider, thus
45 *         the columns here are mostly comprised of basic entities that are usually seen to users
46 *         regardless of standard such as channel number and name.</li>
47 *     <li>A row in the {@link Programs} table represents a set of data describing a TV program such
48 *         as program title and start time.</li>
49 * </ul>
50 */
51public final class TvContract {
52    /** The authority for the TV provider. */
53    public static final String AUTHORITY = "android.media.tv";
54
55    private static final String PATH_CHANNEL = "channel";
56    private static final String PATH_PROGRAM = "program";
57    private static final String PATH_INPUT = "input";
58    private static final String PATH_PASSTHROUGH = "passthrough";
59
60    /**
61     * An optional query, update or delete URI parameter that allows the caller to specify start
62     * time (in milliseconds since the epoch) to filter programs.
63     *
64     * @hide
65     */
66    public static final String PARAM_START_TIME = "start_time";
67
68    /**
69     * An optional query, update or delete URI parameter that allows the caller to specify end time
70     * (in milliseconds since the epoch) to filter programs.
71     *
72     * @hide
73     */
74    public static final String PARAM_END_TIME = "end_time";
75
76    /**
77     * A query, update or delete URI parameter that allows the caller to operate on all or
78     * browsable-only channels. If set to "true", the rows that contain non-browsable channels are
79     * not affected.
80     *
81     * @hide
82     */
83    public static final String PARAM_BROWSABLE_ONLY = "browsable_only";
84
85    /**
86     * A optional query, update or delete URI parameter that allows the caller to specify canonical
87     * genre to filter programs.
88     *
89     * @hide
90     */
91    public static final String PARAM_CANONICAL_GENRE = "canonical_genre";
92
93    /**
94     * Builds an ID that uniquely identifies a TV input service.
95     *
96     * @param name The {@link ComponentName} of the TV input service to build ID for.
97     * @return the ID for the given TV input service.
98     */
99    public static final String buildInputId(ComponentName name) {
100        return name.flattenToShortString();
101    }
102
103    /**
104     * Builds a URI that points to a specific channel.
105     *
106     * @param channelId The ID of the channel to point to.
107     */
108    public static final Uri buildChannelUri(long channelId) {
109        return ContentUris.withAppendedId(Channels.CONTENT_URI, channelId);
110    }
111
112    /**
113     * Build a special channel URI intended to be used with pass-through type inputs. (e.g. HDMI)
114     *
115     * @param inputId The ID of the TV input to build a channels URI for.
116     * @see TvInputInfo#isPassthroughInputType()
117     */
118    public static final Uri buildChannelUriForPassthroughTvInput(String inputId) {
119        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
120                .appendPath(PATH_INPUT).appendPath(inputId).appendPath(PATH_CHANNEL)
121                .appendPath(PATH_PASSTHROUGH).build();
122    }
123
124    /**
125     * Returns true, if {@code channelUri} is a channel URI for a passthrough TV input.
126     * @hide
127     */
128    @SystemApi
129    public static final boolean isChannelUriForPassthroughTvInput(Uri channelUri) {
130        return channelUri.toString().endsWith(PATH_PASSTHROUGH);
131    }
132
133    /**
134     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
135     *
136     * @param channelId The ID of the channel whose logo is pointed to.
137     */
138    public static final Uri buildChannelLogoUri(long channelId) {
139        return buildChannelLogoUri(buildChannelUri(channelId));
140    }
141
142    /**
143     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
144     *
145     * @param channelUri The URI of the channel whose logo is pointed to.
146     */
147    public static final Uri buildChannelLogoUri(Uri channelUri) {
148        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
149            throw new IllegalArgumentException("Not a channel: " + channelUri);
150        }
151        return Uri.withAppendedPath(channelUri, Channels.Logo.CONTENT_DIRECTORY);
152    }
153
154    /**
155     * Builds a URI that points to all channels from a given TV input.
156     *
157     * @param inputId The ID of the TV input to build a channels URI for.
158     */
159    public static final Uri buildChannelsUriForInput(String inputId) {
160        return buildChannelsUriForInput(inputId, false);
161    }
162
163    /**
164     * Builds a URI that points to all or browsable-only channels from a given TV input.
165     *
166     * @param inputId The ID of the TV input to build a channels URI for.
167     * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set
168     *            to {@code false} the URI points to all channels regardless of whether they are
169     *            browsable or not.
170     * @hide
171     */
172    public static final Uri buildChannelsUriForInput(String inputId, boolean browsableOnly) {
173        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
174                .appendPath(PATH_INPUT).appendPath(inputId).appendPath(PATH_CHANNEL)
175                .appendQueryParameter(PARAM_BROWSABLE_ONLY, String.valueOf(browsableOnly)).build();
176    }
177
178    /**
179     * Builds a URI that points to all or browsable-only channels which have programs with the given
180     * genre from the given TV input.
181     *
182     * @param inputId The ID of the TV input to build a channels URI for. If null, builds a URI for
183     *            all the TV inputs.
184     * @param genre {@link Programs.Genres} to search.
185     * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set
186     *            to {@code false} the URI points to all channels regardless of whether they are
187     *            browsable or not.
188     * @hide
189     */
190    public static final Uri buildChannelsUriForCanonicalGenre(String inputId, String genre,
191            boolean browsableOnly) {
192        if (!Programs.Genres.isCanonical(genre)) {
193            throw new IllegalArgumentException("Not a canonical genre: '" + genre + "'");
194        }
195
196        Uri uri;
197        if (inputId == null) {
198            uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
199                    .appendPath(PATH_CHANNEL).build();
200        } else {
201            uri = buildChannelsUriForInput(inputId, browsableOnly);
202        }
203        return uri.buildUpon().appendQueryParameter(PARAM_CANONICAL_GENRE, genre).build();
204    }
205
206    /**
207     * Builds a URI that points to a specific program.
208     *
209     * @param programId The ID of the program to point to.
210     */
211    public static final Uri buildProgramUri(long programId) {
212        return ContentUris.withAppendedId(Programs.CONTENT_URI, programId);
213    }
214
215    /**
216     * Builds a URI that points to all programs on a given channel.
217     *
218     * @param channelId The ID of the channel to return programs for.
219     */
220    public static final Uri buildProgramsUriForChannel(long channelId) {
221        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
222                .appendPath(PATH_CHANNEL).appendPath(String.valueOf(channelId))
223                .appendPath(PATH_PROGRAM).build();
224    }
225
226    /**
227     * Builds a URI that points to all programs on a given channel.
228     *
229     * @param channelUri The URI of the channel to return programs for.
230     */
231    public static final Uri buildProgramsUriForChannel(Uri channelUri) {
232        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
233            throw new IllegalArgumentException("Not a channel: " + channelUri);
234        }
235        return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
236    }
237
238    /**
239     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
240     * given time frame.
241     *
242     * @param channelId The ID of the channel to return programs for.
243     * @param startTime The start time used to filter programs. The returned programs should have
244     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
245     * @param endTime The end time used to filter programs. The returned programs should have
246     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
247     */
248    public static final Uri buildProgramsUriForChannel(long channelId, long startTime,
249            long endTime) {
250        Uri uri = buildProgramsUriForChannel(channelId);
251        return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
252                .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
253    }
254
255    /**
256     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
257     * given time frame.
258     *
259     * @param channelUri The URI of the channel to return programs for.
260     * @param startTime The start time used to filter programs. The returned programs should have
261     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
262     * @param endTime The end time used to filter programs. The returned programs should have
263     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
264     */
265    public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
266            long endTime) {
267        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
268            throw new IllegalArgumentException("Not a channel: " + channelUri);
269        }
270        return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
271    }
272
273    /**
274     * Builds a URI that points to a specific program the user watched.
275     *
276     * @param watchedProgramId The ID of the watched program to point to.
277     * @hide
278     */
279    public static final Uri buildWatchedProgramUri(long watchedProgramId) {
280        return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId);
281    }
282
283    /**
284     * Extracts the {@link Channels#COLUMN_INPUT_ID} from a given URI.
285     *
286     * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(String)},
287     *            {@link #buildChannelsUriForInput(String, boolean)}, or
288     *            {@link #buildChannelsUriForCanonicalGenre(String, String, boolean)}.
289     * @hide
290     */
291    public static final String getInputId(Uri channelsUri) {
292        final List<String> paths = channelsUri.getPathSegments();
293        if (paths.size() < 3) {
294            throw new IllegalArgumentException("Not channels: " + channelsUri);
295        }
296        if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(2))) {
297            throw new IllegalArgumentException("Not channels: " + channelsUri);
298        }
299        return paths.get(1);
300    }
301
302    /**
303     * Extracts the {@link Channels#_ID} from a given URI.
304     *
305     * @param programsUri A URI constructed by {@link #buildProgramsUriForChannel(Uri)} or
306     *            {@link #buildProgramsUriForChannel(Uri, long, long)}.
307     * @hide
308     */
309    public static final String getChannelId(Uri programsUri) {
310        final List<String> paths = programsUri.getPathSegments();
311        if (paths.size() < 3) {
312            throw new IllegalArgumentException("Not programs: " + programsUri);
313        }
314        if (!PATH_CHANNEL.equals(paths.get(0)) || !PATH_PROGRAM.equals(paths.get(2))) {
315            throw new IllegalArgumentException("Not programs: " + programsUri);
316        }
317        return paths.get(1);
318    }
319
320
321    private TvContract() {}
322
323    /**
324     * Common base for the tables of TV channels/programs.
325     */
326    public interface BaseTvColumns extends BaseColumns {
327        /**
328         * The name of the package that owns a row in each table.
329         * <p>
330         * The TV provider fills it in with the name of the package that provides the initial data
331         * of that row. If the package is later uninstalled, the rows it owns are automatically
332         * removed from the tables.
333         * </p><p>
334         * Type: TEXT
335         * </p>
336         */
337        public static final String COLUMN_PACKAGE_NAME = "package_name";
338    }
339
340    /** Column definitions for the TV channels table. */
341    public static final class Channels implements BaseTvColumns {
342
343        /** The content:// style URI for this table. */
344        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
345                + PATH_CHANNEL);
346
347        /** The MIME type of a directory of TV channels. */
348        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
349
350        /** The MIME type of a single TV channel. */
351        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
352
353        /** A generic channel type. */
354        public static final String TYPE_OTHER = "TYPE_OTHER";
355
356        /** The channel type for NTSC. */
357        public static final String TYPE_NTSC = "TYPE_NTSC";
358
359        /** The channel type for PAL. */
360        public static final String TYPE_PAL = "TYPE_PAL";
361
362        /** The channel type for SECAM. */
363        public static final String TYPE_SECAM = "TYPE_SECAM";
364
365        /** The channel type for DVB-T (terrestrial). */
366        public static final String TYPE_DVB_T = "TYPE_DVB_T";
367
368        /** The channel type for DVB-T2 (terrestrial). */
369        public static final String TYPE_DVB_T2 = "TYPE_DVB_T2";
370
371        /** The channel type for DVB-S (satellite). */
372        public static final String TYPE_DVB_S = "TYPE_DVB_S";
373
374        /** The channel type for DVB-S2 (satellite). */
375        public static final String TYPE_DVB_S2 = "TYPE_DVB_S2";
376
377        /** The channel type for DVB-C (cable). */
378        public static final String TYPE_DVB_C = "TYPE_DVB_C";
379
380        /** The channel type for DVB-C2 (cable). */
381        public static final String TYPE_DVB_C2 = "TYPE_DVB_C2";
382
383        /** The channel type for DVB-H (handheld). */
384        public static final String TYPE_DVB_H = "TYPE_DVB_H";
385
386        /** The channel type for DVB-SH (satellite). */
387        public static final String TYPE_DVB_SH = "TYPE_DVB_SH";
388
389        /** The channel type for ATSC (terrestrial). */
390        public static final String TYPE_ATSC_T = "TYPE_ATSC_T";
391
392        /** The channel type for ATSC (cable). */
393        public static final String TYPE_ATSC_C = "TYPE_ATSC_C";
394
395        /** The channel type for ATSC-M/H (mobile/handheld). */
396        public static final String TYPE_ATSC_M_H = "TYPE_ATSC_M_H";
397
398        /** The channel type for ISDB-T (terrestrial). */
399        public static final String TYPE_ISDB_T = "TYPE_ISDB_T";
400
401        /** The channel type for ISDB-Tb (Brazil). */
402        public static final String TYPE_ISDB_TB = "TYPE_ISDB_TB";
403
404        /** The channel type for ISDB-S (satellite). */
405        public static final String TYPE_ISDB_S = "TYPE_ISDB_S";
406
407        /** The channel type for ISDB-C (cable). */
408        public static final String TYPE_ISDB_C = "TYPE_ISDB_C";
409
410        /** The channel type for 1seg (handheld). */
411        public static final String TYPE_1SEG = "TYPE_1SEG";
412
413        /** The channel type for DTMB (terrestrial). */
414        public static final String TYPE_DTMB = "TYPE_DTMB";
415
416        /** The channel type for CMMB (handheld). */
417        public static final String TYPE_CMMB = "TYPE_CMMB";
418
419        /** The channel type for T-DMB (terrestrial). */
420        public static final String TYPE_T_DMB = "TYPE_T_DMB";
421
422        /** The channel type for S-DMB (satellite). */
423        public static final String TYPE_S_DMB = "TYPE_S_DMB";
424
425        /** A generic service type. */
426        public static final String SERVICE_TYPE_OTHER = "SERVICE_TYPE_OTHER";
427
428        /** The service type for regular TV channels that have both audio and video. */
429        public static final String SERVICE_TYPE_AUDIO_VIDEO = "SERVICE_TYPE_AUDIO_VIDEO";
430
431        /** The service type for radio channels that have audio only. */
432        public static final String SERVICE_TYPE_AUDIO = "SERVICE_TYPE_AUDIO";
433
434        /** The video format for 240p. */
435        public static final String VIDEO_FORMAT_240P = "VIDEO_FORMAT_240P";
436
437        /** The video format for 360p. */
438        public static final String VIDEO_FORMAT_360P = "VIDEO_FORMAT_360P";
439
440        /** The video format for 480i. */
441        public static final String VIDEO_FORMAT_480I = "VIDEO_FORMAT_480I";
442
443        /** The video format for 480p. */
444        public static final String VIDEO_FORMAT_480P = "VIDEO_FORMAT_480P";
445
446        /** The video format for 576i. */
447        public static final String VIDEO_FORMAT_576I = "VIDEO_FORMAT_576I";
448
449        /** The video format for 576p. */
450        public static final String VIDEO_FORMAT_576P = "VIDEO_FORMAT_576P";
451
452        /** The video format for 720p. */
453        public static final String VIDEO_FORMAT_720P = "VIDEO_FORMAT_720P";
454
455        /** The video format for 1080i. */
456        public static final String VIDEO_FORMAT_1080I = "VIDEO_FORMAT_1080I";
457
458        /** The video format for 1080p. */
459        public static final String VIDEO_FORMAT_1080P = "VIDEO_FORMAT_1080P";
460
461        /** The video format for 2160p. */
462        public static final String VIDEO_FORMAT_2160P = "VIDEO_FORMAT_2160P";
463
464        /** The video format for 4320p. */
465        public static final String VIDEO_FORMAT_4320P = "VIDEO_FORMAT_4320P";
466
467        /** The video resolution for standard-definition. */
468        public static final String VIDEO_RESOLUTION_SD = "VIDEO_RESOLUTION_SD";
469
470        /** The video resolution for enhanced-definition. */
471        public static final String VIDEO_RESOLUTION_ED = "VIDEO_RESOLUTION_ED";
472
473        /** The video resolution for high-definition. */
474        public static final String VIDEO_RESOLUTION_HD = "VIDEO_RESOLUTION_HD";
475
476        /** The video resolution for full high-definition. */
477        public static final String VIDEO_RESOLUTION_FHD = "VIDEO_RESOLUTION_FHD";
478
479        /** The video resolution for ultra high-definition. */
480        public static final String VIDEO_RESOLUTION_UHD = "VIDEO_RESOLUTION_UHD";
481
482        private static final Map<String, String> VIDEO_FORMAT_TO_RESOLUTION_MAP =
483                new HashMap<String, String>();
484
485        static {
486            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_480I, VIDEO_RESOLUTION_SD);
487            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_480P, VIDEO_RESOLUTION_ED);
488            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_576I, VIDEO_RESOLUTION_SD);
489            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_576P, VIDEO_RESOLUTION_ED);
490            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_720P, VIDEO_RESOLUTION_HD);
491            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_1080I, VIDEO_RESOLUTION_HD);
492            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_1080P, VIDEO_RESOLUTION_FHD);
493            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_2160P, VIDEO_RESOLUTION_UHD);
494            VIDEO_FORMAT_TO_RESOLUTION_MAP.put(VIDEO_FORMAT_4320P, VIDEO_RESOLUTION_UHD);
495        }
496
497        /**
498         * Returns the video resolution (definition) for a given video format.
499         *
500         * @param videoFormat The video format defined in {@link Channels}.
501         * @return the corresponding video resolution string. {@code null} if the resolution string
502         *         is not defined for the given video format.
503         * @see #COLUMN_VIDEO_FORMAT
504         */
505        public static final String getVideoResolution(String videoFormat) {
506            return VIDEO_FORMAT_TO_RESOLUTION_MAP.get(videoFormat);
507        }
508
509        /**
510         * The ID of the TV input service that provides this TV channel.
511         * <p>
512         * Use {@link #buildInputId} to build the ID.
513         * </p><p>
514         * This is a required field.
515         * </p><p>
516         * Type: TEXT
517         * </p>
518         */
519        public static final String COLUMN_INPUT_ID = "input_id";
520
521        /**
522         * The predefined type of this TV channel.
523         * <p>
524         * This is primarily used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the
525         * current channel conforms to. The value should match to one of the followings:
526         * {@link #TYPE_OTHER}, {@link #TYPE_DVB_T}, {@link #TYPE_DVB_T2}, {@link #TYPE_DVB_S},
527         * {@link #TYPE_DVB_S2}, {@link #TYPE_DVB_C}, {@link #TYPE_DVB_C2}, {@link #TYPE_DVB_H},
528         * {@link #TYPE_DVB_SH}, {@link #TYPE_ATSC_T}, {@link #TYPE_ATSC_C},
529         * {@link #TYPE_ATSC_M_H}, {@link #TYPE_ISDB_T}, {@link #TYPE_ISDB_TB},
530         * {@link #TYPE_ISDB_S}, {@link #TYPE_ISDB_C}, {@link #TYPE_1SEG}, {@link #TYPE_DTMB},
531         * {@link #TYPE_CMMB}, {@link #TYPE_T_DMB}, {@link #TYPE_S_DMB}
532         * </p><p>
533         * This is a required field.
534         * </p><p>
535         * Type: TEXT
536         * </p>
537         */
538        public static final String COLUMN_TYPE = "type";
539
540        /**
541         * The predefined service type of this TV channel.
542         * <p>
543         * This is primarily used to indicate whether the current channel is a regular TV channel or
544         * a radio-like channel. Use the same coding for {@code service_type} in the underlying
545         * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB
546         * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER},
547         * {@link #SERVICE_TYPE_AUDIO_VIDEO}, {@link #SERVICE_TYPE_AUDIO}
548         * </p><p>
549         * This is a required field.
550         * </p><p>
551         * Type: TEXT
552         * </p>
553         */
554        public static final String COLUMN_SERVICE_TYPE = "service_type";
555
556        /**
557         * The original network ID of this TV channel.
558         * <p>
559         * This is used to identify the originating delivery system, if applicable. Use the same
560         * coding for {@code original_network_id} in the underlying broadcast standard if it is
561         * defined there (e.g. ETSI EN 300 468/TR 101 211 and ARIB STD-B10). If channels cannot be
562         * globally identified by 2-tuple {{@link #COLUMN_TRANSPORT_STREAM_ID},
563         * {@link #COLUMN_SERVICE_ID}}, one must carefully assign a value to this field to form a
564         * unique 3-tuple identification {{@link #COLUMN_ORIGINAL_NETWORK_ID},
565         * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels.
566         * </p><p>
567         * This is a required field if the channel cannot be uniquely identified by a 2-tuple
568         * {{@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}}.
569         * </p><p>
570         * Type: INTEGER
571         * </p>
572         */
573        public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
574
575        /**
576         * The transport stream ID of this channel.
577         * <p>
578         * This is used to identify the Transport Stream that contains the current channel from any
579         * other multiplex within a network, if applicable. Use the same coding for
580         * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
581         * the MPEG Transport Stream as is the case for many digital broadcast standards.
582         * </p><p>
583         * This is a required field if the current channel is transmitted via the MPEG Transport
584         * Stream.
585         * </p><p>
586         * Type: INTEGER
587         * </p>
588         */
589        public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
590
591        /**
592         * The service ID of this channel.
593         * <p>
594         * This is used to identify the current service (roughly equivalent to channel) from any
595         * other service within the Transport Stream, if applicable. Use the same coding for
596         * {@code service_id} in the underlying broadcast standard if it is defined there (e.g. ETSI
597         * EN 300 468 and ARIB STD-B10) or {@code program_number} (which usually has the same value
598         * as {@code service_id}) in ISO/IEC 13818-1 if the channel is transmitted via the MPEG
599         * Transport Stream.
600         * </p><p>
601         * This is a required field if the current channel is transmitted via the MPEG Transport
602         * Stream.
603         * </p><p>
604         * Type: INTEGER
605         * </p>
606         */
607        public static final String COLUMN_SERVICE_ID = "service_id";
608
609        /**
610         * The channel number that is displayed to the user.
611         * <p>
612         * The format can vary depending on broadcast standard and product specification.
613         * </p><p>
614         * Type: TEXT
615         * </p>
616         */
617        public static final String COLUMN_DISPLAY_NUMBER = "display_number";
618
619        /**
620         * The channel name that is displayed to the user.
621         * <p>
622         * A call sign is a good candidate to use for this purpose but any name that helps the user
623         * recognize the current channel will be enough. Can also be empty depending on broadcast
624         * standard.
625         * </p><p>
626         * Type: TEXT
627         * </p>
628         */
629        public static final String COLUMN_DISPLAY_NAME = "display_name";
630
631        /**
632         * The network affiliation for this TV channel.
633         * <p>
634         * This is used to identify a channel that is commonly called by its network affiliation
635         * instead of the display name. Examples include ABC for the channel KGO-HD, FOX for the
636         * channel KTVU-HD and NBC for the channel KNTV-HD. Can be empty if not applicable.
637         * </p><p>
638         * Type: TEXT
639         * </p>
640         */
641        public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
642
643        /**
644         * The description of this TV channel.
645         * <p>
646         * Can be empty initially.
647         * </p><p>
648         * Type: TEXT
649         * </p>
650         */
651        public static final String COLUMN_DESCRIPTION = "description";
652
653        /**
654         * The typical video format for programs from this TV channel.
655         * <p>
656         * This is primarily used to filter out channels based on video format by applications. The
657         * value should match one of the followings: {@link #VIDEO_FORMAT_240P},
658         * {@link #VIDEO_FORMAT_360P}, {@link #VIDEO_FORMAT_480I}, {@link #VIDEO_FORMAT_480P},
659         * {@link #VIDEO_FORMAT_576I}, {@link #VIDEO_FORMAT_576P}, {@link #VIDEO_FORMAT_720P},
660         * {@link #VIDEO_FORMAT_1080I}, {@link #VIDEO_FORMAT_1080P}, {@link #VIDEO_FORMAT_2160P},
661         * {@link #VIDEO_FORMAT_4320P}. Note that the actual video resolution of each program from a
662         * given channel can vary thus one should use {@link Programs#COLUMN_VIDEO_WIDTH} and
663         * {@link Programs#COLUMN_VIDEO_HEIGHT} to get more accurate video resolution.
664         * </p><p>
665         * Type: TEXT
666         * </p>
667         * @see #getVideoResolution
668         */
669        public static final String COLUMN_VIDEO_FORMAT = "video_format";
670
671        /**
672         * The flag indicating whether this TV channel is browsable or not.
673         * <p>
674         * A value of 1 indicates the channel is included in the channel list that applications use
675         * to browse channels, a value of 0 indicates the channel is not included in the list. If
676         * not specified, this value is set to 1 (browsable) by default.
677         * </p><p>
678         * Type: INTEGER (boolean)
679         * </p>
680         * @hide
681         */
682        public static final String COLUMN_BROWSABLE = "browsable";
683
684        /**
685         * The flag indicating whether this TV channel is searchable or not.
686         * <p>
687         * In some regions, it is not allowed to surface search results for a given channel without
688         * broadcaster's consent. This is used to impose such restriction. Channels marked with
689         * "not searchable" cannot be used by other services except for the system service that
690         * shows the TV content. A value of 1 indicates the channel is searchable and can be
691         * included in search results, a value of 0 indicates the channel and its TV programs are
692         * hidden from search. If not specified, this value is set to 1 (searchable) by default.
693         * </p><p>
694         * Type: INTEGER (boolean)
695         * </p>
696         */
697        public static final String COLUMN_SEARCHABLE = "searchable";
698
699        /**
700         * The flag indicating whether this TV channel is locked or not.
701         * <p>
702         * This is primarily used for alternative parental control to prevent unauthorized users
703         * from watching the current channel regardless of the content rating. A value of 1
704         * indicates the channel is locked and the user is required to enter passcode to unlock it
705         * in order to watch the current program from the channel, a value of 0 indicates the
706         * channel is not locked thus the user is not prompted to enter passcode If not specified,
707         * this value is set to 0 (not locked) by default.
708         * </p><p>
709         * Type: INTEGER (boolean)
710         * </p>
711         * @hide
712         */
713        public static final String COLUMN_LOCKED = "locked";
714
715        /**
716         * Internal data used by individual TV input services.
717         * <p>
718         * This is internal to the provider that inserted it, and should not be decoded by other
719         * apps.
720         * </p><p>
721         * Type: BLOB
722         * </p>
723         */
724        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
725
726        /**
727         * The version number of this row entry used by TV input services.
728         * <p>
729         * This is best used by sync adapters to identify the rows to update. The number can be
730         * defined by individual TV input services. One may assign the same value as
731         * {@code version_number} that appears in ETSI EN 300 468 or ATSC A/65, if the data are
732         * coming from a TV broadcast.
733         * </p><p>
734         * Type: INTEGER
735         * </p>
736         */
737        public static final String COLUMN_VERSION_NUMBER = "version_number";
738
739        private Channels() {}
740
741        /**
742         * A sub-directory of a single TV channel that represents its primary logo.
743         * <p>
744         * To access this directory, append {@link Channels.Logo#CONTENT_DIRECTORY} to the raw
745         * channel URI.  The resulting URI represents an image file, and should be interacted
746         * using ContentResolver.openAssetFileDescriptor.
747         * </p><p>
748         * Note that this sub-directory also supports opening the logo as an asset file in write
749         * mode.  Callers can create or replace the primary logo associated with this channel by
750         * opening the asset file and writing the full-size photo contents into it.  When the file
751         * is closed, the image will be parsed, sized down if necessary, and stored.
752         * </p><p>
753         * Usage example:
754         * <pre>
755         * public void writeChannelLogo(long channelId, byte[] logo) {
756         *     Uri channelLogoUri = TvContract.buildChannelLogoUri(channelId);
757         *     try {
758         *         AssetFileDescriptor fd =
759         *             getContentResolver().openAssetFileDescriptor(channelLogoUri, "rw");
760         *         OutputStream os = fd.createOutputStream();
761         *         os.write(logo);
762         *         os.close();
763         *         fd.close();
764         *     } catch (IOException e) {
765         *         // Handle error cases.
766         *     }
767         * }
768         * </pre>
769         * </p>
770         */
771        public static final class Logo {
772
773            /**
774             * The directory twig for this sub-table.
775             */
776            public static final String CONTENT_DIRECTORY = "logo";
777
778            private Logo() {}
779        }
780    }
781
782    /** Column definitions for the TV programs table. */
783    public static final class Programs implements BaseTvColumns {
784
785        /** The content:// style URI for this table. */
786        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
787                + PATH_PROGRAM);
788
789        /** The MIME type of a directory of TV programs. */
790        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/program";
791
792        /** The MIME type of a single TV program. */
793        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
794
795        /**
796         * The ID of the TV channel that contains this TV program.
797         * <p>
798         * This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
799         * </p><p>
800         * Type: INTEGER (long)
801         * </p>
802         */
803        public static final String COLUMN_CHANNEL_ID = "channel_id";
804
805        /**
806         * The title of this TV program.
807         * <p>
808         * If this program is an episodic TV show, it is recommended that the title is the series
809         * title and its related fields ({@link #COLUMN_SEASON_NUMBER},
810         * {@link #COLUMN_EPISODE_NUMBER}, and {@link #COLUMN_EPISODE_TITLE}) are filled in.
811         * </p><p>
812         * Type: TEXT
813         * </p>
814         **/
815        public static final String COLUMN_TITLE = "title";
816
817        /**
818         * The season number of this TV program for episodic TV shows.
819         * <p>
820         * Can be empty.
821         * </p><p>
822         * Type: INTEGER
823         * </p>
824         **/
825        public static final String COLUMN_SEASON_NUMBER = "season_number";
826
827        /**
828         * The episode number of this TV program for episodic TV shows.
829         * <p>
830         * Can be empty.
831         * </p><p>
832         * Type: INTEGER
833         * </p>
834         **/
835        public static final String COLUMN_EPISODE_NUMBER = "episode_number";
836
837        /**
838         * The episode title of this TV program for episodic TV shows.
839         * <p>
840         * Can be empty.
841         * </p><p>
842         * Type: TEXT
843         * </p>
844         **/
845        public static final String COLUMN_EPISODE_TITLE = "episode_title";
846
847        /**
848         * The start time of this TV program, in milliseconds since the epoch.
849         * <p>
850         * Type: INTEGER (long)
851         * </p>
852         */
853        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
854
855        /**
856         * The end time of this TV program, in milliseconds since the epoch.
857         * <p>
858         * Type: INTEGER (long)
859         * </p>
860         */
861        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
862
863        /**
864         * The comma-separated genre string of this TV program.
865         * <p>
866         * Use the same language appeared in the underlying broadcast standard, if applicable. (For
867         * example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
868         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty.
869         * </p><p>
870         * Type: TEXT
871         * </p>
872         */
873        public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
874
875        /**
876         * The comma-separated canonical genre string of this TV program.
877         * <p>
878         * Canonical genres are defined in {@link Genres}. Use {@link Genres#encode Genres.encode()}
879         * to create a text that can be stored in this column. Use {@link Genres#decode
880         * Genres.decode()} to get the canonical genre strings from the text stored in this column.
881         * </p><p>
882         * Type: TEXT
883         * </p>
884         * @see Genres
885         */
886        public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
887
888        /**
889         * The short description of this TV program that is displayed to the user by default.
890         * <p>
891         * It is recommended to limit the length of the descriptions to 256 characters.
892         * </p><p>
893         * Type: TEXT
894         * </p>
895         */
896        public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
897
898        /**
899         * The detailed, lengthy description of this TV program that is displayed only when the user
900         * wants to see more information.
901         * <p>
902         * TV input services should leave this field empty if they have no additional details beyond
903         * {@link #COLUMN_SHORT_DESCRIPTION}.
904         * </p><p>
905         * Type: TEXT
906         * </p>
907         */
908        public static final String COLUMN_LONG_DESCRIPTION = "long_description";
909
910        /**
911         * The width of the video for this TV program, in the unit of pixels.
912         * <p>
913         * Together with {@link #COLUMN_VIDEO_HEIGHT} this is used to determine the video resolution
914         * of the current TV program. Can be empty if it is not known initially or the program does
915         * not convey any video such as the programs from type {@link Channels#SERVICE_TYPE_AUDIO}
916         * channels.
917         * </p><p>
918         * Type: INTEGER
919         * </p>
920         */
921        public static final String COLUMN_VIDEO_WIDTH = "video_width";
922
923        /**
924         * The height of the video for this TV program, in the unit of pixels.
925         * <p>
926         * Together with {@link #COLUMN_VIDEO_WIDTH} this is used to determine the video resolution
927         * of the current TV program. Can be empty if it is not known initially or the program does
928         * not convey any video such as the programs from type {@link Channels#SERVICE_TYPE_AUDIO}
929         * channels.
930         * </p><p>
931         * Type: INTEGER
932         * </p>
933         */
934        public static final String COLUMN_VIDEO_HEIGHT = "video_height";
935
936        /**
937         * The comma-separated audio languages of this TV program.
938         * <p>
939         * This is used to describe available audio languages included in the program. Use
940         * 3-character language code as specified by ISO 639-2.
941         * </p><p>
942         * Type: TEXT
943         * </p>
944         */
945        public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
946
947        /**
948         * The comma-separated content ratings of this TV program.
949         * <p>
950         * This is used to describe the content rating(s) of this program. Each comma-separated
951         * content rating sub-string should be generated by calling
952         * {@link TvContentRating#flattenToString}. Note that in most cases the program content is
953         * rated by a single rating system, thus resulting in a corresponding single sub-string that
954         * does not require comma separation and multiple sub-strings appear only when the program
955         * content is rated by two or more content rating systems. If any of those ratings is
956         * specified as "blocked rating" in the user's parental control settings, the TV input
957         * service should block the current content and wait for the signal that it is okay to
958         * unblock.
959         * </p><p>
960         * Type: TEXT
961         * </p>
962         */
963        public static final String COLUMN_CONTENT_RATING = "content_rating";
964
965        /**
966         * The URI for the poster art of this TV program.
967         * <p>
968         * Can be empty.
969         * </p><p>
970         * Type: TEXT
971         * </p>
972         */
973        public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
974
975        /**
976         * The URI for the thumbnail of this TV program.
977         * <p>
978         * Can be empty.
979         * </p><p>
980         * Type: TEXT
981         * </p>
982         */
983        public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
984
985        /**
986         * Internal data used by individual TV input services.
987         * <p>
988         * This is internal to the provider that inserted it, and should not be decoded by other
989         * apps.
990         * </p><p>
991         * Type: BLOB
992         * </p>
993         */
994        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
995
996        /**
997         * The version number of this row entry used by TV input services.
998         * <p>
999         * This is best used by sync adapters to identify the rows to update. The number can be
1000         * defined by individual TV input services. One may assign the same value as
1001         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
1002         * broadcast.
1003         * </p><p>
1004         * Type: INTEGER
1005         * </p>
1006         */
1007        public static final String COLUMN_VERSION_NUMBER = "version_number";
1008
1009        private Programs() {}
1010
1011        /** Canonical genres for TV programs. */
1012        public static final class Genres {
1013            /** The genre for Family/Kids. */
1014            public static final String FAMILY_KIDS = "FAMILY_KIDS";
1015
1016            /** The genre for Sports. */
1017            public static final String SPORTS = "SPORTS";
1018
1019            /** The genre for Shopping. */
1020            public static final String SHOPPING = "SHOPPING";
1021
1022            /** The genre for Movies. */
1023            public static final String MOVIES = "MOVIES";
1024
1025            /** The genre for Comedy. */
1026            public static final String COMEDY = "COMEDY";
1027
1028            /** The genre for Travel. */
1029            public static final String TRAVEL = "TRAVEL";
1030
1031            /** The genre for Drama. */
1032            public static final String DRAMA = "DRAMA";
1033
1034            /** The genre for Education. */
1035            public static final String EDUCATION = "EDUCATION";
1036
1037            /** The genre for Animal/Wildlife. */
1038            public static final String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE";
1039
1040            /** The genre for News. */
1041            public static final String NEWS = "NEWS";
1042
1043            /** The genre for Gaming. */
1044            public static final String GAMING = "GAMING";
1045
1046            private static final ArraySet<String> CANONICAL_GENRES = new ArraySet<String>();
1047            static {
1048                CANONICAL_GENRES.add(FAMILY_KIDS);
1049                CANONICAL_GENRES.add(SPORTS);
1050                CANONICAL_GENRES.add(SHOPPING);
1051                CANONICAL_GENRES.add(MOVIES);
1052                CANONICAL_GENRES.add(COMEDY);
1053                CANONICAL_GENRES.add(TRAVEL);
1054                CANONICAL_GENRES.add(DRAMA);
1055                CANONICAL_GENRES.add(EDUCATION);
1056                CANONICAL_GENRES.add(ANIMAL_WILDLIFE);
1057                CANONICAL_GENRES.add(NEWS);
1058                CANONICAL_GENRES.add(GAMING);
1059            }
1060
1061            private Genres() {}
1062
1063            /**
1064             * Encodes canonical genre strings to a text that can be put into the database.
1065             *
1066             * @param genres Canonical genre strings. Use the strings defined in this class.
1067             * @return an encoded genre string that can be inserted into the
1068             *         {@link #COLUMN_CANONICAL_GENRE} column.
1069             */
1070            public static String encode(String... genres) {
1071                StringBuilder sb = new StringBuilder();
1072                String separator = "";
1073                for (String genre : genres) {
1074                    sb.append(separator).append(genre);
1075                    separator = ",";
1076                }
1077                return sb.toString();
1078            }
1079
1080            /**
1081             * Decodes the canonical genre strings from the text stored in the database.
1082             *
1083             * @param genres The encoded genre string retrieved from the
1084             *            {@link #COLUMN_CANONICAL_GENRE} column.
1085             * @return canonical genre strings.
1086             */
1087            public static String[] decode(String genres) {
1088                return genres.split("\\s*,\\s*");
1089            }
1090
1091            /**
1092             * Check whether a given genre is canonical or not.
1093             *
1094             * @param genre The name of genre to be checked.
1095             * @return {@code true} if the genre is canonical, otherwise {@code false}.
1096             * @hide
1097             */
1098            @SystemApi
1099            public static boolean isCanonical(String genre) {
1100                return CANONICAL_GENRES.contains(genre);
1101            }
1102        }
1103    }
1104
1105    /**
1106     * Column definitions for the TV programs that the user watched. Applications do not have access
1107     * to this table.
1108     *
1109     * @hide
1110     */
1111    public static final class WatchedPrograms implements BaseTvColumns {
1112
1113        /** The content:// style URI for this table. */
1114        public static final Uri CONTENT_URI =
1115                Uri.parse("content://" + AUTHORITY + "/watched_program");
1116
1117        /** The MIME type of a directory of watched programs. */
1118        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
1119
1120        /** The MIME type of a single item in this table. */
1121        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
1122
1123        /**
1124         * The UTC time that the user started watching this TV program, in milliseconds since the
1125         * epoch.
1126         * <p>
1127         * Type: INTEGER (long)
1128         * </p>
1129         */
1130        public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS =
1131                "watch_start_time_utc_millis";
1132
1133        /**
1134         * The UTC time that the user stopped watching this TV program, in milliseconds since the
1135         * epoch.
1136         * <p>
1137         * Type: INTEGER (long)
1138         * </p>
1139         */
1140        public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
1141
1142        /**
1143         * The channel ID that contains this TV program.
1144         * <p>
1145         * Type: INTEGER (long)
1146         * </p>
1147         */
1148        public static final String COLUMN_CHANNEL_ID = "channel_id";
1149
1150        /**
1151         * The title of this TV program.
1152         * <p>
1153         * Type: TEXT
1154         * </p>
1155         */
1156        public static final String COLUMN_TITLE = "title";
1157
1158        /**
1159         * The start time of this TV program, in milliseconds since the epoch.
1160         * <p>
1161         * Type: INTEGER (long)
1162         * </p>
1163         */
1164        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
1165
1166        /**
1167         * The end time of this TV program, in milliseconds since the epoch.
1168         * <p>
1169         * Type: INTEGER (long)
1170         * </p>
1171         */
1172        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
1173
1174        /**
1175         * The description of this TV program.
1176         * <p>
1177         * Type: TEXT
1178         * </p>
1179         */
1180        public static final String COLUMN_DESCRIPTION = "description";
1181
1182        /**
1183         * Extra parameters of the tune operation.
1184         * <p>
1185         * This column contains an encoded string which is comma-separated key-value pairs.
1186         * (Ex. "[key1]=[value1], [key2]=[value2]"). COLUMN_TUNE_PARAMS will use '%' as an escape
1187         * character for the characters of '%', '=', and ','.
1188         * </p><p>
1189         * Type: TEXT
1190         * </p>
1191         * @see TvInputManager.Session.tune(Uri, Bundle)
1192         */
1193        public static final String COLUMN_TUNE_PARAMS = "tune_params";
1194
1195        private WatchedPrograms() {}
1196    }
1197}
1198