TvContentRating.java revision e6dca2cfa4eecd3a45792703b722fc3ef86e8744
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.net.Uri;
21import android.text.TextUtils;
22import android.util.Log;
23
24import java.util.Arrays;
25import java.util.Collections;
26import java.util.List;
27
28/**
29 * A class representing a TV content rating.
30 * When a TV input service provides the content rating information of a program into TV provider,
31 * TvContentRating class will be used for generating the value of {@link
32 * TvContract.Programs#COLUMN_CONTENT_RATING}. To create an object of {@link TvContentRating}, use
33 * the {@link #createRating} method with valid arguments. The arguments could be a system defined
34 * strings, or a TV input service defined strings.
35 * TV input service defined strings are in an xml file defined in <code>&lt;{@link
36 * android.R.styleable#TvInputService tv-input}&gt;</code> with the {@link
37 * android.R.attr#contentRatingSystemXml contentRatingSystemXml} attribute by the TV input service.
38 *
39 * <h3> Content Rating System XML format </h3>
40 * The XML file for publishing content rating system should follow the DTD bellow:
41 * <p><pre class="prettyprint">
42 * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
43 * &lt;!DOCTYPE rating-systems [
44 *     &lt;!ELEMENT rating-system-definitions (rating-system-definition+)&gt;
45 *     &lt;!ELEMENT rating-system-definition (
46 *         (sub-rating-definition*, rating-definition, sub-rating-definition*)+, order*)&gt;
47 *     &lt;!ATTLIST rating-system-definition
48 *         id          ID    #REQUIRED
49 *         displayName CDATA #IMPLIED
50 *         description CDATA #IMPLIED
51 *         country     CDATA #IMPLIED&gt;
52 *     &lt;!ELEMENT sub-rating-definition EMPTY&gt;
53 *     &lt;!ATTLIST sub-rating-definition
54 *         id          ID    #REQUIRED
55 *         displayName CDATA #IMPLIED
56 *         icon        CDATA #IMPLIED
57 *         description CDATA #IMPLIED&gt;
58 *     &lt;!ELEMENT rating-definition (sub-rating*))&gt;
59 *     &lt;!ATTLIST rating-definition
60 *         id          ID    #REQUIRED
61 *         displayName CDATA #IMPLIED
62 *         icon        CDATA #IMPLIED
63 *         description CDATA #IMPLIED&gt;
64 *     &lt;!ELEMENT sub-rating EMPTY&gt;
65 *     &lt;!ATTLIST sub-rating id IDREF #REQUIRED&gt;
66 *     &lt;!ELEMENT order (rating, rating+)&gt;
67 *     &lt;!ELEMENT rating EMPTY&gt;
68 *     &lt;!ATTLIST rating id IDREF #REQUIRED&gt;
69 * ]&gt;
70 * </pre></p>
71 *
72 * <h3>System defined rating strings</h3>
73 *
74 * <u>System defined string for {@code domain}</u>
75 * <table border="0" cellspacing="0" cellpadding="0">
76 *     <tr>
77 *         <td>String value</td>
78 *         <td>Comments</td>
79 *     </tr>
80 *     <tr>
81 *         <td>android.media.tv</td>
82 *         <td>Used for creating system defined content ratings</td>
83 *     </tr>
84 * </table>
85 * <u>System defined string for {@code ratingSystem}</u>
86 * <table border="0" cellspacing="0" cellpadding="0">
87 *     <tr>
88 *         <td>String value</td>
89 *         <td>Comments</td>
90 *     </tr>
91 *     <!--tr>
92 *         <td>AM_TV</td>
93 *         <td></td>
94 *     </tr-->
95 *     <!--tr>
96 *         <td>AR_TV</td>
97 *         <td></td>
98 *     </tr-->
99 *     <!--tr>
100 *         <td>AU_TV</td>
101 *         <td></td>
102 *     </tr-->
103 *     <!--tr>
104 *         <td>BG_TV</td>
105 *         <td></td>
106 *     </tr-->
107 *     <!--tr>
108 *         <td>BR_TV</td>
109 *         <td></td>
110 *     </tr-->
111 *     <!--tr>
112 *         <td>CA_TV</td>
113 *         <td></td>
114 *     </tr-->
115 *     <!--tr>
116 *         <td>CH_TV</td>
117 *         <td></td>
118 *     </tr-->
119 *     <!--tr>
120 *         <td>CL_TV</td>
121 *         <td></td>
122 *     </tr-->
123 *     <!--tr>
124 *         <td>CO_TV</td>
125 *         <td></td>
126 *     </tr-->
127 *     <!--tr>
128 *         <td>DE_TV</td>
129 *         <td></td>
130 *     </tr-->
131 *     <!--tr>
132 *         <td>DK_TV</td>
133 *         <td></td>
134 *     </tr-->
135 *     <!--tr>
136 *         <td>ES_TV</td>
137 *         <td></td>
138 *     </tr-->
139 *     <!--tr>
140 *         <td>FI_TV</td>
141 *         <td></td>
142 *     </tr-->
143 *     <!--tr>
144 *         <td>FR_TV</td>
145 *         <td></td>
146 *     </tr-->
147 *     <!--tr>
148 *         <td>GR_TV</td>
149 *         <td></td>
150 *     </tr-->
151 *     <!--tr>
152 *         <td>HK_TV</td>
153 *         <td></td>
154 *     </tr-->
155 *     <!--tr>
156 *         <td>HU_TV</td>
157 *         <td></td>
158 *     </tr-->
159 *     <!--tr>
160 *         <td>ID_TV</td>
161 *         <td></td>
162 *     </tr-->
163 *     <!--tr>
164 *         <td>IE_TV</td>
165 *         <td></td>
166 *     </tr-->
167 *     <!--tr>
168 *         <td>IL_TV</td>
169 *         <td></td>
170 *     </tr-->
171 *     <!--tr>
172 *         <td>IN_TV</td>
173 *         <td></td>
174 *     </tr-->
175 *     <!--tr>
176 *         <td>IS_TV</td>
177 *         <td></td>
178 *     </tr-->
179 *     <!--tr>
180 *         <td>IT_TV</td>
181 *         <td></td>
182 *     </tr-->
183 *     <!--tr>
184 *         <td>KH_TV</td>
185 *         <td></td>
186 *     </tr-->
187 *     <tr>
188 *         <td>KR_TV</td>
189 *         <td>The South Korean television rating system</td>
190 *     </tr>
191 *     <!--tr>
192 *         <td>MV_TV</td>
193 *         <td></td>
194 *     </tr-->
195 *     <!--tr>
196 *         <td>MX_TV</td>
197 *         <td></td>
198 *     </tr-->
199 *     <!--tr>
200 *         <td>MY_TV</td>
201 *         <td></td>
202 *     </tr-->
203 *     <!--tr>
204 *         <td>NL_TV</td>
205 *         <td></td>
206 *     </tr-->
207 *     <!--tr>
208 *         <td>NZ_TV</td>
209 *         <td></td>
210 *     </tr-->
211 *     <!--tr>
212 *         <td>PE_TV</td>
213 *         <td></td>
214 *     </tr-->
215 *     <!--tr>
216 *         <td>PH_TV</td>
217 *         <td></td>
218 *     </tr-->
219 *     <!--tr>
220 *         <td>PL_TV</td>
221 *         <td></td>
222 *     </tr-->
223 *     <!--tr>
224 *         <td>PT_TV</td>
225 *         <td></td>
226 *     </tr-->
227 *     <!--tr>
228 *         <td>RO_TV</td>
229 *         <td></td>
230 *     </tr-->
231 *     <!--tr>
232 *         <td>RU_TV</td>
233 *         <td></td>
234 *     </tr-->
235 *     <!--tr>
236 *         <td>RS_TV</td>
237 *         <td></td>
238 *     </tr-->
239 *     <!--tr>
240 *         <td>SG_TV</td>
241 *         <td></td>
242 *     </tr-->
243 *     <!--tr>
244 *         <td>SI_TV</td>
245 *         <td></td>
246 *     </tr-->
247 *     <!--tr>
248 *         <td>TH_TV</td>
249 *         <td></td>
250 *     </tr-->
251 *     <!--tr>
252 *         <td>TR_TV</td>
253 *         <td></td>
254 *     </tr-->
255 *     <!--tr>
256 *         <td>TW_TV</td>
257 *         <td></td>
258 *     </tr-->
259 *     <!--tr>
260 *         <td>UA_TV</td>
261 *         <td></td>
262 *     </tr-->
263 *     <tr>
264 *         <td>US_TVPG</td>
265 *         <td>The TV Parental Guidelines for US TV content ratings</td>
266 *     </tr>
267 *     <!--tr>
268 *         <td>VE_TV</td>
269 *         <td></td>
270 *     </tr-->
271 *     <!--tr>
272 *         <td>ZA_TV</td>
273 *         <td></td>
274 *     </tr-->
275 * </table>
276 *
277 * <u>System defined string for {@code rating}</u>
278 * <table border="0" cellspacing="0" cellpadding="0">
279 *     <tr>
280 *         <td>String value</td>
281 *         <td>Comments</td>
282 *     </tr>
283 *     <!--tr>
284 *         <td>AM_TV_ALL</td>
285 *         <td></td>
286 *     </tr-->
287 *     <!--tr>
288 *         <td>AR_TV_ALL</td>
289 *         <td></td>
290 *     </tr-->
291 *     <!--tr>
292 *         <td>AU_TV_ALL</td>
293 *         <td></td>
294 *     </tr-->
295 *     <!--tr>
296 *         <td>BG_TV_ALL</td>
297 *         <td></td>
298 *     </tr-->
299 *     <!--tr>
300 *         <td>BR_TV_ALL</td>
301 *         <td></td>
302 *     </tr-->
303 *     <!--tr>
304 *         <td>CA_TV_ALL</td>
305 *         <td></td>
306 *     </tr-->
307 *     <!--tr>
308 *         <td>CH_TV_ALL</td>
309 *         <td></td>
310 *     </tr-->
311 *     <!--tr>
312 *         <td>CL_TV_ALL</td>
313 *         <td></td>
314 *     </tr-->
315 *     <!--tr>
316 *         <td>CO_TV_ALL</td>
317 *         <td></td>
318 *     </tr-->
319 *     <!--tr>
320 *         <td>DE_TV_ALL</td>
321 *         <td></td>
322 *     </tr-->
323 *     <!--tr>
324 *         <td>DK_TV_ALL</td>
325 *         <td></td>
326 *     </tr-->
327 *     <!--tr>
328 *         <td>ES_TV_ALL</td>
329 *         <td></td>
330 *     </tr-->
331 *     <!--tr>
332 *         <td>FI_TV_ALL</td>
333 *         <td></td>
334 *     </tr-->
335 *     <!--tr>
336 *         <td>FR_TV_ALL</td>
337 *         <td></td>
338 *     </tr-->
339 *     <!--tr>
340 *         <td>GR_TV_ALL</td>
341 *         <td></td>
342 *     </tr-->
343 *     <!--tr>
344 *         <td>HK_TV_ALL</td>
345 *         <td></td>
346 *     </tr-->
347 *     <!--tr>
348 *         <td>HU_TV_ALL</td>
349 *         <td></td>
350 *     </tr-->
351 *     <!--tr>
352 *         <td>ID_TV_ALL</td>
353 *         <td></td>
354 *     </tr-->
355 *     <!--tr>
356 *         <td>IE_TV_ALL</td>
357 *         <td></td>
358 *     </tr-->
359 *     <!--tr>
360 *         <td>IL_TV_ALL</td>
361 *         <td></td>
362 *     </tr-->
363 *     <!--tr>
364 *         <td>IN_TV_ALL</td>
365 *         <td></td>
366 *     </tr-->
367 *     <!--tr>
368 *         <td>IS_TV_ALL</td>
369 *         <td></td>
370 *     </tr-->
371 *     <!--tr>
372 *         <td>IT_TV_ALL</td>
373 *         <td></td>
374 *     </tr-->
375 *     <!--tr>
376 *         <td>KH_TV_ALL</td>
377 *         <td></td>
378 *     </tr-->
379 *     <tr>
380 *         <td>KR_TV_ALL</td>
381 *         <td>A rating string for {@code KR_TV}. This rating is for programs that are appropriate
382 *         for all ages. This program usually involves programs designed for children or families.
383 *         </td>
384 *     </tr>
385 *     <tr>
386 *         <td>KR_TV_7</td>
387 *         <td>A rating string for {@code KR_TV}. This rating is for programs that may contain
388 *         material inappropriate for children younger than 7, and parental guidance is required.
389 *         </td>
390 *     </tr>
391 *     <tr>
392 *         <td>KR_TV_12</td>
393 *         <td>A rating string for {@code KR_TV}. This rating is for programs that may contain
394 *         material inappropriate for children younger than 12, and parental guidance is required.
395 *         </td>
396 *     </tr>
397 *     <tr>
398 *         <td>KR_TV_15</td>
399 *         <td>A rating string for {@code KR_TV}. This rating is for programs that may contain
400 *         material inappropriate for children younger than 15, and parental guidance is required.
401 *     </tr>
402 *     <tr>
403 *         <td>KR_TV_19</td>
404 *         <td>A rating string for {@code KR_TV}. This rating is for programs designed for adults
405 *         only.</td>
406 *     </tr>
407 *     <!--tr>
408 *         <td>MV_TV_ALL</td>
409 *         <td></td>
410 *     </tr-->
411 *     <!--tr>
412 *         <td>MX_TV_ALL</td>
413 *         <td></td>
414 *     </tr-->
415 *     <!--tr>
416 *         <td>MY_TV_ALL</td>
417 *         <td></td>
418 *     </tr-->
419 *     <!--tr>
420 *         <td>NL_TV_ALL</td>
421 *         <td></td>
422 *     </tr-->
423 *     <!--tr>
424 *         <td>NZ_TV_ALL</td>
425 *         <td></td>
426 *     </tr-->
427 *     <!--tr>
428 *         <td>PE_TV_ALL</td>
429 *         <td></td>
430 *     </tr-->
431 *     <!--tr>
432 *         <td>PH_TV_ALL</td>
433 *         <td></td>
434 *     </tr-->
435 *     <!--tr>
436 *         <td>PL_TV_ALL</td>
437 *         <td></td>
438 *     </tr-->
439 *     <!--tr>
440 *         <td>PT_TV_ALL</td>
441 *         <td></td>
442 *     </tr-->
443 *     <!--tr>
444 *         <td>RO_TV_ALL</td>
445 *         <td></td>
446 *     </tr-->
447 *     <!--tr>
448 *         <td>RU_TV_ALL</td>
449 *         <td></td>
450 *     </tr-->
451 *     <!--tr>
452 *         <td>RS_TV_ALL</td>
453 *         <td></td>
454 *     </tr-->
455 *     <!--tr>
456 *         <td>SG_TV_ALL</td>
457 *         <td></td>
458 *     </tr-->
459 *     <!--tr>
460 *         <td>SI_TV_ALL</td>
461 *         <td></td>
462 *     </tr-->
463 *     <!--tr>
464 *         <td>TH_TV_ALL</td>
465 *         <td></td>
466 *     </tr-->
467 *     <!--tr>
468 *         <td>TR_TV_ALL</td>
469 *         <td></td>
470 *     </tr-->
471 *     <!--tr>
472 *         <td>TW_TV_ALL</td>
473 *         <td></td>
474 *     </tr-->
475 *     <!--tr>
476 *         <td>UA_TV_ALL</td>
477 *         <td></td>
478 *     </tr-->
479 *     <tr>
480 *         <td>US_TVPG_TV_Y</td>
481 *         <td>A rating string for {@code US_TVPG}. Programs rated this are designed to be
482 *         appropriate for all children. Whether animated or live-action, the themes and elements
483 *         in this program are specifically designed for a very young audience, including children
484 *         from ages 2-6. This program is not expected to frighten younger children.</td>
485 *     </tr>
486 *     <tr>
487 *         <td>US_TVPG_TV_Y7</td>
488 *         <td>A rating string for {@code US_TVPG}. Programs rated this are designed for children
489 *         age 7 and above. It may be more appropriate for children who have acquired the
490 *         developmental skills needed to distinguish between make-believe and reality. Themes and
491 *         elements in this program may include mild fantasy violence or comedic violence, or may
492 *         frighten children under the age of 7. Therefore, parents may wish to consider the
493 *         suitability of this program for their very young children. This rating may contain
494 *         fantasy violence (US_TVPG_FV) when programs are generally more intense or more combative
495 *         than other programs in this category.</td>
496 *     </tr>
497 *     <tr>
498 *         <td>US_TVPG_TV_G</td>
499 *         <td>A rating string for {@code US_TVPG}. Most parents would find this program suitable
500 *         for all ages. Although this rating does not signify a program designed specifically for
501 *         children, most parents may let younger children watch this program unattended. It
502 *         contains little or no violence, no strong language and little or no sexual dialogue or
503 *         situations.</td>
504 *     </tr>
505 *     <tr>
506 *         <td>US_TVPG_TV_PG</td>
507 *         <td>A rating string for {@code US_TVPG}. Programs rated this contain material that
508 *         parents may find unsuitable for younger children. Many parents may want to watch it with
509 *         their younger children. The theme itself may call for parental guidance and/or the
510 *         program may contain one or more of the following: some suggestive dialogue (
511 *         {@code US_TVPG_D}), infrequent coarse language ({@code US_TVPG_L}), some sexual
512 *         situations ({@code US_TVPG_S}), or moderate violence ({@code US_TVPG_V}).</td>
513 *     </tr>
514 *     <tr>
515 *         <td>US_TVPG_TV_14</td>
516 *         <td>A rating string for {@code US_TVPG}. Programs rated this contains some material
517 *         that many parents would find unsuitable for children under 14 years of age. Parents are
518 *         strongly urged to exercise greater care in monitoring this program and are cautioned
519 *         against letting children under the age of 14 watch unattended. This program may contain
520 *         one or more of the following: intensely suggestive dialogue ({@code US_TVPG_D}), strong
521 *         coarse language ({@code US_TVPG_L}), intense sexual situations ({@code US_TVPG_S}), or
522 *         intense violence ({@code US_TVPG_V}).</td>
523 *     </tr>
524 *     <tr>
525 *         <td>US_TVPG_TV_MA</td>
526 *         <td>A rating string for {@code US_TVPG}. Programs rated TV-MA are specifically
527 *         designed to be viewed by adults and therefore may be unsuitable for children under 17.
528 *         This program may contain one or more of the following: crude indecent language
529 *         ({@code US_TVPG_L}), explicit sexual activity ({@code US_TVPG_S}), or graphic violence
530 *         ({@code US_TVPG_V}).</td>
531 *     </tr>
532 *     <!--tr>
533 *         <td>VE_TV_ALL</td>
534 *         <td></td>
535 *     </tr-->
536 *     <!--tr>
537 *         <td>ZA_TV_ALL</td>
538 *         <td></td>
539 *     </tr-->
540 * </table>
541 *
542 * <u>System defined string for {@code subRating}</u>
543 * <table border="0" cellspacing="0" cellpadding="0">
544 *     <tr>
545 *         <td>String value</td>
546 *         <td>Comments</td>
547 *     </tr>
548 *     <!--tr>
549 *         <td>AM_TV_</td>
550 *         <td></td>
551 *     </tr-->
552 *     <!--tr>
553 *         <td>AR_TV_</td>
554 *         <td></td>
555 *     </tr-->
556 *     <!--tr>
557 *         <td>AU_TV_</td>
558 *         <td></td>
559 *     </tr-->
560 *     <!--tr>
561 *         <td>BG_TV_</td>
562 *         <td></td>
563 *     </tr-->
564 *     <!--tr>
565 *         <td>BR_TV_</td>
566 *         <td></td>
567 *     </tr-->
568 *     <!--tr>
569 *         <td>CA_TV_</td>
570 *         <td></td>
571 *     </tr-->
572 *     <!--tr>
573 *         <td>CH_TV_</td>
574 *         <td></td>
575 *     </tr-->
576 *     <!--tr>
577 *         <td>CL_TV_</td>
578 *         <td></td>
579 *     </tr-->
580 *     <!--tr>
581 *         <td>CO_TV_</td>
582 *         <td></td>
583 *     </tr-->
584 *     <!--tr>
585 *         <td>DE_TV_</td>
586 *         <td></td>
587 *     </tr-->
588 *     <!--tr>
589 *         <td>DK_TV_</td>
590 *         <td></td>
591 *     </tr-->
592 *     <!--tr>
593 *         <td>ES_TV_</td>
594 *         <td></td>
595 *     </tr-->
596 *     <!--tr>
597 *         <td>FI_TV_</td>
598 *         <td></td>
599 *     </tr-->
600 *     <!--tr>
601 *         <td>FR_TV_</td>
602 *         <td></td>
603 *     </tr-->
604 *     <!--tr>
605 *         <td>GR_TV_</td>
606 *         <td></td>
607 *     </tr-->
608 *     <!--tr>
609 *         <td>HK_TV_</td>
610 *         <td></td>
611 *     </tr-->
612 *     <!--tr>
613 *         <td>HU_TV_</td>
614 *         <td></td>
615 *     </tr-->
616 *     <!--tr>
617 *         <td>ID_TV_</td>
618 *         <td></td>
619 *     </tr-->
620 *     <!--tr>
621 *         <td>IE_TV_</td>
622 *         <td></td>
623 *     </tr-->
624 *     <!--tr>
625 *         <td>IL_TV_</td>
626 *         <td></td>
627 *     </tr-->
628 *     <!--tr>
629 *         <td>IN_TV_</td>
630 *         <td></td>
631 *     </tr-->
632 *     <!--tr>
633 *         <td>IS_TV_</td>
634 *         <td></td>
635 *     </tr-->
636 *     <!--tr>
637 *         <td>IT_TV_</td>
638 *         <td></td>
639 *     </tr-->
640 *     <!--tr>
641 *         <td>KH_TV_</td>
642 *         <td></td>
643 *     </tr-->
644 *     <!--tr>
645 *         <td>MV_TV_</td>
646 *         <td></td>
647 *     </tr-->
648 *     <!--tr>
649 *         <td>MX_TV_</td>
650 *         <td></td>
651 *     </tr-->
652 *     <!--tr>
653 *         <td>MY_TV_</td>
654 *         <td></td>
655 *     </tr-->
656 *     <!--tr>
657 *         <td>NL_TV_</td>
658 *         <td></td>
659 *     </tr-->
660 *     <!--tr>
661 *         <td>NZ_TV_</td>
662 *         <td></td>
663 *     </tr-->
664 *     <!--tr>
665 *         <td>PE_TV_</td>
666 *         <td></td>
667 *     </tr-->
668 *     <!--tr>
669 *         <td>PH_TV_</td>
670 *         <td></td>
671 *     </tr-->
672 *     <!--tr>
673 *         <td>PL_TV_</td>
674 *         <td></td>
675 *     </tr-->
676 *     <!--tr>
677 *         <td>PT_TV_</td>
678 *         <td></td>
679 *     </tr-->
680 *     <!--tr>
681 *         <td>RO_TV_</td>
682 *         <td></td>
683 *     </tr-->
684 *     <!--tr>
685 *         <td>RU_TV_</td>
686 *         <td></td>
687 *     </tr-->
688 *     <!--tr>
689 *         <td>RS_TV_</td>
690 *         <td></td>
691 *     </tr-->
692 *     <!--tr>
693 *         <td>SG_TV_</td>
694 *         <td></td>
695 *     </tr-->
696 *     <!--tr>
697 *         <td>SI_TV_</td>
698 *         <td></td>
699 *     </tr-->
700 *     <!--tr>
701 *         <td>TH_TV_</td>
702 *         <td></td>
703 *     </tr-->
704 *     <!--tr>
705 *         <td>TR_TV_</td>
706 *         <td></td>
707 *     </tr-->
708 *     <!--tr>
709 *         <td>TW_TV_</td>
710 *         <td></td>
711 *     </tr-->
712 *     <!--tr>
713 *         <td>UA_TV_</td>
714 *         <td></td>
715 *     </tr-->
716 *     <tr>
717 *         <td>US_TVPG_D</td>
718 *         <td>Suggestive dialogue (Not used with US_TVPG_TV_MA)</td>
719 *     </tr>
720 *     <tr>
721 *         <td>US_TVPG_L</td>
722 *         <td>Coarse language</td>
723 *     </tr>
724 *     <tr>
725 *         <td>US_TVPG_S</td>
726 *         <td>Sexual content</td>
727 *     </tr>
728 *     <tr>
729 *         <td>US_TVPG_V</td>
730 *         <td>Violence</td>
731 *     </tr>
732 *     <tr>
733 *         <td>US_TVPG_FV</td>
734 *         <td>Fantasy violence (exclusive to US_TVPG_TV_Y7)</td>
735 *     </tr>
736 *     <!--tr>
737 *         <td>VE_TV_</td>
738 *         <td></td>
739 *     </tr-->
740 *     <!--tr>
741 *         <td>ZA_TV_</td>
742 *         <td></td>
743 *     </tr-->
744 * </table>
745 */
746public final class TvContentRating {
747    private static final String TAG = "TvContentRating";
748
749    /** @hide */
750    public static final Uri SYSTEM_CONTENT_RATING_SYSTEM_XML = Uri.parse(
751            "android.resource://system/" + com.android.internal.R.xml.tv_content_rating_systems);
752
753    // TODO: Consider to use other DELIMITER. In some countries such as India may use this delimiter
754    // in the main ratings.
755    private static final String DELIMITER = "/";
756
757    private final String mDomain;
758    private final String mCountryCode;
759    private final String mRatingSystem;
760    private final String mRating;
761    private final String[] mSubRatings;
762
763    /**
764     * Creates a TvContentRating object.
765     *
766     * @param domain The domain name.
767     * @param countryCode The country code in ISO 3166-2 format or {@code null}.
768     * @param ratingSystem The rating system id.
769     * @param rating The content rating string.
770     * @param subRatings The string array of sub-ratings.
771     * @return A TvContentRating object, or null if creation failed.
772     */
773    public static TvContentRating createRating(String domain, String countryCode,
774            String ratingSystem, String rating, String... subRatings) {
775        if (TextUtils.isEmpty(domain)) {
776            throw new IllegalArgumentException("domain cannot be empty");
777        }
778        if (TextUtils.isEmpty(rating)) {
779            throw new IllegalArgumentException("rating cannot be empty");
780        }
781        return new TvContentRating(domain, countryCode, ratingSystem, rating, subRatings);
782    }
783
784    /**
785     * Recovers a TvContentRating from a String that was previously created with
786     * {@link #flattenToString}.
787     *
788     * @param ratingString The String that was returned by flattenToString().
789     * @return a new TvContentRating containing the domain, countryCode, rating system, rating and
790     *         sub-ratings information was encoded in {@code ratingString}.
791     * @see #flattenToString
792     */
793    public static TvContentRating unflattenFromString(String ratingString) {
794        if (TextUtils.isEmpty(ratingString)) {
795            throw new IllegalArgumentException("ratingString cannot be empty");
796        }
797        String[] strs = ratingString.split(DELIMITER);
798        if (strs.length < 4) {
799            throw new IllegalArgumentException("Invalid rating string: " + ratingString);
800        }
801        if (strs.length > 4) {
802            String[] subRatings = new String[strs.length - 4];
803            System.arraycopy(strs, 4, subRatings, 0, subRatings.length);
804            return new TvContentRating(strs[0], strs[1], strs[2], strs[3], subRatings);
805        }
806        return new TvContentRating(strs[0], strs[1], strs[2], strs[3], null);
807    }
808
809    /**
810     * Constructs a TvContentRating object from a given rating and sub-rating constants.
811     *
812     * @param rating The rating constant defined in this class.
813     * @param subRatings The String array of sub-rating constants defined in this class.
814     */
815    private TvContentRating(String domain, String countryCode,
816            String ratingSystem, String rating, String[] subRatings) {
817        mDomain = domain;
818        mCountryCode = countryCode;
819        mRatingSystem = ratingSystem;
820        mRating = rating;
821        mSubRatings = subRatings;
822    }
823
824    /**
825     * Returns the domain.
826     */
827    public String getDomain() {
828        return mDomain;
829    }
830
831    /**
832     * Returns the country code in ISO 3166-2 format or {@code null}.
833     */
834    public String getCountry() {
835        return mCountryCode;
836    }
837
838    /**
839     * Returns the rating system id.
840     */
841    public String getRatingSystem() {
842        return mRatingSystem;
843    }
844
845    /**
846     * Returns the main rating.
847     */
848    public String getMainRating() {
849        return mRating;
850    }
851
852    /**
853     * Returns the unmodifiable {@code List} of sub-rating strings.
854     */
855    public List<String> getSubRatings() {
856        if (mSubRatings == null) {
857            return null;
858        }
859        return Collections.unmodifiableList(Arrays.asList(mSubRatings));
860    }
861
862    /**
863     * Returns a String that unambiguously describes both the rating and sub-rating information
864     * contained in the TvContentRating. You can later recover the TvContentRating from this string
865     * through {@link #unflattenFromString}.
866     *
867     * @return a new String holding rating/sub-rating information, which can later be stored in the
868     *         database and settings.
869     * @see #unflattenFromString
870     */
871    public String flattenToString() {
872        StringBuilder builder = new StringBuilder();
873        builder.append(mDomain);
874        builder.append(DELIMITER);
875        builder.append(mCountryCode);
876        builder.append(DELIMITER);
877        builder.append(mRatingSystem);
878        builder.append(DELIMITER);
879        builder.append(mRating);
880        if (mSubRatings != null) {
881            for (String subRating : mSubRatings) {
882                builder.append(DELIMITER);
883                builder.append(subRating);
884            }
885        }
886        return builder.toString();
887    }
888
889    /**
890     * Returns true if this rating has the same main rating as the specified rating and when this
891     * rating's sub-ratings contain the other's.
892     * <p>
893     * For example, a TvContentRating object that represents TV-PG with S(Sexual content) and
894     * V(Violence) contains TV-PG, TV-PG/S, TV-PG/V and itself.
895     * </p>
896     *
897     * @param rating The {@link TvContentRating} to check.
898     * @return {@code true} if this object contains {@code rating}, {@code false} otherwise.
899     * @hide
900     */
901    @SystemApi
902    public final boolean contains(TvContentRating rating) {
903        if (rating == null) {
904            throw new IllegalArgumentException("rating cannot be null");
905        }
906        if (!rating.getMainRating().equals(mRating)) {
907            return false;
908        }
909        List<String> subRatings = getSubRatings();
910        List<String> subRatingsOther = rating.getSubRatings();
911        if (subRatings == null && subRatingsOther == null) {
912            return true;
913        } else if (subRatings == null && subRatingsOther != null) {
914            return false;
915        } else if (subRatings != null && subRatingsOther == null) {
916            return true;
917        } else {
918            return subRatings.containsAll(subRatingsOther);
919        }
920    }
921}
922