TvContract.java revision cf9bec5bb6abfe134332d5004c1fee90901da62c
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.content.ComponentName;
20import android.content.ContentResolver;
21import android.content.ContentUris;
22import android.net.Uri;
23import android.provider.BaseColumns;
24
25import java.util.List;
26
27/**
28 * <p>
29 * The contract between the TV provider and applications. Contains definitions for the supported
30 * URIs and columns.
31 * </p>
32 * <h3>Overview</h3>
33 * <p>
34 * TvContract defines a basic database of TV content metadata such as channel and program
35 * information. The information is stored in {@link Channels} and {@link Programs} tables.
36 * </p>
37 * <ul>
38 *     <li>A row in the {@link Channels} table represents information about a TV channel. The data
39 *         format can vary greatly from standard to standard or according to service provider, thus
40 *         the columns here are mostly comprised of basic entities that are usually seen to users
41 *         regardless of standard such as channel number and name.</li>
42 *     <li>A row in the {@link Programs} table represents a set of data describing a TV program such
43 *         as program title and start time.</li>
44 * </ul>
45 */
46public final class TvContract {
47    /** The authority for the TV provider. */
48    public static final String AUTHORITY = "android.media.tv";
49
50    private static final String PATH_CHANNEL = "channel";
51    private static final String PATH_PROGRAM = "program";
52    private static final String PATH_INPUT = "input";
53
54    /**
55     * An optional query, update or delete URI parameter that allows the caller to specify start
56     * time (in milliseconds since the epoch) to filter programs.
57     *
58     * @hide
59     */
60    public static final String PARAM_START_TIME = "start_time";
61
62    /**
63     * An optional query, update or delete URI parameter that allows the caller to specify end time
64     * (in milliseconds since the epoch) to filter programs.
65     *
66     * @hide
67     */
68    public static final String PARAM_END_TIME = "end_time";
69
70    /**
71     * A query, update or delete URI parameter that allows the caller to operate on all or
72     * browsable-only channels. If set to "true", the rows that contain non-browsable channels are
73     * not affected.
74     *
75     * @hide
76     */
77    public static final String PARAM_BROWSABLE_ONLY = "browsable_only";
78
79    /**
80     * Builds a URI that points to a specific channel.
81     *
82     * @param channelId The ID of the channel to point to.
83     */
84    public static final Uri buildChannelUri(long channelId) {
85        return ContentUris.withAppendedId(Channels.CONTENT_URI, channelId);
86    }
87
88    /**
89     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
90     *
91     * @param channelId The ID of the channel whose logo is pointed to.
92     */
93    public static final Uri buildChannelLogoUri(long channelId) {
94        return buildChannelLogoUri(buildChannelUri(channelId));
95    }
96
97    /**
98     * Builds a URI that points to a channel logo. See {@link Channels.Logo}.
99     *
100     * @param channelUri The URI of the channel whose logo is pointed to.
101     */
102    public static final Uri buildChannelLogoUri(Uri channelUri) {
103        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
104            throw new IllegalArgumentException("Not a channel: " + channelUri);
105        }
106        return Uri.withAppendedPath(channelUri, Channels.Logo.CONTENT_DIRECTORY);
107    }
108
109    /**
110     * Builds a URI that points to all browsable channels from a given TV input.
111     *
112     * @param name {@link ComponentName} of the {@link android.media.tv.TvInputService} that
113     *            implements the given TV input.
114     */
115    public static final Uri buildChannelsUriForInput(ComponentName name) {
116        return buildChannelsUriForInput(name, true);
117    }
118
119    /**
120     * Builds a URI that points to all or browsable-only channels from a given TV input.
121     *
122     * @param name {@link ComponentName} of the {@link android.media.tv.TvInputService} that
123     *            implements the given TV input.
124     * @param browsableOnly If set to {@code true} the URI points to only browsable channels. If set
125     *            to {@code false} the URI points to all channels regardless of whether they are
126     *            browsable or not.
127     */
128    public static final Uri buildChannelsUriForInput(ComponentName name, boolean browsableOnly) {
129        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
130                .appendPath(PATH_INPUT).appendPath(name.getPackageName())
131                .appendPath(name.getClassName()).appendPath(PATH_CHANNEL)
132                .appendQueryParameter(PARAM_BROWSABLE_ONLY, String.valueOf(browsableOnly)).build();
133    }
134
135    /**
136     * Builds a URI that points to a specific program.
137     *
138     * @param programId The ID of the program to point to.
139     */
140    public static final Uri buildProgramUri(long programId) {
141        return ContentUris.withAppendedId(Programs.CONTENT_URI, programId);
142    }
143
144    /**
145     * Builds a URI that points to all programs on a given channel.
146     *
147     * @param channelId The ID of the channel to return programs for.
148     */
149    public static final Uri buildProgramsUriForChannel(long channelId) {
150        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
151                .appendPath(PATH_CHANNEL).appendPath(String.valueOf(channelId))
152                .appendPath(PATH_PROGRAM).build();
153    }
154
155    /**
156     * Builds a URI that points to all programs on a given channel.
157     *
158     * @param channelUri The URI of the channel to return programs for.
159     */
160    public static final Uri buildProgramsUriForChannel(Uri channelUri) {
161        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
162            throw new IllegalArgumentException("Not a channel: " + channelUri);
163        }
164        return buildProgramsUriForChannel(ContentUris.parseId(channelUri));
165    }
166
167    /**
168     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
169     * given time frame.
170     *
171     * @param channelId The ID of the channel to return programs for.
172     * @param startTime The start time used to filter programs. The returned programs should have
173     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
174     * @param endTime The end time used to filter programs. The returned programs should have
175     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
176     */
177    public static final Uri buildProgramsUriForChannel(long channelId, long startTime,
178            long endTime) {
179        Uri uri = buildProgramsUriForChannel(channelId);
180        return uri.buildUpon().appendQueryParameter(PARAM_START_TIME, String.valueOf(startTime))
181                .appendQueryParameter(PARAM_END_TIME, String.valueOf(endTime)).build();
182    }
183
184    /**
185     * Builds a URI that points to programs on a specific channel whose schedules overlap with the
186     * given time frame.
187     *
188     * @param channelUri The URI of the channel to return programs for.
189     * @param startTime The start time used to filter programs. The returned programs should have
190     *            {@link Programs#COLUMN_END_TIME_UTC_MILLIS} that is greater than this time.
191     * @param endTime The end time used to filter programs. The returned programs should have
192     *            {@link Programs#COLUMN_START_TIME_UTC_MILLIS} that is less than this time.
193     */
194    public static final Uri buildProgramsUriForChannel(Uri channelUri, long startTime,
195            long endTime) {
196        if (!PATH_CHANNEL.equals(channelUri.getPathSegments().get(0))) {
197            throw new IllegalArgumentException("Not a channel: " + channelUri);
198        }
199        return buildProgramsUriForChannel(ContentUris.parseId(channelUri), startTime, endTime);
200    }
201
202    /**
203     * Builds a URI that points to a specific program the user watched.
204     *
205     * @param watchedProgramId The ID of the watched program to point to.
206     * @hide
207     */
208    public static final Uri buildWatchedProgramUri(long watchedProgramId) {
209        return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, watchedProgramId);
210    }
211
212    /**
213     * Extracts the {@link Channels#COLUMN_PACKAGE_NAME} from a given URI.
214     *
215     * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or
216     *            {@link #buildChannelsUriForInput(ComponentName, boolean)}.
217     * @hide
218     */
219    public static final String getPackageName(Uri channelsUri) {
220        final List<String> paths = channelsUri.getPathSegments();
221        if (paths.size() < 4) {
222            throw new IllegalArgumentException("Not channels: " + channelsUri);
223        }
224        if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(3))) {
225            throw new IllegalArgumentException("Not channels: " + channelsUri);
226        }
227        return paths.get(1);
228    }
229
230    /**
231     * Extracts the {@link Channels#COLUMN_SERVICE_NAME} from a given URI.
232     *
233     * @param channelsUri A URI constructed by {@link #buildChannelsUriForInput(ComponentName)} or
234     *            {@link #buildChannelsUriForInput(ComponentName, boolean)}.
235     * @hide
236     */
237    public static final String getServiceName(Uri channelsUri) {
238        final List<String> paths = channelsUri.getPathSegments();
239        if (paths.size() < 4) {
240            throw new IllegalArgumentException("Not channels: " + channelsUri);
241        }
242        if (!PATH_INPUT.equals(paths.get(0)) || !PATH_CHANNEL.equals(paths.get(3))) {
243            throw new IllegalArgumentException("Not channels: " + channelsUri);
244        }
245        return paths.get(2);
246    }
247
248    /**
249     * Extracts the {@link Channels#_ID} from a given URI.
250     *
251     * @param programsUri A URI constructed by {@link #buildProgramsUriForChannel(Uri)} or
252     *            {@link #buildProgramsUriForChannel(Uri, long, long)}.
253     * @hide
254     */
255    public static final String getChannelId(Uri programsUri) {
256        final List<String> paths = programsUri.getPathSegments();
257        if (paths.size() < 3) {
258            throw new IllegalArgumentException("Not programs: " + programsUri);
259        }
260        if (!PATH_CHANNEL.equals(paths.get(0)) || !PATH_PROGRAM.equals(paths.get(2))) {
261            throw new IllegalArgumentException("Not programs: " + programsUri);
262        }
263        return paths.get(1);
264    }
265
266
267    private TvContract() {}
268
269    /**
270     * Common base for the tables of TV channels/programs.
271     */
272    public interface BaseTvColumns extends BaseColumns {
273        /**
274         * The name of the package that owns a row in each table.
275         * <p>
276         * The TV provider fills it in with the name of the package that provides the initial data
277         * of that row. If the package is later uninstalled, the rows it owns are automatically
278         * removed from the tables.
279         * </p><p>
280         * Type: TEXT
281         * </p>
282         */
283        public static final String COLUMN_PACKAGE_NAME = "package_name";
284    }
285
286    /** Column definitions for the TV channels table. */
287    public static final class Channels implements BaseTvColumns {
288
289        /** The content:// style URI for this table. */
290        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
291                + PATH_CHANNEL);
292
293        /** The MIME type of a directory of TV channels. */
294        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
295
296        /** The MIME type of a single TV channel. */
297        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
298
299        /** A generic channel type. */
300        public static final int TYPE_OTHER = 0x0;
301
302        /** The channel type for NTSC. */
303        public static final int TYPE_NTSC = 0x1;
304
305        /** The channel type for PAL. */
306        public static final int TYPE_PAL = 0x2;
307
308        /** The channel type for SECAM. */
309        public static final int TYPE_SECAM = 0x3;
310
311        /** The special channel type used for pass-through inputs such as HDMI. */
312        public static final int TYPE_PASSTHROUGH = 0x00010000;
313
314        /** The channel type for DVB-T (terrestrial). */
315        public static final int TYPE_DVB_T = 0x00020000;
316
317        /** The channel type for DVB-T2 (terrestrial). */
318        public static final int TYPE_DVB_T2 = 0x00020001;
319
320        /** The channel type for DVB-S (satellite). */
321        public static final int TYPE_DVB_S = 0x00020100;
322
323        /** The channel type for DVB-S2 (satellite). */
324        public static final int TYPE_DVB_S2 = 0x00020101;
325
326        /** The channel type for DVB-C (cable). */
327        public static final int TYPE_DVB_C = 0x00020200;
328
329        /** The channel type for DVB-C2 (cable). */
330        public static final int TYPE_DVB_C2 = 0x00020201;
331
332        /** The channel type for DVB-H (handheld). */
333        public static final int TYPE_DVB_H = 0x00020300;
334
335        /** The channel type for DVB-SH (satellite). */
336        public static final int TYPE_DVB_SH = 0x00020400;
337
338        /** The channel type for ATSC (terrestrial). */
339        public static final int TYPE_ATSC_T = 0x00030000;
340
341        /** The channel type for ATSC (cable). */
342        public static final int TYPE_ATSC_C = 0x00030200;
343
344        /** The channel type for ATSC-M/H (mobile/handheld). */
345        public static final int TYPE_ATSC_M_H = 0x00030300;
346
347        /** The channel type for ISDB-T (terrestrial). */
348        public static final int TYPE_ISDB_T = 0x00040000;
349
350        /** The channel type for ISDB-Tb (Brazil). */
351        public static final int TYPE_ISDB_TB = 0x00040100;
352
353        /** The channel type for ISDB-S (satellite). */
354        public static final int TYPE_ISDB_S = 0x00040200;
355
356        /** The channel type for ISDB-C (cable). */
357        public static final int TYPE_ISDB_C = 0x00040300;
358
359        /** The channel type for 1seg (handheld). */
360        public static final int TYPE_1SEG = 0x00040400;
361
362        /** The channel type for DTMB (terrestrial). */
363        public static final int TYPE_DTMB = 0x00050000;
364
365        /** The channel type for CMMB (handheld). */
366        public static final int TYPE_CMMB = 0x00050100;
367
368        /** The channel type for T-DMB (terrestrial). */
369        public static final int TYPE_T_DMB = 0x00060000;
370
371        /** The channel type for S-DMB (satellite). */
372        public static final int TYPE_S_DMB = 0x00060100;
373
374        /** A generic service type. */
375        public static final int SERVICE_TYPE_OTHER = 0x0;
376
377        /** The service type for regular TV channels that have both audio and video. */
378        public static final int SERVICE_TYPE_AUDIO_VIDEO = 0x1;
379
380        /** The service type for radio channels that have audio only. */
381        public static final int SERVICE_TYPE_AUDIO = 0x2;
382
383        /**
384         * The name of the {@link TvInputService} subclass that provides this TV channel. This
385         * should be a fully qualified class name (such as, "com.example.project.TvInputService").
386         * <p>
387         * This is a required field.
388         * </p><p>
389         * Type: TEXT
390         * </p>
391         */
392        public static final String COLUMN_SERVICE_NAME = "service_name";
393
394        /**
395         * The predefined type of this TV channel.
396         * <p>
397         * This is primarily used to indicate which broadcast standard (e.g. ATSC, DVB or ISDB) the
398         * current channel conforms to, with an exception being {@link #TYPE_PASSTHROUGH}, which is
399         * a special channel type used only by pass-through inputs such as HDMI. The value should
400         * match to one of the followings: {@link #TYPE_OTHER}, {@link #TYPE_PASSTHROUGH},
401         * {@link #TYPE_DVB_T}, {@link #TYPE_DVB_T2}, {@link #TYPE_DVB_S}, {@link #TYPE_DVB_S2},
402         * {@link #TYPE_DVB_C}, {@link #TYPE_DVB_C2}, {@link #TYPE_DVB_H}, {@link #TYPE_DVB_SH},
403         * {@link #TYPE_ATSC_T}, {@link #TYPE_ATSC_C}, {@link #TYPE_ATSC_M_H}, {@link #TYPE_ISDB_T},
404         * {@link #TYPE_ISDB_TB}, {@link #TYPE_ISDB_S}, {@link #TYPE_ISDB_C} {@link #TYPE_1SEG},
405         * {@link #TYPE_DTMB}, {@link #TYPE_CMMB}, {@link #TYPE_T_DMB}, {@link #TYPE_S_DMB}
406         * </p><p>
407         * This is a required field.
408         * </p><p>
409         * Type: INTEGER
410         * </p>
411         */
412        public static final String COLUMN_TYPE = "type";
413
414        /**
415         * The predefined service type of this TV channel.
416         * <p>
417         * This is primarily used to indicate whether the current channel is a regular TV channel or
418         * a radio-like channel. Use the same coding for {@code service_type} in the underlying
419         * broadcast standard if it is defined there (e.g. ATSC A/53, ETSI EN 300 468 and ARIB
420         * STD-B10). Otherwise use one of the followings: {@link #SERVICE_TYPE_OTHER},
421         * {@link #SERVICE_TYPE_AUDIO_VIDEO}, {@link #SERVICE_TYPE_AUDIO}
422         * </p><p>
423         * This is a required field.
424         * </p><p>
425         * Type: INTEGER
426         * </p>
427         */
428        public static final String COLUMN_SERVICE_TYPE = "service_type";
429
430        /**
431         * The original network ID of this TV channel.
432         * <p>
433         * This is used to identify the originating delivery system, if applicable. Use the same
434         * coding for {@code original_network_id} in the underlying broadcast standard if it is
435         * defined there (e.g. ETSI EN 300 468/TR 101 211 and ARIB STD-B10). If channels cannot be
436         * globally identified by 2-tuple {{@link #COLUMN_TRANSPORT_STREAM_ID},
437         * {@link #COLUMN_SERVICE_ID}}, one must carefully assign a value to this field to form a
438         * unique 3-tuple identification {{@link #COLUMN_ORIGINAL_NETWORK_ID},
439         * {@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}} for its channels.
440         * </p><p>
441         * This is a required field if the channel cannot be uniquely identified by a 2-tuple
442         * {{@link #COLUMN_TRANSPORT_STREAM_ID}, {@link #COLUMN_SERVICE_ID}}.
443         * </p><p>
444         * Type: INTEGER
445         * </p>
446         */
447        public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
448
449        /**
450         * The transport stream ID of this channel.
451         * <p>
452         * This is used to identify the Transport Stream that contains the current channel from any
453         * other multiplex within a network, if applicable. Use the same coding for
454         * {@code transport_stream_id} defined in ISO/IEC 13818-1 if the channel is transmitted via
455         * the MPEG Transport Stream as is the case for many digital broadcast standards.
456         * </p><p>
457         * This is a required field if the current channel is transmitted via the MPEG Transport
458         * Stream.
459         * </p><p>
460         * Type: INTEGER
461         * </p>
462         */
463        public static final String COLUMN_TRANSPORT_STREAM_ID = "transport_stream_id";
464
465        /**
466         * The service ID of this channel.
467         * <p>
468         * This is used to identify the current service (roughly equivalent to channel) from any
469         * other service within the Transport Stream, if applicable. Use the same coding for
470         * {@code service_id} in the underlying broadcast standard if it is defined there (e.g. ETSI
471         * EN 300 468 and ARIB STD-B10) or {@code program_number} (which usually has the same value
472         * as {@code service_id}) in ISO/IEC 13818-1 if the channel is transmitted via the MPEG
473         * Transport Stream.
474         * </p><p>
475         * This is a required field if the current channel is transmitted via the MPEG Transport
476         * Stream.
477         * </p><p>
478         * Type: INTEGER
479         * </p>
480         */
481        public static final String COLUMN_SERVICE_ID = "service_id";
482
483        /**
484         * The channel number that is displayed to the user.
485         * <p>
486         * The format can vary depending on broadcast standard and product specification.
487         * </p><p>
488         * Type: TEXT
489         * </p>
490         */
491        public static final String COLUMN_DISPLAY_NUMBER = "display_number";
492
493        /**
494         * The channel name that is displayed to the user.
495         * <p>
496         * A call sign is a good candidate to use for this purpose but any name that helps the user
497         * recognize the current channel will be enough. Can also be empty depending on broadcast
498         * standard.
499         * </p><p>
500         * Type: TEXT
501         * </p>
502         */
503        public static final String COLUMN_DISPLAY_NAME = "display_name";
504
505        /**
506         * The description of this TV channel.
507         * <p>
508         * Can be empty initially.
509         * </p><p>
510         * Type: TEXT
511         * </p>
512         */
513        public static final String COLUMN_DESCRIPTION = "description";
514
515        /**
516         * The flag indicating whether this TV channel is browsable or not.
517         * <p>
518         * A value of 1 indicates the channel is included in the channel list that applications use
519         * to browse channels, a value of 0 indicates the channel is not included in the list. If
520         * not specified, this value is set to 1 (browsable) by default.
521         * </p><p>
522         * Type: INTEGER (boolean)
523         * </p>
524         */
525        public static final String COLUMN_BROWSABLE = "browsable";
526
527        /**
528         * The flag indicating whether this TV channel is searchable or not.
529         * <p>
530         * In some regions, it is not allowed to surface search results for a given channel without
531         * broadcaster's consent. This is used to impose such restriction. A value of 1 indicates
532         * the channel is searchable and can be included in search results, a value of 0 indicates
533         * the channel and its TV programs are hidden from search. If not specified, this value is
534         * set to 1 (searchable) by default.
535         * </p>
536         * <p>
537         * Type: INTEGER (boolean)
538         * </p>
539         */
540        public static final String COLUMN_SEARCHABLE = "searchable";
541
542        /**
543         * The flag indicating whether this TV channel is locked or not.
544         * <p>
545         * This is primarily used for alternative parental control to prevent unauthorized users
546         * from watching the current channel regardless of the content rating. A value of 1
547         * indicates the channel is locked and the user is required to enter passcode to unlock it
548         * in order to watch the current program from the channel, a value of 0 indicates the
549         * channel is not locked thus the user is not prompted to enter passcode If not specified,
550         * this value is set to 0 (not locked) by default.
551         * </p><p>
552         * Type: INTEGER (boolean)
553         * </p>
554         * @hide
555         */
556        public static final String COLUMN_LOCKED = "locked";
557
558        /**
559         * Internal data used by individual TV input services.
560         * <p>
561         * This is internal to the provider that inserted it, and should not be decoded by other
562         * apps.
563         * </p><p>
564         * Type: BLOB
565         * </p>
566         */
567        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
568
569        /**
570         * The version number of this row entry used by TV input services.
571         * <p>
572         * This is best used by sync adapters to identify the rows to update. The number can be
573         * defined by individual TV input services. One may assign the same value as
574         * {@code version_number} that appears in ETSI EN 300 468 or ATSC A/65, if the data are
575         * coming from a TV broadcast.
576         * </p><p>
577         * Type: INTEGER
578         * </p>
579         */
580        public static final String COLUMN_VERSION_NUMBER = "version_number";
581
582        private Channels() {}
583
584        /**
585         * A sub-directory of a single TV channel that represents its primary logo.
586         * <p>
587         * To access this directory, append {@link Channels.Logo#CONTENT_DIRECTORY} to the raw
588         * channel URI.  The resulting URI represents an image file, and should be interacted
589         * using ContentResolver.openAssetFileDescriptor.
590         * </p>
591         * <p>
592         * Note that this sub-directory also supports opening the logo as an asset file in write
593         * mode.  Callers can create or replace the primary logo associated with this channel by
594         * opening the asset file and writing the full-size photo contents into it.  When the file
595         * is closed, the image will be parsed, sized down if necessary, and stored.
596         * </p>
597         * <p>
598         * Usage example:
599         * <pre>
600         * public void writeChannelLogo(long channelId, byte[] logo) {
601         *     Uri channelLogoUri = TvContract.buildChannelLogoUri(channelId);
602         *     try {
603         *         AssetFileDescriptor fd =
604         *             getContentResolver().openAssetFileDescriptor(channelLogoUri, "rw");
605         *         OutputStream os = fd.createOutputStream();
606         *         os.write(logo);
607         *         os.close();
608         *         fd.close();
609         *     } catch (IOException e) {
610         *         // Handle error cases.
611         *     }
612         * }
613         * </pre>
614         * </p>
615         */
616        public static final class Logo {
617
618            /**
619             * The directory twig for this sub-table.
620             */
621            public static final String CONTENT_DIRECTORY = "logo";
622
623            private Logo() {}
624        }
625    }
626
627    /** Column definitions for the TV programs table. */
628    public static final class Programs implements BaseTvColumns {
629
630        /** The content:// style URI for this table. */
631        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
632                + PATH_PROGRAM);
633
634        /** The MIME type of a directory of TV programs. */
635        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/program";
636
637        /** The MIME type of a single TV program. */
638        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
639
640        /**
641         * The ID of the TV channel that contains this TV program.
642         * <p>
643         * This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
644         * </p><p>
645         * Type: INTEGER (long)
646         * </p>
647         */
648        public static final String COLUMN_CHANNEL_ID = "channel_id";
649
650        /**
651         * The title of this TV program.
652         * <p>
653         * Type: TEXT
654         * </p>
655         **/
656        public static final String COLUMN_TITLE = "title";
657
658        /**
659         * The start time of this TV program, in milliseconds since the epoch.
660         * <p>
661         * Type: INTEGER (long)
662         * </p>
663         */
664        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
665
666        /**
667         * The end time of this TV program, in milliseconds since the epoch.
668         * <p>
669         * Type: INTEGER (long)
670         * </p>
671         */
672        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
673
674        /**
675         * The comma-separated genre string of this TV program.
676         * <p>
677         * Use the same language appeared in the underlying broadcast standard, if applicable. (For
678         * example, one can refer to the genre strings used in Genre Descriptor of ATSC A/65 or
679         * Content Descriptor of ETSI EN 300 468, if appropriate.) Otherwise, leave empty.
680         * </p><p>
681         * Type: TEXT
682         * </p>
683         */
684        public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
685
686        /**
687         * The comma-separated canonical genre string of this TV program.
688         * <p>
689         * Canonical genres are defined in {@link Genres}. Use {@link Genres#encode Genres.encode()}
690         * to create a text that can be stored in this column. Use {@link Genres#decode
691         * Genres.decode()} to get the canonical genre strings from the text stored in this column.
692         * </p><p>
693         * Type: TEXT
694         * </p>
695         * @see Genres
696         */
697        public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
698
699        /**
700         * The short description of this TV program that is displayed to the user by default.
701         * <p>
702         * It is recommended to limit the length of the descriptions to 256 characters.
703         * </p><p>
704         * Type: TEXT
705         * </p>
706         */
707        public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
708
709        /**
710         * The detailed, lengthy description of this TV program that is displayed only when the user
711         * wants to see more information.
712         * <p>
713         * TV input services should leave this field empty if they have no additional details beyond
714         * {@link #COLUMN_SHORT_DESCRIPTION}.
715         * </p><p>
716         * Type: TEXT
717         * </p>
718         */
719        public static final String COLUMN_LONG_DESCRIPTION = "long_description";
720
721        /**
722         * The comma-separated audio languages of this TV program.
723         * <p>
724         * This is used to describe available audio languages included in the program. Use
725         * 3-character language code as specified by ISO 639-2.
726         * </p><p>
727         * Type: TEXT
728         * </p>
729         */
730        public static final String COLUMN_AUDIO_LANGUAGE = "audio_language";
731
732        /**
733         * The URI for the poster art of this TV program.
734         * <p>
735         * Can be empty.
736         * </p><p>
737         * Type: TEXT
738         * </p>
739         */
740        public static final String COLUMN_POSTER_ART_URI = "poster_art_uri";
741
742        /**
743         * The URI for the thumbnail of this TV program.
744         * <p>
745         * Can be empty.
746         * </p><p>
747         * Type: TEXT
748         * </p>
749         */
750        public static final String COLUMN_THUMBNAIL_URI = "thumbnail_uri";
751
752        /**
753         * Internal data used by individual TV input services.
754         * <p>
755         * This is internal to the provider that inserted it, and should not be decoded by other
756         * apps.
757         * </p><p>
758         * Type: BLOB
759         * </p>
760         */
761        public static final String COLUMN_INTERNAL_PROVIDER_DATA = "internal_provider_data";
762
763        /**
764         * The version number of this row entry used by TV input services.
765         * <p>
766         * This is best used by sync adapters to identify the rows to update. The number can be
767         * defined by individual TV input services. One may assign the same value as
768         * {@code version_number} in ETSI EN 300 468 or ATSC A/65, if the data are coming from a TV
769         * broadcast.
770         * </p><p>
771         * Type: INTEGER
772         * </p>
773         */
774        public static final String COLUMN_VERSION_NUMBER = "version_number";
775
776        private Programs() {}
777
778        /** Canonical genres for TV programs. */
779        public static final class Genres {
780            /** The genre for Family/Kids. */
781            public static final String FAMILY_KIDS = "Family/Kids";
782
783            /** The genre for Sports. */
784            public static final String SPORTS = "Sports";
785
786            /** The genre for Shopping. */
787            public static final String SHOPPING = "Shopping";
788
789            /** The genre for Movies. */
790            public static final String MOVIES = "Movies";
791
792            /** The genre for Comedy. */
793            public static final String COMEDY = "Comedy";
794
795            /** The genre for Travel. */
796            public static final String TRAVEL = "Travel";
797
798            /** The genre for Drama. */
799            public static final String DRAMA = "Drama";
800
801            /** The genre for Education. */
802            public static final String EDUCATION = "Education";
803
804            /** The genre for Animal/Wildlife. */
805            public static final String ANIMAL_WILDLIFE = "Animal/Wildlife";
806
807            /** The genre for News. */
808            public static final String NEWS = "News";
809
810            /** The genre for Gaming. */
811            public static final String GAMING = "Gaming";
812
813            private Genres() {}
814
815            /**
816             * Encodes canonical genre strings to a text that can be put into the database.
817             *
818             * @param genres Canonical genre strings. Use the strings defined in this class.
819             * @return an encoded genre string that can be inserted into the
820             *         {@link #COLUMN_CANONICAL_GENRE} column.
821             */
822            public static String encode(String... genres) {
823                StringBuilder sb = new StringBuilder();
824                String separator = "";
825                for (String genre : genres) {
826                    sb.append(separator).append(genre);
827                    separator = ",";
828                }
829                return sb.toString();
830            }
831
832            /**
833             * Decodes the canonical genre strings from the text stored in the database.
834             *
835             * @param genres The encoded genre string retrieved from the
836             *            {@link #COLUMN_CANONICAL_GENRE} column.
837             * @return canonical genre strings.
838             */
839            public static String[] decode(String genres) {
840                return genres.split("\\s*,\\s*");
841            }
842        }
843    }
844
845    /**
846     * Column definitions for the TV programs that the user watched. Applications do not have access
847     * to this table.
848     *
849     * @hide
850     */
851    public static final class WatchedPrograms implements BaseColumns {
852
853        /** The content:// style URI for this table. */
854        public static final Uri CONTENT_URI =
855                Uri.parse("content://" + AUTHORITY + "/watched_program");
856
857        /** The MIME type of a directory of watched programs. */
858        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program";
859
860        /** The MIME type of a single item in this table. */
861        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program";
862
863        /**
864         * The UTC time that the user started watching this TV program, in milliseconds since the
865         * epoch.
866         * <p>
867         * Type: INTEGER (long)
868         * </p>
869         */
870        public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS =
871                "watch_start_time_utc_millis";
872
873        /**
874         * The UTC time that the user stopped watching this TV program, in milliseconds since the
875         * epoch.
876         * <p>
877         * Type: INTEGER (long)
878         * </p>
879         */
880        public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis";
881
882        /**
883         * The channel ID that contains this TV program.
884         * <p>
885         * Type: INTEGER (long)
886         * </p>
887         */
888        public static final String COLUMN_CHANNEL_ID = "channel_id";
889
890        /**
891         * The title of this TV program.
892         * <p>
893         * Type: TEXT
894         * </p>
895         */
896        public static final String COLUMN_TITLE = "title";
897
898        /**
899         * The start time of this TV program, in milliseconds since the epoch.
900         * <p>
901         * Type: INTEGER (long)
902         * </p>
903         */
904        public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis";
905
906        /**
907         * The end time of this TV program, in milliseconds since the epoch.
908         * <p>
909         * Type: INTEGER (long)
910         * </p>
911         */
912        public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
913
914        /**
915         * The description of this TV program.
916         * <p>
917         * Type: TEXT
918         * </p>
919         */
920        public static final String COLUMN_DESCRIPTION = "description";
921
922        private WatchedPrograms() {}
923    }
924}
925