1 /* 2 * Copyright (C) 2015 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 com.android.tv.tuner.data; 18 19 import android.support.annotation.NonNull; 20 import android.text.TextUtils; 21 import android.text.format.DateUtils; 22 import com.android.tv.common.util.StringUtils; 23 import com.android.tv.tuner.data.nano.Track.AtscAudioTrack; 24 import com.android.tv.tuner.data.nano.Track.AtscCaptionTrack; 25 import com.android.tv.tuner.util.ConvertUtils; 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Locale; 30 31 /** Collection of ATSC PSIP table items. */ 32 public class PsipData { 33 PsipData()34 private PsipData() {} 35 36 public static class PsipSection { 37 private final int mTableId; 38 private final int mTableIdExtension; 39 private final int mSectionNumber; 40 private final boolean mCurrentNextIndicator; 41 create(byte[] data)42 public static PsipSection create(byte[] data) { 43 if (data.length < 9) { 44 return null; 45 } 46 int tableId = data[0] & 0xff; 47 int tableIdExtension = (data[3] & 0xff) << 8 | (data[4] & 0xff); 48 int sectionNumber = data[6] & 0xff; 49 boolean currentNextIndicator = (data[5] & 0x01) != 0; 50 return new PsipSection(tableId, tableIdExtension, sectionNumber, currentNextIndicator); 51 } 52 PsipSection( int tableId, int tableIdExtension, int sectionNumber, boolean currentNextIndicator)53 private PsipSection( 54 int tableId, 55 int tableIdExtension, 56 int sectionNumber, 57 boolean currentNextIndicator) { 58 mTableId = tableId; 59 mTableIdExtension = tableIdExtension; 60 mSectionNumber = sectionNumber; 61 mCurrentNextIndicator = currentNextIndicator; 62 } 63 getTableId()64 public int getTableId() { 65 return mTableId; 66 } 67 getTableIdExtension()68 public int getTableIdExtension() { 69 return mTableIdExtension; 70 } 71 getSectionNumber()72 public int getSectionNumber() { 73 return mSectionNumber; 74 } 75 76 // This is for indicating that the section sent is applicable. 77 // We only consider a situation where currentNextIndicator is expected to have a true value. 78 // So, we are not going to compare this variable in hashCode() and equals() methods. getCurrentNextIndicator()79 public boolean getCurrentNextIndicator() { 80 return mCurrentNextIndicator; 81 } 82 83 @Override hashCode()84 public int hashCode() { 85 int result = 17; 86 result = 31 * result + mTableId; 87 result = 31 * result + mTableIdExtension; 88 result = 31 * result + mSectionNumber; 89 return result; 90 } 91 92 @Override equals(Object obj)93 public boolean equals(Object obj) { 94 if (obj instanceof PsipSection) { 95 PsipSection another = (PsipSection) obj; 96 return mTableId == another.getTableId() 97 && mTableIdExtension == another.getTableIdExtension() 98 && mSectionNumber == another.getSectionNumber(); 99 } 100 return false; 101 } 102 } 103 104 /** {@link TvTracksInterface} for serving the audio and caption tracks. */ 105 public interface TvTracksInterface { 106 /** Set the flag that tells the caption tracks have been found in this section container. */ setHasCaptionTrack()107 void setHasCaptionTrack(); 108 109 /** 110 * Returns whether or not the caption tracks have been found in this section container. If 111 * true, zero caption track will be interpreted as a clearance of the caption tracks. 112 */ hasCaptionTrack()113 boolean hasCaptionTrack(); 114 115 /** Returns the audio tracks received. */ getAudioTracks()116 List<AtscAudioTrack> getAudioTracks(); 117 118 /** Returns the caption tracks received. */ getCaptionTracks()119 List<AtscCaptionTrack> getCaptionTracks(); 120 } 121 122 public static class MgtItem { 123 public static final int TABLE_TYPE_EIT_RANGE_START = 0x0100; 124 public static final int TABLE_TYPE_EIT_RANGE_END = 0x017f; 125 public static final int TABLE_TYPE_CHANNEL_ETT = 0x0004; 126 public static final int TABLE_TYPE_ETT_RANGE_START = 0x0200; 127 public static final int TABLE_TYPE_ETT_RANGE_END = 0x027f; 128 129 private final int mTableType; 130 private final int mTableTypePid; 131 MgtItem(int tableType, int tableTypePid)132 public MgtItem(int tableType, int tableTypePid) { 133 mTableType = tableType; 134 mTableTypePid = tableTypePid; 135 } 136 getTableType()137 public int getTableType() { 138 return mTableType; 139 } 140 getTableTypePid()141 public int getTableTypePid() { 142 return mTableTypePid; 143 } 144 } 145 146 public static class VctItem { 147 private final String mShortName; 148 private final String mLongName; 149 private final int mServiceType; 150 private final int mChannelTsid; 151 private final int mProgramNumber; 152 private final int mMajorChannelNumber; 153 private final int mMinorChannelNumber; 154 private final int mSourceId; 155 private String mDescription; 156 VctItem( String shortName, String longName, int serviceType, int channelTsid, int programNumber, int majorChannelNumber, int minorChannelNumber, int sourceId)157 public VctItem( 158 String shortName, 159 String longName, 160 int serviceType, 161 int channelTsid, 162 int programNumber, 163 int majorChannelNumber, 164 int minorChannelNumber, 165 int sourceId) { 166 mShortName = shortName; 167 mLongName = longName; 168 mServiceType = serviceType; 169 mChannelTsid = channelTsid; 170 mProgramNumber = programNumber; 171 mMajorChannelNumber = majorChannelNumber; 172 mMinorChannelNumber = minorChannelNumber; 173 mSourceId = sourceId; 174 } 175 getShortName()176 public String getShortName() { 177 return mShortName; 178 } 179 getLongName()180 public String getLongName() { 181 return mLongName; 182 } 183 getServiceType()184 public int getServiceType() { 185 return mServiceType; 186 } 187 getChannelTsid()188 public int getChannelTsid() { 189 return mChannelTsid; 190 } 191 getProgramNumber()192 public int getProgramNumber() { 193 return mProgramNumber; 194 } 195 getMajorChannelNumber()196 public int getMajorChannelNumber() { 197 return mMajorChannelNumber; 198 } 199 getMinorChannelNumber()200 public int getMinorChannelNumber() { 201 return mMinorChannelNumber; 202 } 203 getSourceId()204 public int getSourceId() { 205 return mSourceId; 206 } 207 208 @Override toString()209 public String toString() { 210 return String.format( 211 Locale.US, 212 "ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x " 213 + "ProgramNumber:%d %d-%d SourceId: %x", 214 mShortName, 215 mLongName, 216 mServiceType, 217 mChannelTsid, 218 mProgramNumber, 219 mMajorChannelNumber, 220 mMinorChannelNumber, 221 mSourceId); 222 } 223 setDescription(String description)224 public void setDescription(String description) { 225 mDescription = description; 226 } 227 getDescription()228 public String getDescription() { 229 return mDescription; 230 } 231 } 232 233 public static class SdtItem { 234 private final String mServiceName; 235 private final String mServiceProviderName; 236 private final int mServiceType; 237 private final int mServiceId; 238 private final int mOriginalNetWorkId; 239 SdtItem( String serviceName, String serviceProviderName, int serviceType, int serviceId, int originalNetWorkId)240 public SdtItem( 241 String serviceName, 242 String serviceProviderName, 243 int serviceType, 244 int serviceId, 245 int originalNetWorkId) { 246 mServiceName = serviceName; 247 mServiceProviderName = serviceProviderName; 248 mServiceType = serviceType; 249 mServiceId = serviceId; 250 mOriginalNetWorkId = originalNetWorkId; 251 } 252 getServiceName()253 public String getServiceName() { 254 return mServiceName; 255 } 256 getServiceProviderName()257 public String getServiceProviderName() { 258 return mServiceProviderName; 259 } 260 getServiceType()261 public int getServiceType() { 262 return mServiceType; 263 } 264 getServiceId()265 public int getServiceId() { 266 return mServiceId; 267 } 268 getOriginalNetworkId()269 public int getOriginalNetworkId() { 270 return mOriginalNetWorkId; 271 } 272 273 @Override toString()274 public String toString() { 275 return String.format( 276 "ServiceName: %s ServiceProviderName:%s ServiceType:%d " 277 + "OriginalNetworkId:%d", 278 mServiceName, mServiceProviderName, mServiceType, mOriginalNetWorkId); 279 } 280 } 281 282 /** A base class for descriptors of Ts packets. */ 283 public abstract static class TsDescriptor { getTag()284 public abstract int getTag(); 285 } 286 287 public static class ContentAdvisoryDescriptor extends TsDescriptor { 288 private final List<RatingRegion> mRatingRegions; 289 ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions)290 public ContentAdvisoryDescriptor(List<RatingRegion> ratingRegions) { 291 mRatingRegions = ratingRegions; 292 } 293 294 @Override getTag()295 public int getTag() { 296 return SectionParser.DESCRIPTOR_TAG_CONTENT_ADVISORY; 297 } 298 getRatingRegions()299 public List<RatingRegion> getRatingRegions() { 300 return mRatingRegions; 301 } 302 } 303 304 public static class CaptionServiceDescriptor extends TsDescriptor { 305 private final List<AtscCaptionTrack> mCaptionTracks; 306 CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks)307 public CaptionServiceDescriptor(List<AtscCaptionTrack> captionTracks) { 308 mCaptionTracks = captionTracks; 309 } 310 311 @Override getTag()312 public int getTag() { 313 return SectionParser.DESCRIPTOR_TAG_CAPTION_SERVICE; 314 } 315 getCaptionTracks()316 public List<AtscCaptionTrack> getCaptionTracks() { 317 return mCaptionTracks; 318 } 319 } 320 321 public static class ExtendedChannelNameDescriptor extends TsDescriptor { 322 private final String mLongChannelName; 323 ExtendedChannelNameDescriptor(String longChannelName)324 public ExtendedChannelNameDescriptor(String longChannelName) { 325 mLongChannelName = longChannelName; 326 } 327 328 @Override getTag()329 public int getTag() { 330 return SectionParser.DESCRIPTOR_TAG_EXTENDED_CHANNEL_NAME; 331 } 332 getLongChannelName()333 public String getLongChannelName() { 334 return mLongChannelName; 335 } 336 } 337 338 public static class GenreDescriptor extends TsDescriptor { 339 private final String[] mBroadcastGenres; 340 private final String[] mCanonicalGenres; 341 GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres)342 public GenreDescriptor(String[] broadcastGenres, String[] canonicalGenres) { 343 mBroadcastGenres = broadcastGenres; 344 mCanonicalGenres = canonicalGenres; 345 } 346 347 @Override getTag()348 public int getTag() { 349 return SectionParser.DESCRIPTOR_TAG_GENRE; 350 } 351 getBroadcastGenres()352 public String[] getBroadcastGenres() { 353 return mBroadcastGenres; 354 } 355 getCanonicalGenres()356 public String[] getCanonicalGenres() { 357 return mCanonicalGenres; 358 } 359 } 360 361 public static class Ac3AudioDescriptor extends TsDescriptor { 362 // See A/52 Annex A. Table A4.2 363 private static final byte SAMPLE_RATE_CODE_48000HZ = 0; 364 private static final byte SAMPLE_RATE_CODE_44100HZ = 1; 365 private static final byte SAMPLE_RATE_CODE_32000HZ = 2; 366 367 private final byte mSampleRateCode; 368 private final byte mBsid; 369 private final byte mBitRateCode; 370 private final byte mSurroundMode; 371 private final byte mBsmod; 372 private final int mNumChannels; 373 private final boolean mFullSvc; 374 private final byte mLangCod; 375 private final byte mLangCod2; 376 private final byte mMainId; 377 private final byte mPriority; 378 private final byte mAsvcflags; 379 private final String mText; 380 private final String mLanguage; 381 private final String mLanguage2; 382 Ac3AudioDescriptor( byte sampleRateCode, byte bsid, byte bitRateCode, byte surroundMode, byte bsmod, int numChannels, boolean fullSvc, byte langCod, byte langCod2, byte mainId, byte priority, byte asvcflags, String text, String language, String language2)383 public Ac3AudioDescriptor( 384 byte sampleRateCode, 385 byte bsid, 386 byte bitRateCode, 387 byte surroundMode, 388 byte bsmod, 389 int numChannels, 390 boolean fullSvc, 391 byte langCod, 392 byte langCod2, 393 byte mainId, 394 byte priority, 395 byte asvcflags, 396 String text, 397 String language, 398 String language2) { 399 mSampleRateCode = sampleRateCode; 400 mBsid = bsid; 401 mBitRateCode = bitRateCode; 402 mSurroundMode = surroundMode; 403 mBsmod = bsmod; 404 mNumChannels = numChannels; 405 mFullSvc = fullSvc; 406 mLangCod = langCod; 407 mLangCod2 = langCod2; 408 mMainId = mainId; 409 mPriority = priority; 410 mAsvcflags = asvcflags; 411 mText = text; 412 mLanguage = language; 413 mLanguage2 = language2; 414 } 415 416 @Override getTag()417 public int getTag() { 418 return SectionParser.DESCRIPTOR_TAG_AC3_AUDIO_STREAM; 419 } 420 getSampleRateCode()421 public byte getSampleRateCode() { 422 return mSampleRateCode; 423 } 424 getSampleRate()425 public int getSampleRate() { 426 switch (mSampleRateCode) { 427 case SAMPLE_RATE_CODE_48000HZ: 428 return 48000; 429 case SAMPLE_RATE_CODE_44100HZ: 430 return 44100; 431 case SAMPLE_RATE_CODE_32000HZ: 432 return 32000; 433 default: 434 return 0; 435 } 436 } 437 getBsid()438 public byte getBsid() { 439 return mBsid; 440 } 441 getBitRateCode()442 public byte getBitRateCode() { 443 return mBitRateCode; 444 } 445 getSurroundMode()446 public byte getSurroundMode() { 447 return mSurroundMode; 448 } 449 getBsmod()450 public byte getBsmod() { 451 return mBsmod; 452 } 453 getNumChannels()454 public int getNumChannels() { 455 return mNumChannels; 456 } 457 isFullSvc()458 public boolean isFullSvc() { 459 return mFullSvc; 460 } 461 getLangCod()462 public byte getLangCod() { 463 return mLangCod; 464 } 465 getLangCod2()466 public byte getLangCod2() { 467 return mLangCod2; 468 } 469 getMainId()470 public byte getMainId() { 471 return mMainId; 472 } 473 getPriority()474 public byte getPriority() { 475 return mPriority; 476 } 477 getAsvcflags()478 public byte getAsvcflags() { 479 return mAsvcflags; 480 } 481 getText()482 public String getText() { 483 return mText; 484 } 485 getLanguage()486 public String getLanguage() { 487 return mLanguage; 488 } 489 getLanguage2()490 public String getLanguage2() { 491 return mLanguage2; 492 } 493 494 @Override toString()495 public String toString() { 496 return String.format( 497 Locale.US, 498 "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, " 499 + "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, " 500 + "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s" 501 + ", language2: %s", 502 mSampleRateCode, 503 mBsid, 504 mBitRateCode, 505 mSurroundMode, 506 mBsmod, 507 mNumChannels, 508 mFullSvc, 509 mLangCod, 510 mLangCod2, 511 mMainId, 512 mPriority, 513 mAsvcflags, 514 mText, 515 mLanguage, 516 mLanguage2); 517 } 518 } 519 520 public static class Iso639LanguageDescriptor extends TsDescriptor { 521 private final List<AtscAudioTrack> mAudioTracks; 522 Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks)523 public Iso639LanguageDescriptor(List<AtscAudioTrack> audioTracks) { 524 mAudioTracks = audioTracks; 525 } 526 527 @Override getTag()528 public int getTag() { 529 return SectionParser.DESCRIPTOR_TAG_ISO639LANGUAGE; 530 } 531 getAudioTracks()532 public List<AtscAudioTrack> getAudioTracks() { 533 return mAudioTracks; 534 } 535 536 @Override toString()537 public String toString() { 538 return String.format("%s %s", getClass().getName(), mAudioTracks); 539 } 540 } 541 542 public static class ServiceDescriptor extends TsDescriptor { 543 private final int mServiceType; 544 private final String mServiceProviderName; 545 private final String mServiceName; 546 ServiceDescriptor(int serviceType, String serviceProviderName, String serviceName)547 public ServiceDescriptor(int serviceType, String serviceProviderName, String serviceName) { 548 mServiceType = serviceType; 549 mServiceProviderName = serviceProviderName; 550 mServiceName = serviceName; 551 } 552 553 @Override getTag()554 public int getTag() { 555 return SectionParser.DVB_DESCRIPTOR_TAG_SERVICE; 556 } 557 getServiceType()558 public int getServiceType() { 559 return mServiceType; 560 } 561 getServiceProviderName()562 public String getServiceProviderName() { 563 return mServiceProviderName; 564 } 565 getServiceName()566 public String getServiceName() { 567 return mServiceName; 568 } 569 570 @Override toString()571 public String toString() { 572 return String.format( 573 "Service descriptor, service type: %d, " 574 + "service provider name: %s, " 575 + "service name: %s", 576 mServiceType, mServiceProviderName, mServiceName); 577 } 578 } 579 580 public static class ShortEventDescriptor extends TsDescriptor { 581 private final String mLanguage; 582 private final String mEventName; 583 private final String mText; 584 ShortEventDescriptor(String language, String eventName, String text)585 public ShortEventDescriptor(String language, String eventName, String text) { 586 mLanguage = language; 587 mEventName = eventName; 588 mText = text; 589 } 590 getEventName()591 public String getEventName() { 592 return mEventName; 593 } 594 595 @Override getTag()596 public int getTag() { 597 return SectionParser.DVB_DESCRIPTOR_TAG_SHORT_EVENT; 598 } 599 600 @Override toString()601 public String toString() { 602 return String.format( 603 "ShortEvent Descriptor, language:%s, event name: %s, " + "text:%s", 604 mLanguage, mEventName, mText); 605 } 606 } 607 608 public static class ParentalRatingDescriptor extends TsDescriptor { 609 private final HashMap<String, Integer> mRatings; 610 ParentalRatingDescriptor(HashMap<String, Integer> ratings)611 public ParentalRatingDescriptor(HashMap<String, Integer> ratings) { 612 mRatings = ratings; 613 } 614 615 @Override getTag()616 public int getTag() { 617 return SectionParser.DVB_DESCRIPTOR_TAG_PARENTAL_RATING; 618 } 619 getRatings()620 public HashMap<String, Integer> getRatings() { 621 return mRatings; 622 } 623 624 @Override toString()625 public String toString() { 626 return String.format("Parental rating descriptor, ratings:" + mRatings); 627 } 628 } 629 630 public static class RatingRegion { 631 private final int mName; 632 private final String mDescription; 633 private final List<RegionalRating> mRegionalRatings; 634 RatingRegion(int name, String description, List<RegionalRating> regionalRatings)635 public RatingRegion(int name, String description, List<RegionalRating> regionalRatings) { 636 mName = name; 637 mDescription = description; 638 mRegionalRatings = regionalRatings; 639 } 640 getName()641 public int getName() { 642 return mName; 643 } 644 getDescription()645 public String getDescription() { 646 return mDescription; 647 } 648 getRegionalRatings()649 public List<RegionalRating> getRegionalRatings() { 650 return mRegionalRatings; 651 } 652 } 653 654 public static class RegionalRating { 655 private final int mDimension; 656 private final int mRating; 657 RegionalRating(int dimension, int rating)658 public RegionalRating(int dimension, int rating) { 659 mDimension = dimension; 660 mRating = rating; 661 } 662 getDimension()663 public int getDimension() { 664 return mDimension; 665 } 666 getRating()667 public int getRating() { 668 return mRating; 669 } 670 } 671 672 public static class EitItem implements Comparable<EitItem>, TvTracksInterface { 673 public static final long INVALID_PROGRAM_ID = -1; 674 675 // A program id is a primary key of TvContract.Programs table. So it must be positive. 676 private final long mProgramId; 677 private final int mEventId; 678 private final String mTitleText; 679 private String mDescription; 680 private final long mStartTime; 681 private final int mLengthInSecond; 682 private final String mContentRating; 683 private final List<AtscAudioTrack> mAudioTracks; 684 private final List<AtscCaptionTrack> mCaptionTracks; 685 private boolean mHasCaptionTrack; 686 private final String mBroadcastGenre; 687 private final String mCanonicalGenre; 688 EitItem( long programId, int eventId, String titleText, long startTime, int lengthInSecond, String contentRating, List<AtscAudioTrack> audioTracks, List<AtscCaptionTrack> captionTracks, String broadcastGenre, String canonicalGenre, String description)689 public EitItem( 690 long programId, 691 int eventId, 692 String titleText, 693 long startTime, 694 int lengthInSecond, 695 String contentRating, 696 List<AtscAudioTrack> audioTracks, 697 List<AtscCaptionTrack> captionTracks, 698 String broadcastGenre, 699 String canonicalGenre, 700 String description) { 701 mProgramId = programId; 702 mEventId = eventId; 703 mTitleText = titleText; 704 mStartTime = startTime; 705 mLengthInSecond = lengthInSecond; 706 mContentRating = contentRating; 707 mAudioTracks = audioTracks; 708 mCaptionTracks = captionTracks; 709 mBroadcastGenre = broadcastGenre; 710 mCanonicalGenre = canonicalGenre; 711 mDescription = description; 712 } 713 getProgramId()714 public long getProgramId() { 715 return mProgramId; 716 } 717 getEventId()718 public int getEventId() { 719 return mEventId; 720 } 721 getTitleText()722 public String getTitleText() { 723 return mTitleText; 724 } 725 setDescription(String description)726 public void setDescription(String description) { 727 mDescription = description; 728 } 729 getDescription()730 public String getDescription() { 731 return mDescription; 732 } 733 getStartTime()734 public long getStartTime() { 735 return mStartTime; 736 } 737 getLengthInSecond()738 public int getLengthInSecond() { 739 return mLengthInSecond; 740 } 741 getStartTimeUtcMillis()742 public long getStartTimeUtcMillis() { 743 return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime) * DateUtils.SECOND_IN_MILLIS; 744 } 745 getEndTimeUtcMillis()746 public long getEndTimeUtcMillis() { 747 return ConvertUtils.convertGPSTimeToUnixEpoch(mStartTime + mLengthInSecond) 748 * DateUtils.SECOND_IN_MILLIS; 749 } 750 getContentRating()751 public String getContentRating() { 752 return mContentRating; 753 } 754 755 @Override getAudioTracks()756 public List<AtscAudioTrack> getAudioTracks() { 757 return mAudioTracks; 758 } 759 760 @Override getCaptionTracks()761 public List<AtscCaptionTrack> getCaptionTracks() { 762 return mCaptionTracks; 763 } 764 getBroadcastGenre()765 public String getBroadcastGenre() { 766 return mBroadcastGenre; 767 } 768 getCanonicalGenre()769 public String getCanonicalGenre() { 770 return mCanonicalGenre; 771 } 772 773 @Override setHasCaptionTrack()774 public void setHasCaptionTrack() { 775 mHasCaptionTrack = true; 776 } 777 778 @Override hasCaptionTrack()779 public boolean hasCaptionTrack() { 780 return mHasCaptionTrack; 781 } 782 783 @Override compareTo(@onNull EitItem item)784 public int compareTo(@NonNull EitItem item) { 785 // The list of caption tracks and the program ids are not compared in here because the 786 // channels in TIF have the concept of the caption and audio tracks while the programs 787 // do not and the programs in TIF only have a program id since they are the rows of 788 // Content Provider. 789 int ret = mEventId - item.getEventId(); 790 if (ret != 0) { 791 return ret; 792 } 793 ret = StringUtils.compare(mTitleText, item.getTitleText()); 794 if (ret != 0) { 795 return ret; 796 } 797 if (mStartTime > item.getStartTime()) { 798 return 1; 799 } else if (mStartTime < item.getStartTime()) { 800 return -1; 801 } 802 if (mLengthInSecond > item.getLengthInSecond()) { 803 return 1; 804 } else if (mLengthInSecond < item.getLengthInSecond()) { 805 return -1; 806 } 807 808 // Compares content ratings 809 ret = StringUtils.compare(mContentRating, item.getContentRating()); 810 if (ret != 0) { 811 return ret; 812 } 813 814 // Compares broadcast genres 815 ret = StringUtils.compare(mBroadcastGenre, item.getBroadcastGenre()); 816 if (ret != 0) { 817 return ret; 818 } 819 // Compares canonical genres 820 ret = StringUtils.compare(mCanonicalGenre, item.getCanonicalGenre()); 821 if (ret != 0) { 822 return ret; 823 } 824 825 // Compares descriptions 826 return StringUtils.compare(mDescription, item.getDescription()); 827 } 828 getAudioLanguage()829 public String getAudioLanguage() { 830 if (mAudioTracks == null) { 831 return ""; 832 } 833 ArrayList<String> languages = new ArrayList<>(); 834 for (AtscAudioTrack audioTrack : mAudioTracks) { 835 languages.add(audioTrack.language); 836 } 837 return TextUtils.join(",", languages); 838 } 839 840 @Override toString()841 public String toString() { 842 return String.format( 843 Locale.US, 844 "EitItem programId: %d, eventId: %d, title: %s, startTime: %10d, " 845 + "length: %6d, rating: %s, audio tracks: %d, caption tracks: %d, " 846 + "genres (broadcast: %s, canonical: %s), description: %s", 847 mProgramId, 848 mEventId, 849 mTitleText, 850 mStartTime, 851 mLengthInSecond, 852 mContentRating, 853 mAudioTracks != null ? mAudioTracks.size() : 0, 854 mCaptionTracks != null ? mCaptionTracks.size() : 0, 855 mBroadcastGenre, 856 mCanonicalGenre, 857 mDescription); 858 } 859 } 860 861 public static class EttItem { 862 public final int eventId; 863 public final String text; 864 EttItem(int eventId, String text)865 public EttItem(int eventId, String text) { 866 this.eventId = eventId; 867 this.text = text; 868 } 869 } 870 } 871