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