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