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 
17 package android.media.tv;
18 
19 import android.annotation.NonNull;
20 import android.text.TextUtils;
21 
22 import com.android.internal.util.Preconditions;
23 
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.Objects;
28 
29 /**
30  * A class representing a TV content rating. When a TV input service inserts the content rating
31  * information on a program into the database, this class can be used to generate the formatted
32  * string for
33  * {@link TvContract.Programs#COLUMN_CONTENT_RATING TvContract.Programs.COLUMN_CONTENT_RATING}.
34  * To create a {@code TvContentRating} object, use the
35  * {@link #createRating TvContentRating.createRating} method with valid rating system string
36  * constants.
37  *
38  * <p>It is possible for an application to define its own content rating system by supplying a
39  * content rating system definition XML resource (see example below) and declaring a broadcast
40  * receiver that filters {@link TvInputManager#ACTION_QUERY_CONTENT_RATING_SYSTEMS} in its manifest.
41  *
42  * <h3> Example: Rating system definition for the TV Parental Guidelines</h3>
43  * The following XML example shows how the TV Parental Guidelines in the United States can be
44  * defined:
45  * <p><pre class="prettyprint">
46  * {@literal
47  * <rating-system-definitions xmlns:android="http://schemas.android.com/apk/res/android"
48  *     android:versionCode="1">
49  *     <rating-system-definition android:name="US_TV"
50  *         android:country="US"
51  *         android:description="@string/description_us_tv">
52  *         <sub-rating-definition android:name="US_TV_D"
53  *             android:title="D"
54  *             android:description="@string/description_us_tv_d" />
55  *         <sub-rating-definition android:name="US_TV_L"
56  *             android:title="L"
57  *             android:description="@string/description_us_tv_l" />
58  *         <sub-rating-definition android:name="US_TV_S"
59  *             android:title="S"
60  *             android:description="@string/description_us_tv_s" />
61  *         <sub-rating-definition android:name="US_TV_V"
62  *             android:title="V"
63  *             android:description="@string/description_us_tv_v" />
64  *         <sub-rating-definition android:name="US_TV_FV"
65  *             android:title="FV"
66  *             android:description="@string/description_us_tv_fv" />
67  *
68  *         <rating-definition android:name="US_TV_Y"
69  *             android:title="TV-Y"
70  *             android:description="@string/description_us_tv_y"
71  *             android:icon="@drawable/icon_us_tv_y"
72  *             android:contentAgeHint="0" />
73  *         <rating-definition android:name="US_TV_Y7"
74  *             android:title="TV-Y7"
75  *             android:description="@string/description_us_tv_y7"
76  *             android:icon="@drawable/icon_us_tv_y7"
77  *             android:contentAgeHint="7">
78  *             <sub-rating android:name="US_TV_FV" />
79  *         </rating-definition>
80  *         <rating-definition android:name="US_TV_G"
81  *             android:title="TV-G"
82  *             android:description="@string/description_us_tv_g"
83  *             android:icon="@drawable/icon_us_tv_g"
84  *             android:contentAgeHint="0" />
85  *         <rating-definition android:name="US_TV_PG"
86  *             android:title="TV-PG"
87  *             android:description="@string/description_us_tv_pg"
88  *             android:icon="@drawable/icon_us_tv_pg"
89  *             android:contentAgeHint="14">
90  *             <sub-rating android:name="US_TV_D" />
91  *             <sub-rating android:name="US_TV_L" />
92  *             <sub-rating android:name="US_TV_S" />
93  *             <sub-rating android:name="US_TV_V" />
94  *         </rating-definition>
95  *         <rating-definition android:name="US_TV_14"
96  *             android:title="TV-14"
97  *             android:description="@string/description_us_tv_14"
98  *             android:icon="@drawable/icon_us_tv_14"
99  *             android:contentAgeHint="14">
100  *             <sub-rating android:name="US_TV_D" />
101  *             <sub-rating android:name="US_TV_L" />
102  *             <sub-rating android:name="US_TV_S" />
103  *             <sub-rating android:name="US_TV_V" />
104  *         </rating-definition>
105  *         <rating-definition android:name="US_TV_MA"
106  *             android:title="TV-MA"
107  *             android:description="@string/description_us_tv_ma"
108  *             android:icon="@drawable/icon_us_tv_ma"
109  *             android:contentAgeHint="17">
110  *             <sub-rating android:name="US_TV_L" />
111  *             <sub-rating android:name="US_TV_S" />
112  *             <sub-rating android:name="US_TV_V" />
113  *         </rating-definition>
114  *         <rating-order>
115  *             <rating android:name="US_TV_Y" />
116  *             <rating android:name="US_TV_Y7" />
117  *         </rating-order>
118  *         <rating-order>
119  *             <rating android:name="US_TV_G" />
120  *             <rating android:name="US_TV_PG" />
121  *             <rating android:name="US_TV_14" />
122  *             <rating android:name="US_TV_MA" />
123  *         </rating-order>
124  *     </rating-system-definition>
125  * </rating-system-definitions>}</pre>
126  *
127  * <h3>System defined rating strings</h3>
128  * The following strings are defined by the system to provide a standard way to create
129  * {@code TvContentRating} objects.
130  *
131  * <p>For example, to create an object that represents TV-PG rating with suggestive dialogue and
132  * coarse language from the TV Parental Guidelines in the United States, one can use the following
133  * code snippet:
134  *
135  * <pre>
136  * TvContentRating rating = TvContentRating.createRating(
137  *         "com.android.tv",
138  *         "US_TV",
139  *         "US_TV_PG",
140  *         "US_TV_D", "US_TV_L");
141  * </pre>
142  * <h4>System defined string for domains</h4>
143  * <table>
144  *     <tr>
145  *         <th>Constant Value</th>
146  *         <th>Description</th>
147  *     </tr>
148  *     <tr>
149  *         <td>com.android.tv</td>
150  *         <td>Used for creating system defined content ratings</td>
151  *     </tr>
152  * </table>
153  *
154  * <h4>System defined strings for rating systems</h4>
155  * <table>
156  *     <tr>
157  *         <th>Constant Value</th>
158  *         <th>Description</th>
159  *     </tr>
160  *     <tr>
161  *         <td>AR_TV</td>
162  *         <td>TV content rating system for Argentina</td>
163  *     </tr>
164  *     <tr>
165  *         <td>AU_TV</td>
166  *         <td>TV content rating system for Australia</td>
167  *     </tr>
168  *     <tr>
169  *         <td>BR_TV</td>
170  *         <td>TV content rating system for Brazil</td>
171  *     </tr>
172  *     <tr>
173  *         <td>CA_TV_EN</td>
174  *         <td>TV content rating system for Canada (English)</td>
175  *     </tr>
176  *     <tr>
177  *         <td>CA_TV_FR</td>
178  *         <td>TV content rating system for Canada (French)</td>
179  *     </tr>
180  *     <tr>
181  *         <td>DTMB</td>
182  *         <td>DTMB content rating system</td>
183  *     </tr>
184  *     <tr>
185  *         <td>DVB</td>
186  *         <td>DVB content rating system</td>
187  *     </tr>
188  *     <tr>
189  *         <td>ES_DVB</td>
190  *         <td>DVB content rating system for Spain</td>
191  *     </tr>
192  *     <tr>
193  *         <td>FR_DVB</td>
194  *         <td>DVB content rating system for France</td>
195  *     </tr>
196  *     <tr>
197  *         <td>ISDB</td>
198  *         <td>ISDB content rating system</td>
199  *     </tr>
200  *     <tr>
201  *         <td>KR_TV</td>
202  *         <td>TV content rating system for South Korea</td>
203  *     </tr>
204  *     <tr>
205  *         <td>NZ_TV</td>
206  *         <td>TV content rating system for New Zealand</td>
207  *     </tr>
208  *     <tr>
209  *         <td>SG_TV</td>
210  *         <td>TV content rating system for Singapore</td>
211  *     </tr>
212  *     <tr>
213  *         <td>TH_TV</td>
214  *         <td>TV content rating system for Thailand</td>
215  *     </tr>
216  *     <tr>
217  *         <td>US_MV</td>
218  *         <td>Movie content rating system for the United States</td>
219  *     </tr>
220  *     <tr>
221  *         <td>US_TV</td>
222  *         <td>TV content rating system for the United States</td>
223  *     </tr>
224  * </table>
225  *
226  * <h4>System defined strings for ratings</h4>
227  * <table>
228  *     <tr>
229  *         <th>Rating System</th>
230  *         <th>Constant Value</th>
231  *         <th>Description</th>
232  *     </tr>
233  *     <tr>
234  *         <td valign="top" rowspan="4">AR_TV</td>
235  *         <td>AR_TV_ATP</td>
236  *         <td>Suitable for all audiences. Programs may contain mild violence, language and mature
237  *         situations</td>
238  *     </tr>
239  *     <tr>
240  *         <td>AR_TV_SAM_13</td>
241  *         <td>Suitable for ages 13 and up. Programs may contain mild to moderate language and mild
242  *         violence and sexual references</td>
243  *     </tr>
244  *     <tr>
245  *         <td>AR_TV_SAM_16</td>
246  *         <td>Suitable for ages 16 and up. Programs may contain more intensive violence and coarse
247  *         language, partial nudity and moderate sexual references</td>
248  *     </tr>
249  *     <tr>
250  *         <td>AR_TV_SAM_18</td>
251  *         <td>Suitable for mature audiences only. Programs contain strong violence, coarse language
252  *         and explicit sexual references</td>
253  *     </tr>
254  *     <tr>
255  *         <td valign="top" rowspan="8">AU_TV</td>
256  *         <td>AU_TV_P</td>
257  *         <td>Recommended for younger children aged between 2 and 11 years</td>
258  *     </tr>
259  *     <tr>
260  *         <td>AU_TV_C</td>
261  *         <td>Recommended for older children aged between 5 and 14 years</td>
262  *     </tr>
263  *     <tr>
264  *         <td>AU_TV_G</td>
265  *         <td>Recommended for all ages</td>
266  *     </tr>
267  *     <tr>
268  *         <td>AU_TV_PG</td>
269  *         <td>Parental guidance is recommended for young viewers under 15</td>
270  *     </tr>
271  *     <tr>
272  *         <td>AU_TV_M</td>
273  *         <td>Recommended for mature audiences aged 15 years and over</td>
274  *     </tr>
275  *     <tr>
276  *         <td>AU_TV_MA</td>
277  *         <td>Not suitable for children and teens under 15, due to sexual descriptions, course
278  *         language, adult themes or drug use</td>
279  *     </tr>
280  *     <tr>
281  *         <td>AU_TV_AV</td>
282  *         <td>Not suitable for children and teens under 15. This category is used specifically for
283  *         violent programs</td>
284  *     </tr>
285  *     <tr>
286  *         <td>AU_TV_R</td>
287  *         <td>Not for children under 18. Content may include graphic violence, sexual situations,
288  *         coarse language and explicit drug use</td>
289  *     </tr>
290  *     <tr>
291  *         <td valign="top" rowspan="6">BR_TV</td>
292  *         <td>BR_TV_L</td>
293  *         <td>Content is suitable for all audiences</td>
294  *     </tr>
295  *     <tr>
296  *         <td>BR_TV_10</td>
297  *         <td>Content suitable for viewers over the age of 10</td>
298  *     </tr>
299  *     <tr>
300  *         <td>BR_TV_12</td>
301  *         <td>Content suitable for viewers over the age of 12</td>
302  *     </tr>
303  *     <tr>
304  *         <td>BR_TV_14</td>
305  *         <td>Content suitable for viewers over the age of 14</td>
306  *     </tr>
307  *     <tr>
308  *         <td>BR_TV_16</td>
309  *         <td>Content suitable for viewers over the age of 16</td>
310  *     </tr>
311  *     <tr>
312  *         <td>BR_TV_18</td>
313  *         <td>Content suitable for viewers over the age of 18</td>
314  *     </tr>
315  *     <tr>
316  *         <td valign="top" rowspan="7">CA_TV_EN</td>
317  *         <td>CA_TV_EN_EXEMPT</td>
318  *         <td>Exempt from ratings</td>
319  *     </tr>
320  *     <tr>
321  *         <td>CA_TV_EN_C</td>
322  *         <td>Suitable for children ages 2&#8211;7</td>
323  *     </tr>
324  *     <tr>
325  *         <td>CA_TV_EN_C8</td>
326  *         <td>Suitable for children ages 8 and older</td>
327  *     </tr>
328  *     <tr>
329  *         <td>CA_TV_EN_G</td>
330  *         <td>Suitable for the entire family</td>
331  *     </tr>
332  *     <tr>
333  *         <td>CA_TV_EN_PG</td>
334  *         <td>May contain moderate violence, profanity, nudity, and sexual references</td>
335  *     </tr>
336  *     <tr>
337  *         <td>CA_TV_EN_14</td>
338  *         <td>Intended for viewers ages 14 and older</td>
339  *     </tr>
340  *     <tr>
341  *         <td>CA_TV_EN_18</td>
342  *         <td>Intended for viewers ages 18 and older</td>
343  *     </tr>
344  *     <tr>
345  *         <td valign="top" rowspan="6">CA_TV_FR</td>
346  *         <td>CA_TV_FR_E</td>
347  *         <td>Exempt from ratings</td>
348  *     </tr>
349  *     <tr>
350  *         <td>CA_TV_FR_G</td>
351  *         <td>Appropriate for all ages</td>
352  *     </tr>
353  *     <tr>
354  *         <td>CA_TV_FR_8</td>
355  *         <td>Appropriate for children 8</td>
356  *     </tr>
357  *     <tr>
358  *         <td>CA_TV_FR_13</td>
359  *         <td>Suitable for children 13</td>
360  *     </tr>
361  *     <tr>
362  *         <td>CA_TV_FR_16</td>
363  *         <td>Recommended for children over the age of 16</td>
364  *     </tr>
365  *     <tr>
366  *         <td>CA_TV_FR_18</td>
367  *         <td>Only to be viewed by adults</td>
368  *     </tr>
369  *     <tr>
370  *         <td valign="top" rowspan="15">DTMB</td>
371  *         <td>DTMB_4</td>
372  *         <td>Recommended for ages 4 and over</td>
373  *     </tr>
374  *     <tr>
375  *         <td>DTMB_5</td>
376  *         <td>Recommended for ages 5 and over</td>
377  *     </tr>
378  *     <tr>
379  *         <td>DTMB_6</td>
380  *         <td>Recommended for ages 6 and over</td>
381  *     </tr>
382  *     <tr>
383  *         <td>DTMB_7</td>
384  *         <td>Recommended for ages 7 and over</td>
385  *     </tr>
386  *     <tr>
387  *         <td>DTMB_8</td>
388  *         <td>Recommended for ages 8 and over</td>
389  *     </tr>
390  *     <tr>
391  *         <td>DTMB_9</td>
392  *         <td>Recommended for ages 9 and over</td>
393  *     </tr>
394  *     <tr>
395  *         <td>DTMB_10</td>
396  *         <td>Recommended for ages 10 and over</td>
397  *     </tr>
398  *     <tr>
399  *         <td>DTMB_11</td>
400  *         <td>Recommended for ages 11 and over</td>
401  *     </tr>
402  *     <tr>
403  *         <td>DTMB_12</td>
404  *         <td>Recommended for ages 12 and over</td>
405  *     </tr>
406  *     <tr>
407  *         <td>DTMB_13</td>
408  *         <td>Recommended for ages 13 and over</td>
409  *     </tr>
410  *     <tr>
411  *         <td>DTMB_14</td>
412  *         <td>Recommended for ages 14 and over</td>
413  *     </tr>
414  *     <tr>
415  *         <td>DTMB_15</td>
416  *         <td>Recommended for ages 15 and over</td>
417  *     </tr>
418  *     <tr>
419  *         <td>DTMB_16</td>
420  *         <td>Recommended for ages 16 and over</td>
421  *     </tr>
422  *     <tr>
423  *         <td>DTMB_17</td>
424  *         <td>Recommended for ages 17 and over</td>
425  *     </tr>
426  *     <tr>
427  *         <td>DTMB_18</td>
428  *         <td>Recommended for ages 18 and over</td>
429  *     </tr>
430  *     <tr>
431  *         <td valign="top" rowspan="15">DVB</td>
432  *         <td>DVB_4</td>
433  *         <td>Recommended for ages 4 and over</td>
434  *     </tr>
435  *     <tr>
436  *         <td>DVB_5</td>
437  *         <td>Recommended for ages 5 and over</td>
438  *     </tr>
439  *     <tr>
440  *         <td>DVB_6</td>
441  *         <td>Recommended for ages 6 and over</td>
442  *     </tr>
443  *     <tr>
444  *         <td>DVB_7</td>
445  *         <td>Recommended for ages 7 and over</td>
446  *     </tr>
447  *     <tr>
448  *         <td>DVB_8</td>
449  *         <td>Recommended for ages 8 and over</td>
450  *     </tr>
451  *     <tr>
452  *         <td>DVB_9</td>
453  *         <td>Recommended for ages 9 and over</td>
454  *     </tr>
455  *     <tr>
456  *         <td>DVB_10</td>
457  *         <td>Recommended for ages 10 and over</td>
458  *     </tr>
459  *     <tr>
460  *         <td>DVB_11</td>
461  *         <td>Recommended for ages 11 and over</td>
462  *     </tr>
463  *     <tr>
464  *         <td>DVB_12</td>
465  *         <td>Recommended for ages 12 and over</td>
466  *     </tr>
467  *     <tr>
468  *         <td>DVB_13</td>
469  *         <td>Recommended for ages 13 and over</td>
470  *     </tr>
471  *     <tr>
472  *         <td>DVB_14</td>
473  *         <td>Recommended for ages 14 and over</td>
474  *     </tr>
475  *     <tr>
476  *         <td>DVB_15</td>
477  *         <td>Recommended for ages 15 and over</td>
478  *     </tr>
479  *     <tr>
480  *         <td>DVB_16</td>
481  *         <td>Recommended for ages 16 and over</td>
482  *     </tr>
483  *     <tr>
484  *         <td>DVB_17</td>
485  *         <td>Recommended for ages 17 and over</td>
486  *     </tr>
487  *     <tr>
488  *         <td>DVB_18</td>
489  *         <td>Recommended for ages 18 and over</td>
490  *     </tr>
491  *     <tr>
492  *         <td valign="top" rowspan="18">ES_DVB</td>
493  *         <td>ES_DVB_ALL</td>
494  *         <td>Recommended for all ages</td>
495  *     </tr>
496  *     <tr>
497  *         <td>ES_DVB_C</td>
498  *         <td>Recommended for children</td>
499  *     </tr>
500  *     <tr>
501  *         <td>ES_DVB_X</td>
502  *         <td>Recommended for adults</td>
503  *     </tr>
504  *     <tr>
505  *         <td>ES_DVB_4</td>
506  *         <td>Recommended for ages 4 and over</td>
507  *     </tr>
508  *     <tr>
509  *         <td>ES_DVB_5</td>
510  *         <td>Recommended for ages 5 and over</td>
511  *     </tr>
512  *     <tr>
513  *         <td>ES_DVB_6</td>
514  *         <td>Recommended for ages 6 and over</td>
515  *     </tr>
516  *     <tr>
517  *         <td>ES_DVB_7</td>
518  *         <td>Recommended for ages 7 and over</td>
519  *     </tr>
520  *     <tr>
521  *         <td>ES_DVB_8</td>
522  *         <td>Recommended for ages 8 and over</td>
523  *     </tr>
524  *     <tr>
525  *         <td>ES_DVB_9</td>
526  *         <td>Recommended for ages 9 and over</td>
527  *     </tr>
528  *     <tr>
529  *         <td>ES_DVB_10</td>
530  *         <td>Recommended for ages 10 and over</td>
531  *     </tr>
532  *     <tr>
533  *         <td>ES_DVB_11</td>
534  *         <td>Recommended for ages 11 and over</td>
535  *     </tr>
536  *     <tr>
537  *         <td>ES_DVB_12</td>
538  *         <td>Recommended for ages 12 and over</td>
539  *     </tr>
540  *     <tr>
541  *         <td>ES_DVB_13</td>
542  *         <td>Recommended for ages 13 and over</td>
543  *     </tr>
544  *     <tr>
545  *         <td>ES_DVB_14</td>
546  *         <td>Recommended for ages 14 and over</td>
547  *     </tr>
548  *     <tr>
549  *         <td>ES_DVB_15</td>
550  *         <td>Recommended for ages 15 and over</td>
551  *     </tr>
552  *     <tr>
553  *         <td>ES_DVB_16</td>
554  *         <td>Recommended for ages 16 and over</td>
555  *     </tr>
556  *     <tr>
557  *         <td>ES_DVB_17</td>
558  *         <td>Recommended for ages 17 and over</td>
559  *     </tr>
560  *     <tr>
561  *         <td>ES_DVB_18</td>
562  *         <td>Recommended for ages 18 and over</td>
563  *     </tr>
564  *     <tr>
565  *         <td valign="top" rowspan="16">FR_DVB</td>
566  *         <td>FR_DVB_U</td>
567  *         <td>Recommended for all ages</td>
568  *     </tr>
569  *     <tr>
570  *         <td>FR_DVB_4</td>
571  *         <td>Recommended for ages 4 and over</td>
572  *     </tr>
573  *     <tr>
574  *         <td>FR_DVB_5</td>
575  *         <td>Recommended for ages 5 and over</td>
576  *     </tr>
577  *     <tr>
578  *         <td>FR_DVB_6</td>
579  *         <td>Recommended for ages 6 and over</td>
580  *     </tr>
581  *     <tr>
582  *         <td>FR_DVB_7</td>
583  *         <td>Recommended for ages 7 and over</td>
584  *     </tr>
585  *     <tr>
586  *         <td>FR_DVB_8</td>
587  *         <td>Recommended for ages 8 and over</td>
588  *     </tr>
589  *     <tr>
590  *         <td>FR_DVB_9</td>
591  *         <td>Recommended for ages 9 and over</td>
592  *     </tr>
593  *     <tr>
594  *         <td>FR_DVB_10</td>
595  *         <td>Recommended for ages 10 and over</td>
596  *     </tr>
597  *     <tr>
598  *         <td>FR_DVB_11</td>
599  *         <td>Recommended for ages 11 and over</td>
600  *     </tr>
601  *     <tr>
602  *         <td>FR_DVB_12</td>
603  *         <td>Recommended for ages 12 and over</td>
604  *     </tr>
605  *     <tr>
606  *         <td>FR_DVB_13</td>
607  *         <td>Recommended for ages 13 and over</td>
608  *     </tr>
609  *     <tr>
610  *         <td>FR_DVB_14</td>
611  *         <td>Recommended for ages 14 and over</td>
612  *     </tr>
613  *     <tr>
614  *         <td>FR_DVB_15</td>
615  *         <td>Recommended for ages 15 and over</td>
616  *     </tr>
617  *     <tr>
618  *         <td>FR_DVB_16</td>
619  *         <td>Recommended for ages 16 and over</td>
620  *     </tr>
621  *     <tr>
622  *         <td>FR_DVB_17</td>
623  *         <td>Recommended for ages 17 and over</td>
624  *     </tr>
625  *     <tr>
626  *         <td>FR_DVB_18</td>
627  *         <td>Recommended for ages 18 and over</td>
628  *     </tr>
629  *     <tr>
630  *         <td valign="top" rowspan="17">ISDB</td>
631  *         <td>ISDB_4</td>
632  *         <td>Recommended for ages 4 and over</td>
633  *     </tr>
634  *     <tr>
635  *         <td>ISDB_5</td>
636  *         <td>Recommended for ages 5 and over</td>
637  *     </tr>
638  *     <tr>
639  *         <td>ISDB_6</td>
640  *         <td>Recommended for ages 6 and over</td>
641  *     </tr>
642  *     <tr>
643  *         <td>ISDB_7</td>
644  *         <td>Recommended for ages 7 and over</td>
645  *     </tr>
646  *     <tr>
647  *         <td>ISDB_8</td>
648  *         <td>Recommended for ages 8 and over</td>
649  *     </tr>
650  *     <tr>
651  *         <td>ISDB_9</td>
652  *         <td>Recommended for ages 9 and over</td>
653  *     </tr>
654  *     <tr>
655  *         <td>ISDB_10</td>
656  *         <td>Recommended for ages 10 and over</td>
657  *     </tr>
658  *     <tr>
659  *         <td>ISDB_11</td>
660  *         <td>Recommended for ages 11 and over</td>
661  *     </tr>
662  *     <tr>
663  *         <td>ISDB_12</td>
664  *         <td>Recommended for ages 12 and over</td>
665  *     </tr>
666  *     <tr>
667  *         <td>ISDB_13</td>
668  *         <td>Recommended for ages 13 and over</td>
669  *     </tr>
670  *     <tr>
671  *         <td>ISDB_14</td>
672  *         <td>Recommended for ages 14 and over</td>
673  *     </tr>
674  *     <tr>
675  *         <td>ISDB_15</td>
676  *         <td>Recommended for ages 15 and over</td>
677  *     </tr>
678  *     <tr>
679  *         <td>ISDB_16</td>
680  *         <td>Recommended for ages 16 and over</td>
681  *     </tr>
682  *     <tr>
683  *         <td>ISDB_17</td>
684  *         <td>Recommended for ages 17 and over</td>
685  *     </tr>
686  *     <tr>
687  *         <td>ISDB_18</td>
688  *         <td>Recommended for ages 18 and over</td>
689  *     </tr>
690  *     <tr>
691  *         <td>ISDB_19</td>
692  *         <td>Recommended for ages 19 and over</td>
693  *     </tr>
694  *     <tr>
695  *         <td>ISDB_20</td>
696  *         <td>Recommended for ages 20 and over</td>
697  *     </tr>
698  *     <tr>
699  *         <td valign="top" rowspan="5">KR_TV</td>
700  *         <td>KR_TV_ALL</td>
701  *         <td>Appropriate for all ages</td>
702  *     </tr>
703  *     <tr>
704  *         <td>KR_TV_7</td>
705  *         <td>May contain material inappropriate for children younger than 7, and parental
706  *         discretion should be used</td>
707  *     </tr>
708  *     <tr>
709  *         <td>KR_TV_12</td>
710  *         <td>May deemed inappropriate for those younger than 12, and parental discretion should be
711  *         used</td>
712  *     </tr>
713  *     <tr>
714  *         <td>KR_TV_15</td>
715  *         <td>May be inappropriate for children under 15, and that parental discretion should be
716  *         used</td>
717  *     </tr>
718  *     <tr>
719  *         <td>KR_TV_19</td>
720  *         <td>For adults only</td>
721  *     </tr>
722  *     <tr>
723  *         <td valign="top" rowspan="3">NZ_TV</td>
724  *         <td>NZ_TV_G</td>
725  *         <td>Programmes which exclude material likely to be unsuitable for children. Programmes
726  *         may not necessarily be designed for child viewers but should not contain material likely
727  *         to alarm or distress them</td>
728  *     </tr>
729  *     <tr>
730  *         <td>NZ_TV_PGR</td>
731  *         <td>Programmes containing material more suited for mature audiences but not necessarily
732  *         unsuitable for child viewers when subject to the guidance of a parent or an adult</td>
733  *     </tr>
734  *     <tr>
735  *         <td>NZ_TV_AO</td>
736  *         <td>Programmes containing adult themes and directed primarily at mature audiences</td>
737  *     </tr>
738  *     <tr>
739  *         <td valign="top" rowspan="6">SG_TV</td>
740  *         <td>SG_TV_G</td>
741  *         <td>Suitable for all ages</td>
742  *     </tr>
743  *     <tr>
744  *         <td>SG_TV_PG</td>
745  *         <td>Suitable for all but parents should guide their young</td>
746  *     </tr>
747  *     <tr>
748  *         <td>SG_TV_PG13</td>
749  *         <td>Suitable for persons aged 13 and above but parental guidance is advised for children
750  *         below 13</td>
751  *     </tr>
752  *     <tr>
753  *         <td>SG_TV_NC16</td>
754  *         <td>Suitable for persons aged 16 and above</td>
755  *     </tr>
756  *     <tr>
757  *         <td>SG_TV_M18</td>
758  *         <td>Suitable for persons aged 18 and above</td>
759  *     </tr>
760  *     <tr>
761  *         <td>SG_TV_R21</td>
762  *         <td>Suitable for adults aged 21 and above</td>
763  *     </tr>
764  *     <tr>
765  *         <td valign="top" rowspan="6">TH_TV</td>
766  *         <td>TH_TV_4</td>
767  *         <td>Suitable for audiences 3 to 5 years of age</td>
768  *     </tr>
769  *     <tr>
770  *         <td>TH_TV_6</td>
771  *         <td>Suitable for audiences 6 to 12 years of age</td>
772  *     </tr>
773  *     <tr>
774  *         <td>TH_TV_10</td>
775  *         <td>Suitable for all audiences</td>
776  *     </tr>
777  *     <tr>
778  *         <td>TH_TV_13</td>
779  *         <td>Parental guidance suggested for viewers age below 13</td>
780  *     </tr>
781  *     <tr>
782  *         <td>TH_TV_18</td>
783  *         <td>Parental guidance suggested for viewers age below 18</td>
784  *     </tr>
785  *     <tr>
786  *         <td>TH_TV_19</td>
787  *         <td>Not suitable for children and teenagers</td>
788  *     </tr>
789  *     <tr>
790  *         <td valign="top" rowspan="5">US_MV</td>
791  *         <td>US_MV_G</td>
792  *         <td>General audiences</td>
793  *     </tr>
794  *     <tr>
795  *         <td>US_MV_PG</td>
796  *         <td>Parental guidance suggested</td>
797  *     </tr>
798  *     <tr>
799  *         <td>US_MV_PG13</td>
800  *         <td>Parents strongly cautioned</td>
801  *     </tr>
802  *     <tr>
803  *         <td>US_MV_R</td>
804  *         <td>Restricted, under 17 requires accompanying parent or adult guardian</td>
805  *     </tr>
806  *     <tr>
807  *         <td>US_MV_NC17</td>
808  *         <td>No one 17 and under admitted</td>
809  *     </tr>
810  *     <tr>
811  *         <td valign="top" rowspan="6">US_TV</td>
812  *         <td>US_TV_Y</td>
813  *         <td>This program is designed to be appropriate for all children</td>
814  *     </tr>
815  *     <tr>
816  *         <td>US_TV_Y7</td>
817  *         <td>This program is designed for children age 7 and above</td>
818  *     </tr>
819  *     <tr>
820  *         <td>US_TV_G</td>
821  *         <td>Most parents would find this program suitable for all ages</td>
822  *     </tr>
823  *     <tr>
824  *         <td>US_TV_PG</td>
825  *         <td>This program contains material that parents may find unsuitable for younger children
826  *         </td>
827  *     </tr>
828  *     <tr>
829  *         <td>US_TV_14</td>
830  *         <td>This program contains some material that many parents would find unsuitable for
831  *         children under 14 years of age</td>
832  *     </tr>
833  *     <tr>
834  *         <td>US_TV_MA</td>
835  *         <td>This program is specifically designed to be viewed by adults and therefore may be
836  *         unsuitable for children under 17</td>
837  *     </tr>
838  * </table>
839  *
840  * <h4>System defined strings for sub-ratings</h4>
841  * <table>
842  *     <tr>
843  *         <th>Rating System</th>
844  *         <th>Constant Value</th>
845  *         <th>Description</th>
846  *     </tr>
847  *     <tr>
848  *         <td valign="top" rowspan="3">BR_TV</td>
849  *         <td>BR_TV_D</td>
850  *         <td>Drugs<br/>Applicable to BR_TV_L, BR_TV_10, BR_TV_12, BR_TV_14, BR_TV_16, and BR_TV_18
851  *         </td>
852  *     </tr>
853  *     <tr>
854  *         <td>BR_TV_S</td>
855  *         <td>Sex<br/>Applicable to BR_TV_L, BR_TV_10, BR_TV_12, BR_TV_14, BR_TV_16, and BR_TV_18
856  *         </td>
857  *     </tr>
858  *     <tr>
859  *         <td>BR_TV_V</td>
860  *         <td>Violence<br/>Applicable to BR_TV_L, BR_TV_10, BR_TV_12, BR_TV_14, BR_TV_16, and
861  *         BR_TV_18</td>
862  *     </tr>
863  *     <tr>
864  *         <td valign="top" rowspan="5">US_TV</td>
865  *         <td>US_TV_D</td>
866  *         <td>Suggestive dialogue (Usually means talks about sex)<br/>Applicable to US_TV_PG, and
867  *         US_TV_14</td>
868  *     </tr>
869  *     <tr>
870  *         <td>US_TV_L</td>
871  *         <td>Coarse language<br/>Applicable to US_TV_PG, US_TV_14, and US_TV_MA</td>
872  *     </tr>
873  *     <tr>
874  *         <td>US_TV_S</td>
875  *         <td>Sexual content<br/>Applicable to US_TV_PG, US_TV_14, and US_TV_MA</td>
876  *     </tr>
877  *     <tr>
878  *         <td>US_TV_V</td>
879  *         <td>Violence<br/>Applicable to US_TV_PG, US_TV_14, and US_TV_MA</td>
880  *     </tr>
881  *     <tr>
882  *         <td>US_TV_FV</td>
883  *         <td>Fantasy violence (Children's programming only)<br/>Applicable to US_TV_Y7</td>
884  *     </tr>
885  * </table>
886  */
887 public final class TvContentRating {
888     // TODO: Consider to use other DELIMITER. In some countries such as India may use this delimiter
889     // in the main ratings.
890     private static final String DELIMITER = "/";
891 
892     private final String mDomain;
893     private final String mRatingSystem;
894     private final String mRating;
895     private final String[] mSubRatings;
896     private final int mHashCode;
897 
898     /**
899      * Rating constant denoting unrated content. Used to handle the case where the content rating
900      * information is missing.
901      *
902      * <p>TV input services can call {@link TvInputManager#isRatingBlocked} with this constant to
903      * determine whether they should block unrated content. The subsequent call to
904      * {@link TvInputService.Session#notifyContentBlocked} with the same constant notifies
905      * applications that the current program content is blocked by parental controls.
906      */
907     public static final TvContentRating UNRATED = new TvContentRating("null", "null", "null", null);
908 
909     /**
910      * Creates a {@code TvContentRating} object with predefined content rating strings.
911      *
912      * @param domain The domain string. For example, "com.android.tv".
913      * @param ratingSystem The rating system string. For example, "US_TV".
914      * @param rating The content rating string. For example, "US_TV_PG".
915      * @param subRatings The sub-rating strings. For example, "US_TV_D" and "US_TV_L".
916      * @return A {@code TvContentRating} object.
917      * @throws IllegalArgumentException If {@code domain}, {@code ratingSystem} or {@code rating} is
918      *             {@code null}.
919      */
createRating(String domain, String ratingSystem, String rating, String... subRatings)920     public static TvContentRating createRating(String domain, String ratingSystem,
921             String rating, String... subRatings) {
922         if (TextUtils.isEmpty(domain)) {
923             throw new IllegalArgumentException("domain cannot be empty");
924         }
925         if (TextUtils.isEmpty(ratingSystem)) {
926             throw new IllegalArgumentException("ratingSystem cannot be empty");
927         }
928         if (TextUtils.isEmpty(rating)) {
929             throw new IllegalArgumentException("rating cannot be empty");
930         }
931         return new TvContentRating(domain, ratingSystem, rating, subRatings);
932     }
933 
934     /**
935      * Recovers a {@code TvContentRating} object from the string that was previously created from
936      * {@link #flattenToString}.
937      *
938      * @param ratingString The string returned by {@link #flattenToString}.
939      * @return the {@code TvContentRating} object containing the domain, rating system, rating and
940      *         sub-ratings information encoded in {@code ratingString}.
941      * @see #flattenToString
942      */
unflattenFromString(String ratingString)943     public static TvContentRating unflattenFromString(String ratingString) {
944         if (TextUtils.isEmpty(ratingString)) {
945             throw new IllegalArgumentException("ratingString cannot be empty");
946         }
947         String[] strs = ratingString.split(DELIMITER);
948         if (strs.length < 3) {
949             throw new IllegalArgumentException("Invalid rating string: " + ratingString);
950         }
951         if (strs.length > 3) {
952             String[] subRatings = new String[strs.length - 3];
953             System.arraycopy(strs, 3, subRatings, 0, subRatings.length);
954             return new TvContentRating(strs[0], strs[1], strs[2], subRatings);
955         }
956         return new TvContentRating(strs[0], strs[1], strs[2], null);
957     }
958 
959     /**
960      * Constructs a TvContentRating object from a given rating and sub-rating constants.
961      *
962      * @param domain The string for domain of the content rating system such as "com.android.tv".
963      * @param ratingSystem The rating system string such as "US_TV".
964      * @param rating The content rating string such as "US_TV_PG".
965      * @param subRatings The sub-rating strings such as "US_TV_D" and "US_TV_L".
966      */
TvContentRating( String domain, String ratingSystem, String rating, String[] subRatings)967     private TvContentRating(
968             String domain, String ratingSystem, String rating, String[] subRatings) {
969         mDomain = domain;
970         mRatingSystem = ratingSystem;
971         mRating = rating;
972         if (subRatings == null || subRatings.length == 0) {
973             mSubRatings = null;
974         } else {
975             Arrays.sort(subRatings);
976             mSubRatings = subRatings;
977         }
978         mHashCode = 31 * Objects.hash(mDomain, mRating) + Arrays.hashCode(mSubRatings);
979     }
980 
981     /**
982      * Returns the domain of this {@code TvContentRating} object.
983      */
getDomain()984     public String getDomain() {
985         return mDomain;
986     }
987 
988     /**
989      * Returns the rating system of this {@code TvContentRating} object.
990      */
getRatingSystem()991     public String getRatingSystem() {
992         return mRatingSystem;
993     }
994 
995     /**
996      * Returns the main rating of this {@code TvContentRating} object.
997      */
getMainRating()998     public String getMainRating() {
999         return mRating;
1000     }
1001 
1002     /**
1003      * Returns the unmodifiable sub-rating string {@link List} of this {@code TvContentRating}
1004      * object.
1005      */
getSubRatings()1006     public List<String> getSubRatings() {
1007         if (mSubRatings == null) {
1008             return null;
1009         }
1010         return Collections.unmodifiableList(Arrays.asList(mSubRatings));
1011     }
1012 
1013     /**
1014      * Returns a string that unambiguously describes the rating information contained in a
1015      * {@code TvContentRating} object. One can later recover the object from this string through
1016      * {@link #unflattenFromString}.
1017      *
1018      * @return a string containing the rating information, which can later be stored in the
1019      *         database.
1020      * @see #unflattenFromString
1021      */
flattenToString()1022     public String flattenToString() {
1023         StringBuilder builder = new StringBuilder();
1024         builder.append(mDomain);
1025         builder.append(DELIMITER);
1026         builder.append(mRatingSystem);
1027         builder.append(DELIMITER);
1028         builder.append(mRating);
1029         if (mSubRatings != null) {
1030             for (String subRating : mSubRatings) {
1031                 builder.append(DELIMITER);
1032                 builder.append(subRating);
1033             }
1034         }
1035         return builder.toString();
1036     }
1037 
1038     /**
1039      * Returns {@code true} if this rating has the same main rating as the specified rating and when
1040      * this rating's sub-ratings contain the other's.
1041      *
1042      * <p>For example, a {@code TvContentRating} object that represents TV-PG with
1043      * S(Sexual content) and V(Violence) contains TV-PG, TV-PG/S, TV-PG/V and itself.
1044      *
1045      * @param rating The {@link TvContentRating} to check.
1046      * @return {@code true} if this object contains {@code rating}, {@code false} otherwise.
1047      */
contains(@onNull TvContentRating rating)1048     public final boolean contains(@NonNull TvContentRating rating) {
1049         Preconditions.checkNotNull(rating);
1050         if (!rating.getMainRating().equals(mRating)) {
1051             return false;
1052         }
1053         if (!rating.getDomain().equals(mDomain) ||
1054                 !rating.getRatingSystem().equals(mRatingSystem) ||
1055                 !rating.getMainRating().equals(mRating)) {
1056             return false;
1057         }
1058         List<String> subRatings = getSubRatings();
1059         List<String> subRatingsOther = rating.getSubRatings();
1060         if (subRatings == null && subRatingsOther == null) {
1061             return true;
1062         } else if (subRatings == null && subRatingsOther != null) {
1063             return false;
1064         } else if (subRatings != null && subRatingsOther == null) {
1065             return true;
1066         } else {
1067             return subRatings.containsAll(subRatingsOther);
1068         }
1069     }
1070 
1071     @Override
equals(Object obj)1072     public boolean equals(Object obj) {
1073         if (!(obj instanceof TvContentRating)) {
1074             return false;
1075         }
1076         TvContentRating other = (TvContentRating) obj;
1077         if (mHashCode != other.mHashCode) {
1078             return false;
1079         }
1080         if (!TextUtils.equals(mDomain, other.mDomain)) {
1081             return false;
1082         }
1083         if (!TextUtils.equals(mRatingSystem, other.mRatingSystem)) {
1084             return false;
1085         }
1086         if (!TextUtils.equals(mRating, other.mRating)) {
1087             return false;
1088         }
1089         return Arrays.equals(mSubRatings, other.mSubRatings);
1090     }
1091 
1092     @Override
hashCode()1093     public int hashCode() {
1094         return mHashCode;
1095     }
1096 }
1097