TvContentRating.java revision 344f9e5e9a6b59495304f4893f055b54ea4d85d3
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>DVB</td> 175 * <td>DVB content rating system</td> 176 * </tr> 177 * <tr> 178 * <td>ES_DVB</td> 179 * <td>DVB content rating system for Spain</td> 180 * </tr> 181 * <tr> 182 * <td>FR_DVB</td> 183 * <td>DVB content rating system for France</td> 184 * </tr> 185 * <tr> 186 * <td>ISDB</td> 187 * <td>ISDB content rating system</td> 188 * </tr> 189 * <tr> 190 * <td>KR_TV</td> 191 * <td>TV content rating system for South Korea</td> 192 * </tr> 193 * <tr> 194 * <td>SG_TV</td> 195 * <td>TV content rating system for Singapore</td> 196 * </tr> 197 * <tr> 198 * <td>US_TV</td> 199 * <td>TV content rating system for the United States</td> 200 * </tr> 201 * </table> 202 * 203 * <h4>System defined strings for ratings</h4> 204 * <table> 205 * <tr> 206 * <th>Rating System</th> 207 * <th>Constant Value</th> 208 * <th>Description</th> 209 * </tr> 210 * <tr> 211 * <td valign="top" rowspan="4">AR_TV</td> 212 * <td>AR_TV_ATP</td> 213 * <td>Suitable for all audiences. Programs may contain mild violence, language and mature 214 * situations</td> 215 * </tr> 216 * <tr> 217 * <td>AR_TV_SAM_13</td> 218 * <td>Suitable for ages 13 and up. Programs may contain mild to moderate language and mild 219 * violence and sexual references</td> 220 * </tr> 221 * <tr> 222 * <td>AR_TV_SAM_16</td> 223 * <td>Suitable for ages 16 and up. Programs may contain more intensive violence and coarse 224 * language, partial nudity and moderate sexual references</td> 225 * </tr> 226 * <tr> 227 * <td>AR_TV_SAM_18</td> 228 * <td>Suitable for mature audiences only. Programs contain strong violence, coarse language 229 * and explicit sexual references</td> 230 * </tr> 231 * <tr> 232 * <td valign="top" rowspan="8">AU_TV</td> 233 * <td>AU_TV_P</td> 234 * <td>Recommended for younger children aged between 2 and 11 years</td> 235 * </tr> 236 * <tr> 237 * <td>AU_TV_C</td> 238 * <td>Recommended for older children aged between 5 and 14 years</td> 239 * </tr> 240 * <tr> 241 * <td>AU_TV_G</td> 242 * <td>Recommended for all ages</td> 243 * </tr> 244 * <tr> 245 * <td>AU_TV_PG</td> 246 * <td>Parental guidance is recommended for young viewers under 15</td> 247 * </tr> 248 * <tr> 249 * <td>AU_TV_M</td> 250 * <td>Recommended for mature audiences aged 15 years and over</td> 251 * </tr> 252 * <tr> 253 * <td>AU_TV_MA</td> 254 * <td>Not suitable for children and teens under 15, due to sexual descriptions, course 255 * language, adult themes or drug use</td> 256 * </tr> 257 * <tr> 258 * <td>AU_TV_AV</td> 259 * <td>Not suitable for children and teens under 15. This category is used specifically for 260 * violent programs</td> 261 * </tr> 262 * <tr> 263 * <td>AU_TV_R</td> 264 * <td>Not for children under 18. Content may include graphic violence, sexual situations, 265 * coarse language and explicit drug use</td> 266 * </tr> 267 * <tr> 268 * <td valign="top" rowspan="6">BR_TV</td> 269 * <td>BR_TV_L</td> 270 * <td>Content is suitable for all audiences</td> 271 * </tr> 272 * <tr> 273 * <td>BR_TV_10</td> 274 * <td>Content suitable for viewers over the age of 10</td> 275 * </tr> 276 * <tr> 277 * <td>BR_TV_12</td> 278 * <td>Content suitable for viewers over the age of 12</td> 279 * </tr> 280 * <tr> 281 * <td>BR_TV_14</td> 282 * <td>Content suitable for viewers over the age of 14</td> 283 * </tr> 284 * <tr> 285 * <td>BR_TV_16</td> 286 * <td>Content suitable for viewers over the age of 16</td> 287 * </tr> 288 * <tr> 289 * <td>BR_TV_18</td> 290 * <td>Content suitable for viewers over the age of 18</td> 291 * </tr> 292 * <tr> 293 * <td valign="top" rowspan="15">DVB</td> 294 * <td>DVB_4</td> 295 * <td>Recommended for ages 4 and over</td> 296 * </tr> 297 * <tr> 298 * <td>DVB_5</td> 299 * <td>Recommended for ages 5 and over</td> 300 * </tr> 301 * <tr> 302 * <td>DVB_6</td> 303 * <td>Recommended for ages 6 and over</td> 304 * </tr> 305 * <tr> 306 * <td>DVB_7</td> 307 * <td>Recommended for ages 7 and over</td> 308 * </tr> 309 * <tr> 310 * <td>DVB_8</td> 311 * <td>Recommended for ages 8 and over</td> 312 * </tr> 313 * <tr> 314 * <td>DVB_9</td> 315 * <td>Recommended for ages 9 and over</td> 316 * </tr> 317 * <tr> 318 * <td>DVB_10</td> 319 * <td>Recommended for ages 10 and over</td> 320 * </tr> 321 * <tr> 322 * <td>DVB_11</td> 323 * <td>Recommended for ages 11 and over</td> 324 * </tr> 325 * <tr> 326 * <td>DVB_12</td> 327 * <td>Recommended for ages 12 and over</td> 328 * </tr> 329 * <tr> 330 * <td>DVB_13</td> 331 * <td>Recommended for ages 13 and over</td> 332 * </tr> 333 * <tr> 334 * <td>DVB_14</td> 335 * <td>Recommended for ages 14 and over</td> 336 * </tr> 337 * <tr> 338 * <td>DVB_15</td> 339 * <td>Recommended for ages 15 and over</td> 340 * </tr> 341 * <tr> 342 * <td>DVB_16</td> 343 * <td>Recommended for ages 16 and over</td> 344 * </tr> 345 * <tr> 346 * <td>DVB_17</td> 347 * <td>Recommended for ages 17 and over</td> 348 * </tr> 349 * <tr> 350 * <td>DVB_18</td> 351 * <td>Recommended for ages 18 and over</td> 352 * </tr> 353 * <tr> 354 * <td valign="top" rowspan="18">ES_DVB</td> 355 * <td>ES_DVB_ALL</td> 356 * <td>Recommended for all ages</td> 357 * </tr> 358 * <tr> 359 * <td>ES_DVB_C</td> 360 * <td>Recommended for children</td> 361 * </tr> 362 * <tr> 363 * <td>ES_DVB_X</td> 364 * <td>Recommended for adults</td> 365 * </tr> 366 * <tr> 367 * <td>ES_DVB_4</td> 368 * <td>Recommended for ages 4 and over</td> 369 * </tr> 370 * <tr> 371 * <td>ES_DVB_5</td> 372 * <td>Recommended for ages 5 and over</td> 373 * </tr> 374 * <tr> 375 * <td>ES_DVB_6</td> 376 * <td>Recommended for ages 6 and over</td> 377 * </tr> 378 * <tr> 379 * <td>ES_DVB_7</td> 380 * <td>Recommended for ages 7 and over</td> 381 * </tr> 382 * <tr> 383 * <td>ES_DVB_8</td> 384 * <td>Recommended for ages 8 and over</td> 385 * </tr> 386 * <tr> 387 * <td>ES_DVB_9</td> 388 * <td>Recommended for ages 9 and over</td> 389 * </tr> 390 * <tr> 391 * <td>ES_DVB_10</td> 392 * <td>Recommended for ages 10 and over</td> 393 * </tr> 394 * <tr> 395 * <td>ES_DVB_11</td> 396 * <td>Recommended for ages 11 and over</td> 397 * </tr> 398 * <tr> 399 * <td>ES_DVB_12</td> 400 * <td>Recommended for ages 12 and over</td> 401 * </tr> 402 * <tr> 403 * <td>ES_DVB_13</td> 404 * <td>Recommended for ages 13 and over</td> 405 * </tr> 406 * <tr> 407 * <td>ES_DVB_14</td> 408 * <td>Recommended for ages 14 and over</td> 409 * </tr> 410 * <tr> 411 * <td>ES_DVB_15</td> 412 * <td>Recommended for ages 15 and over</td> 413 * </tr> 414 * <tr> 415 * <td>ES_DVB_16</td> 416 * <td>Recommended for ages 16 and over</td> 417 * </tr> 418 * <tr> 419 * <td>ES_DVB_17</td> 420 * <td>Recommended for ages 17 and over</td> 421 * </tr> 422 * <tr> 423 * <td>ES_DVB_18</td> 424 * <td>Recommended for ages 18 and over</td> 425 * </tr> 426 * <tr> 427 * <td valign="top" rowspan="16">FR_DVB</td> 428 * <td>FR_DVB_U</td> 429 * <td>Recommended for all ages</td> 430 * </tr> 431 * <tr> 432 * <td>FR_DVB_4</td> 433 * <td>Recommended for ages 4 and over</td> 434 * </tr> 435 * <tr> 436 * <td>FR_DVB_5</td> 437 * <td>Recommended for ages 5 and over</td> 438 * </tr> 439 * <tr> 440 * <td>FR_DVB_6</td> 441 * <td>Recommended for ages 6 and over</td> 442 * </tr> 443 * <tr> 444 * <td>FR_DVB_7</td> 445 * <td>Recommended for ages 7 and over</td> 446 * </tr> 447 * <tr> 448 * <td>FR_DVB_8</td> 449 * <td>Recommended for ages 8 and over</td> 450 * </tr> 451 * <tr> 452 * <td>FR_DVB_9</td> 453 * <td>Recommended for ages 9 and over</td> 454 * </tr> 455 * <tr> 456 * <td>FR_DVB_10</td> 457 * <td>Recommended for ages 10 and over</td> 458 * </tr> 459 * <tr> 460 * <td>FR_DVB_11</td> 461 * <td>Recommended for ages 11 and over</td> 462 * </tr> 463 * <tr> 464 * <td>FR_DVB_12</td> 465 * <td>Recommended for ages 12 and over</td> 466 * </tr> 467 * <tr> 468 * <td>FR_DVB_13</td> 469 * <td>Recommended for ages 13 and over</td> 470 * </tr> 471 * <tr> 472 * <td>FR_DVB_14</td> 473 * <td>Recommended for ages 14 and over</td> 474 * </tr> 475 * <tr> 476 * <td>FR_DVB_15</td> 477 * <td>Recommended for ages 15 and over</td> 478 * </tr> 479 * <tr> 480 * <td>FR_DVB_16</td> 481 * <td>Recommended for ages 16 and over</td> 482 * </tr> 483 * <tr> 484 * <td>FR_DVB_17</td> 485 * <td>Recommended for ages 17 and over</td> 486 * </tr> 487 * <tr> 488 * <td>FR_DVB_18</td> 489 * <td>Recommended for ages 18 and over</td> 490 * </tr> 491 * <tr> 492 * <td valign="top" rowspan="17">ISDB</td> 493 * <td>ISDB_4</td> 494 * <td>Recommended for ages 4 and over</td> 495 * </tr> 496 * <tr> 497 * <td>ISDB_5</td> 498 * <td>Recommended for ages 5 and over</td> 499 * </tr> 500 * <tr> 501 * <td>ISDB_6</td> 502 * <td>Recommended for ages 6 and over</td> 503 * </tr> 504 * <tr> 505 * <td>ISDB_7</td> 506 * <td>Recommended for ages 7 and over</td> 507 * </tr> 508 * <tr> 509 * <td>ISDB_8</td> 510 * <td>Recommended for ages 8 and over</td> 511 * </tr> 512 * <tr> 513 * <td>ISDB_9</td> 514 * <td>Recommended for ages 9 and over</td> 515 * </tr> 516 * <tr> 517 * <td>ISDB_10</td> 518 * <td>Recommended for ages 10 and over</td> 519 * </tr> 520 * <tr> 521 * <td>ISDB_11</td> 522 * <td>Recommended for ages 11 and over</td> 523 * </tr> 524 * <tr> 525 * <td>ISDB_12</td> 526 * <td>Recommended for ages 12 and over</td> 527 * </tr> 528 * <tr> 529 * <td>ISDB_13</td> 530 * <td>Recommended for ages 13 and over</td> 531 * </tr> 532 * <tr> 533 * <td>ISDB_14</td> 534 * <td>Recommended for ages 14 and over</td> 535 * </tr> 536 * <tr> 537 * <td>ISDB_15</td> 538 * <td>Recommended for ages 15 and over</td> 539 * </tr> 540 * <tr> 541 * <td>ISDB_16</td> 542 * <td>Recommended for ages 16 and over</td> 543 * </tr> 544 * <tr> 545 * <td>ISDB_17</td> 546 * <td>Recommended for ages 17 and over</td> 547 * </tr> 548 * <tr> 549 * <td>ISDB_18</td> 550 * <td>Recommended for ages 18 and over</td> 551 * </tr> 552 * <tr> 553 * <td>ISDB_19</td> 554 * <td>Recommended for ages 19 and over</td> 555 * </tr> 556 * <tr> 557 * <td>ISDB_20</td> 558 * <td>Recommended for ages 20 and over</td> 559 * </tr> 560 * <tr> 561 * <td valign="top" rowspan="5">KR_TV</td> 562 * <td>KR_TV_ALL</td> 563 * <td>Appropriate for all ages</td> 564 * </tr> 565 * <tr> 566 * <td>KR_TV_7</td> 567 * <td>May contain material inappropriate for children younger than 7, and parental 568 * discretion should be used</td> 569 * </tr> 570 * <tr> 571 * <td>KR_TV_12</td> 572 * <td>May deemed inappropriate for those younger than 12, and parental discretion should be 573 * used</td> 574 * </tr> 575 * <tr> 576 * <td>KR_TV_15</td> 577 * <td>May be inappropriate for children under 15, and that parental discretion should be 578 * used</td> 579 * </tr> 580 * <tr> 581 * <td>KR_TV_19</td> 582 * <td>For adults only</td> 583 * </tr> 584 * <tr> 585 * <td valign="top" rowspan="6">SG_TV</td> 586 * <td>SG_TV_G</td> 587 * <td>Suitable for all ages</td> 588 * </tr> 589 * <tr> 590 * <td>SG_TV_PG</td> 591 * <td>Suitable for all but parents should guide their young</td> 592 * </tr> 593 * <tr> 594 * <td>SG_TV_PG13</td> 595 * <td>Suitable for persons aged 13 and above but parental guidance is advised for children 596 * below 13</td> 597 * </tr> 598 * <tr> 599 * <td>SG_TV_NC16</td> 600 * <td>Suitable for persons aged 16 and above</td> 601 * </tr> 602 * <tr> 603 * <td>SG_TV_M18</td> 604 * <td>Suitable for persons aged 18 and above</td> 605 * </tr> 606 * <tr> 607 * <td>SG_TV_R21</td> 608 * <td>Suitable for adults aged 21 and above</td> 609 * </tr> 610 * <tr> 611 * <td valign="top" rowspan="6">US_TV</td> 612 * <td>US_TV_Y</td> 613 * <td>This program is designed to be appropriate for all children</td> 614 * </tr> 615 * <tr> 616 * <td>US_TV_Y7</td> 617 * <td>This program is designed for children age 7 and above</td> 618 * </tr> 619 * <tr> 620 * <td>US_TV_G</td> 621 * <td>Most parents would find this program suitable for all ages</td> 622 * </tr> 623 * <tr> 624 * <td>US_TV_PG</td> 625 * <td>This program contains material that parents may find unsuitable for younger children 626 * </td> 627 * </tr> 628 * <tr> 629 * <td>US_TV_14</td> 630 * <td>This program contains some material that many parents would find unsuitable for 631 * children under 14 years of age</td> 632 * </tr> 633 * <tr> 634 * <td>US_TV_MA</td> 635 * <td>This program is specifically designed to be viewed by adults and therefore may be 636 * unsuitable for children under 17</td> 637 * </tr> 638 * </table> 639 * 640 * <h4>System defined strings for sub-ratings</h4> 641 * <table> 642 * <tr> 643 * <th>Rating System</th> 644 * <th>Constant Value</th> 645 * <th>Description</th> 646 * </tr> 647 * <tr> 648 * <td valign="top" rowspan="3">BR_TV</td> 649 * <td>BR_TV_D</td> 650 * <td>Drugs<br/>Applicable to BR_TV_L, BR_TV_10, BR_TV_12, BR_TV_14, BR_TV_16, and BR_TV_18 651 * </td> 652 * </tr> 653 * <tr> 654 * <td>BR_TV_S</td> 655 * <td>Sex<br/>Applicable to BR_TV_L, BR_TV_10, BR_TV_12, BR_TV_14, BR_TV_16, and BR_TV_18 656 * </td> 657 * </tr> 658 * <tr> 659 * <td>BR_TV_V</td> 660 * <td>Violence<br/>Applicable to BR_TV_L, BR_TV_10, BR_TV_12, BR_TV_14, BR_TV_16, and 661 * BR_TV_18</td> 662 * </tr> 663 * <tr> 664 * <td valign="top" rowspan="5">US_TV</td> 665 * <td>US_TV_D</td> 666 * <td>Suggestive dialogue (Usually means talks about sex)<br/>Applicable to US_TV_PG, and 667 * US_TV_14</td> 668 * </tr> 669 * <tr> 670 * <td>US_TV_L</td> 671 * <td>Coarse language<br/>Applicable to US_TV_PG, US_TV_14, and US_TV_MA</td> 672 * </tr> 673 * <tr> 674 * <td>US_TV_S</td> 675 * <td>Sexual content<br/>Applicable to US_TV_PG, US_TV_14, and US_TV_MA</td> 676 * </tr> 677 * <tr> 678 * <td>US_TV_V</td> 679 * <td>Violence<br/>Applicable to US_TV_PG, US_TV_14, and US_TV_MA</td> 680 * </tr> 681 * <tr> 682 * <td>US_TV_FV</td> 683 * <td>Fantasy violence (Children's programming only)<br/>Applicable to US_TV_Y7</td> 684 * </tr> 685 * </table> 686 */ 687public final class TvContentRating { 688 // TODO: Consider to use other DELIMITER. In some countries such as India may use this delimiter 689 // in the main ratings. 690 private static final String DELIMITER = "/"; 691 692 private final String mDomain; 693 private final String mRatingSystem; 694 private final String mRating; 695 private final String[] mSubRatings; 696 private final int mHashCode; 697 698 /** 699 * Rating constant denoting unrated content. 700 */ 701 public static final TvContentRating UNRATED = new TvContentRating("com.android.tv", "", 702 "UNRATED", null); 703 704 /** 705 * Creates a {@code TvContentRating} object with predefined content rating strings. 706 * 707 * @param domain The domain string. For example, "com.android.tv". 708 * @param ratingSystem The rating system string. For example, "US_TV". 709 * @param rating The content rating string. For example, "US_TV_PG". 710 * @param subRatings The sub-rating strings. For example, "US_TV_D" and "US_TV_L". 711 * @return A {@code TvContentRating} object. 712 * @throws IllegalArgumentException If {@code domain}, {@code ratingSystem} or {@code rating} is 713 * {@code null}. 714 */ 715 public static TvContentRating createRating(String domain, String ratingSystem, 716 String rating, String... subRatings) { 717 if (TextUtils.isEmpty(domain)) { 718 throw new IllegalArgumentException("domain cannot be empty"); 719 } 720 if (TextUtils.isEmpty(ratingSystem)) { 721 throw new IllegalArgumentException("ratingSystem cannot be empty"); 722 } 723 if (TextUtils.isEmpty(rating)) { 724 throw new IllegalArgumentException("rating cannot be empty"); 725 } 726 return new TvContentRating(domain, ratingSystem, rating, subRatings); 727 } 728 729 /** 730 * Recovers a {@code TvContentRating} object from the string that was previously created from 731 * {@link #flattenToString}. 732 * 733 * @param ratingString The string returned by {@link #flattenToString}. 734 * @return the {@code TvContentRating} object containing the domain, rating system, rating and 735 * sub-ratings information encoded in {@code ratingString}. 736 * @see #flattenToString 737 */ 738 public static TvContentRating unflattenFromString(String ratingString) { 739 if (TextUtils.isEmpty(ratingString)) { 740 throw new IllegalArgumentException("ratingString cannot be empty"); 741 } 742 String[] strs = ratingString.split(DELIMITER); 743 if (strs.length < 3) { 744 throw new IllegalArgumentException("Invalid rating string: " + ratingString); 745 } 746 if (strs.length > 3) { 747 String[] subRatings = new String[strs.length - 3]; 748 System.arraycopy(strs, 3, subRatings, 0, subRatings.length); 749 return new TvContentRating(strs[0], strs[1], strs[2], subRatings); 750 } 751 return new TvContentRating(strs[0], strs[1], strs[2], null); 752 } 753 754 /** 755 * Constructs a TvContentRating object from a given rating and sub-rating constants. 756 * 757 * @param domain The string for domain of the content rating system such as "com.android.tv". 758 * @param ratingSystem The rating system string such as "US_TV". 759 * @param rating The content rating string such as "US_TV_PG". 760 * @param subRatings The sub-rating strings such as "US_TV_D" and "US_TV_L". 761 */ 762 private TvContentRating( 763 String domain, String ratingSystem, String rating, String[] subRatings) { 764 mDomain = domain; 765 mRatingSystem = ratingSystem; 766 mRating = rating; 767 if (subRatings == null || subRatings.length == 0) { 768 mSubRatings = null; 769 } else { 770 Arrays.sort(subRatings); 771 mSubRatings = subRatings; 772 } 773 mHashCode = 31 * Objects.hash(mDomain, mRating) + Arrays.hashCode(mSubRatings); 774 } 775 776 /** 777 * Returns the domain of this {@code TvContentRating} object. 778 */ 779 public String getDomain() { 780 return mDomain; 781 } 782 783 /** 784 * Returns the rating system of this {@code TvContentRating} object. 785 */ 786 public String getRatingSystem() { 787 return mRatingSystem; 788 } 789 790 /** 791 * Returns the main rating of this {@code TvContentRating} object. 792 */ 793 public String getMainRating() { 794 return mRating; 795 } 796 797 /** 798 * Returns the unmodifiable sub-rating string {@link List} of this {@code TvContentRating} 799 * object. 800 */ 801 public List<String> getSubRatings() { 802 if (mSubRatings == null) { 803 return null; 804 } 805 return Collections.unmodifiableList(Arrays.asList(mSubRatings)); 806 } 807 808 /** 809 * Returns a string that unambiguously describes the rating information contained in a 810 * {@code TvContentRating} object. One can later recover the object from this string through 811 * {@link #unflattenFromString}. 812 * 813 * @return a string containing the rating information, which can later be stored in the 814 * database. 815 * @see #unflattenFromString 816 */ 817 public String flattenToString() { 818 StringBuilder builder = new StringBuilder(); 819 builder.append(mDomain); 820 builder.append(DELIMITER); 821 builder.append(mRatingSystem); 822 builder.append(DELIMITER); 823 builder.append(mRating); 824 if (mSubRatings != null) { 825 for (String subRating : mSubRatings) { 826 builder.append(DELIMITER); 827 builder.append(subRating); 828 } 829 } 830 return builder.toString(); 831 } 832 833 /** 834 * Returns {@code true} if this rating has the same main rating as the specified rating and when 835 * this rating's sub-ratings contain the other's. 836 * 837 * <p>For example, a {@code TvContentRating} object that represents TV-PG with 838 * S(Sexual content) and V(Violence) contains TV-PG, TV-PG/S, TV-PG/V and itself. 839 * 840 * @param rating The {@link TvContentRating} to check. 841 * @return {@code true} if this object contains {@code rating}, {@code false} otherwise. 842 * @hide 843 */ 844 @SystemApi 845 public final boolean contains(@NonNull TvContentRating rating) { 846 Preconditions.checkNotNull(rating); 847 if (!rating.getMainRating().equals(mRating)) { 848 return false; 849 } 850 if (!rating.getDomain().equals(mDomain) || 851 !rating.getRatingSystem().equals(mRatingSystem) || 852 !rating.getMainRating().equals(mRating)) { 853 return false; 854 } 855 List<String> subRatings = getSubRatings(); 856 List<String> subRatingsOther = rating.getSubRatings(); 857 if (subRatings == null && subRatingsOther == null) { 858 return true; 859 } else if (subRatings == null && subRatingsOther != null) { 860 return false; 861 } else if (subRatings != null && subRatingsOther == null) { 862 return true; 863 } else { 864 return subRatings.containsAll(subRatingsOther); 865 } 866 } 867 868 @Override 869 public boolean equals(Object obj) { 870 if (!(obj instanceof TvContentRating)) { 871 return false; 872 } 873 TvContentRating other = (TvContentRating) obj; 874 if (mHashCode != other.mHashCode) { 875 return false; 876 } 877 if (!TextUtils.equals(mDomain, other.mDomain)) { 878 return false; 879 } 880 if (!TextUtils.equals(mRatingSystem, other.mRatingSystem)) { 881 return false; 882 } 883 if (!TextUtils.equals(mRating, other.mRating)) { 884 return false; 885 } 886 return Arrays.equals(mSubRatings, other.mSubRatings); 887 } 888 889 @Override 890 public int hashCode() { 891 return mHashCode; 892 } 893} 894