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