• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.common.recording;
18 
19 import static android.media.tv.TvContract.RecordedPrograms;
20 
21 import android.content.ContentUris;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.database.Cursor;
25 import android.media.tv.TvContract;
26 import android.net.Uri;
27 import android.support.annotation.Nullable;
28 import android.text.TextUtils;
29 
30 import com.android.tv.common.R;
31 
32 import java.util.Arrays;
33 import java.util.Comparator;
34 import java.util.Objects;
35 
36 /**
37  * Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}.
38  */
39 public class RecordedProgram {
40     public static final int ID_NOT_SET = -1;
41 
42     public final static String[] PROJECTION = {
43             // These are in exactly the order listed in RecordedPrograms
44             RecordedPrograms._ID,
45             RecordedPrograms.COLUMN_INPUT_ID,
46             RecordedPrograms.COLUMN_CHANNEL_ID,
47             RecordedPrograms.COLUMN_TITLE,
48             RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER,
49             RecordedPrograms.COLUMN_SEASON_TITLE,
50             RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER,
51             RecordedPrograms.COLUMN_EPISODE_TITLE,
52             RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS,
53             RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS,
54             RecordedPrograms.COLUMN_BROADCAST_GENRE,
55             RecordedPrograms.COLUMN_CANONICAL_GENRE,
56             RecordedPrograms.COLUMN_SHORT_DESCRIPTION,
57             RecordedPrograms.COLUMN_LONG_DESCRIPTION,
58             RecordedPrograms.COLUMN_VIDEO_WIDTH,
59             RecordedPrograms.COLUMN_VIDEO_HEIGHT,
60             RecordedPrograms.COLUMN_AUDIO_LANGUAGE,
61             RecordedPrograms.COLUMN_CONTENT_RATING,
62             RecordedPrograms.COLUMN_POSTER_ART_URI,
63             RecordedPrograms.COLUMN_THUMBNAIL_URI,
64             RecordedPrograms.COLUMN_SEARCHABLE,
65             RecordedPrograms.COLUMN_RECORDING_DATA_URI,
66             RecordedPrograms.COLUMN_RECORDING_DATA_BYTES,
67             RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS,
68             RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS,
69             RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
70             RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
71             RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
72             RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3,
73             RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4,
74             RecordedPrograms.COLUMN_VERSION_NUMBER,
75     };
76 
fromCursor(Cursor cursor)77     public static final RecordedProgram fromCursor(Cursor cursor) {
78         int index = 0;
79         return builder()
80                 .setId(cursor.getLong(index++))
81                 .setInputId(cursor.getString(index++))
82                 .setChannelId(cursor.getLong(index++))
83                 .setTitle(cursor.getString(index++))
84                 .setSeasonNumber(cursor.getString(index++))
85                 .setSeasonTitle(cursor.getString(index++))
86                 .setEpisodeNumber(cursor.getString(index++))
87                 .setEpisodeTitle(cursor.getString(index++))
88                 .setStartTimeUtcMillis(cursor.getLong(index++))
89                 .setEndTimeUtcMillis(cursor.getLong(index++))
90                 .setBroadcastGenres(cursor.getString(index++))
91                 .setCanonicalGenres(cursor.getString(index++))
92                 .setShortDescription(cursor.getString(index++))
93                 .setLongDescription(cursor.getString(index++))
94                 .setVideoWidth(cursor.getInt(index++))
95                 .setVideoHeight(cursor.getInt(index++))
96                 .setAudioLanguage(cursor.getString(index++))
97                 .setContentRating(cursor.getString(index++))
98                 .setPosterArt(cursor.getString(index++))
99                 .setThumbnail(cursor.getString(index++))
100                 .setSearchable(cursor.getInt(index++) == 1)
101                 .setDataUri(cursor.getString(index++))
102                 .setDataBytes(cursor.getLong(index++))
103                 .setDurationMillis(cursor.getLong(index++))
104                 .setExpireTimeUtcMillis(cursor.getLong(index++))
105                 .setInternalProviderData(cursor.getBlob(index++))
106                 .setInternalProviderFlag1(cursor.getInt(index++))
107                 .setInternalProviderFlag2(cursor.getInt(index++))
108                 .setInternalProviderFlag3(cursor.getInt(index++))
109                 .setInternalProviderFlag4(cursor.getInt(index++))
110                 .setVersionNumber(cursor.getInt(index++))
111                 .build();
112     }
113 
toValues(RecordedProgram recordedProgram)114     public static ContentValues toValues(RecordedProgram recordedProgram) {
115         ContentValues values = new ContentValues();
116         if (recordedProgram.mId != ID_NOT_SET) {
117             values.put(RecordedPrograms._ID, recordedProgram.mId);
118         }
119         values.put(RecordedPrograms.COLUMN_INPUT_ID, recordedProgram.mInputId);
120         values.put(RecordedPrograms.COLUMN_CHANNEL_ID, recordedProgram.mChannelId);
121         values.put(RecordedPrograms.COLUMN_TITLE, recordedProgram.mTitle);
122         values.put(RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, recordedProgram.mSeasonNumber);
123         values.put(RecordedPrograms.COLUMN_SEASON_TITLE, recordedProgram.mSeasonTitle);
124         values.put(RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, recordedProgram.mEpisodeNumber);
125         values.put(RecordedPrograms.COLUMN_EPISODE_TITLE, recordedProgram.mTitle);
126         values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS,
127                 recordedProgram.mStartTimeUtcMillis);
128         values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, recordedProgram.mEndTimeUtcMillis);
129         values.put(RecordedPrograms.COLUMN_BROADCAST_GENRE,
130                 safeEncode(recordedProgram.mBroadcastGenres));
131         values.put(RecordedPrograms.COLUMN_CANONICAL_GENRE,
132                 safeEncode(recordedProgram.mCanonicalGenres));
133         values.put(RecordedPrograms.COLUMN_SHORT_DESCRIPTION, recordedProgram.mShortDescription);
134         values.put(RecordedPrograms.COLUMN_LONG_DESCRIPTION, recordedProgram.mLongDescription);
135         if (recordedProgram.mVideoWidth == 0) {
136             values.putNull(RecordedPrograms.COLUMN_VIDEO_WIDTH);
137         } else {
138             values.put(RecordedPrograms.COLUMN_VIDEO_WIDTH, recordedProgram.mVideoWidth);
139         }
140         if (recordedProgram.mVideoHeight == 0) {
141             values.putNull(RecordedPrograms.COLUMN_VIDEO_HEIGHT);
142         } else {
143             values.put(RecordedPrograms.COLUMN_VIDEO_HEIGHT, recordedProgram.mVideoHeight);
144         }
145         values.put(RecordedPrograms.COLUMN_AUDIO_LANGUAGE, recordedProgram.mAudioLanguage);
146         values.put(RecordedPrograms.COLUMN_CONTENT_RATING, recordedProgram.mContentRating);
147         values.put(RecordedPrograms.COLUMN_POSTER_ART_URI,
148                 safeToString(recordedProgram.mPosterArt));
149         values.put(RecordedPrograms.COLUMN_THUMBNAIL_URI, safeToString(recordedProgram.mThumbnail));
150         values.put(RecordedPrograms.COLUMN_SEARCHABLE, recordedProgram.mSearchable ? 1 : 0);
151         values.put(RecordedPrograms.COLUMN_RECORDING_DATA_URI,
152                 safeToString(recordedProgram.mDataUri));
153         values.put(RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, recordedProgram.mDataBytes);
154         values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS,
155                 recordedProgram.mDurationMillis);
156         values.put(RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS,
157                 recordedProgram.mExpireTimeUtcMillis);
158         values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
159                 recordedProgram.mInternalProviderData);
160         values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
161                 recordedProgram.mInternalProviderFlag1);
162         values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
163                 recordedProgram.mInternalProviderFlag2);
164         values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3,
165                 recordedProgram.mInternalProviderFlag3);
166         values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4,
167                 recordedProgram.mInternalProviderFlag4);
168         values.put(RecordedPrograms.COLUMN_VERSION_NUMBER, recordedProgram.mVersionNumber);
169         return values;
170     }
171 
172     public static class Builder{
173         private long mId = ID_NOT_SET;
174         private String mInputId;
175         private long mChannelId;
176         private String mTitle;
177         private String mSeasonNumber;
178         private String mSeasonTitle;
179         private String mEpisodeNumber;
180         private String mEpisodeTitle;
181         private long mStartTimeUtcMillis;
182         private long mEndTimeUtcMillis;
183         private String[] mBroadcastGenres;
184         private String[] mCanonicalGenres;
185         private String mShortDescription;
186         private String mLongDescription;
187         private int mVideoWidth;
188         private int mVideoHeight;
189         private String mAudioLanguage;
190         private String mContentRating;
191         private Uri mPosterArt;
192         private Uri mThumbnail;
193         private boolean mSearchable = true;
194         private Uri mDataUri;
195         private long mDataBytes;
196         private long mDurationMillis;
197         private long mExpireTimeUtcMillis;
198         private byte[] mInternalProviderData;
199         private int mInternalProviderFlag1;
200         private int mInternalProviderFlag2;
201         private int mInternalProviderFlag3;
202         private int mInternalProviderFlag4;
203         private int mVersionNumber;
204 
setId(long id)205         public Builder setId(long id) {
206             mId = id;
207             return this;
208         }
209 
setInputId(String inputId)210         public Builder setInputId(String inputId) {
211             mInputId = inputId;
212             return this;
213         }
214 
setChannelId(long channelId)215         public Builder setChannelId(long channelId) {
216             mChannelId = channelId;
217             return this;
218         }
219 
setTitle(String title)220         public Builder setTitle(String title) {
221             mTitle = title;
222             return this;
223         }
224 
setSeasonNumber(String seasonNumber)225         public Builder setSeasonNumber(String seasonNumber) {
226             mSeasonNumber = seasonNumber;
227             return this;
228         }
229 
setSeasonTitle(String seasonTitle)230         public Builder setSeasonTitle(String seasonTitle) {
231             mSeasonTitle = seasonTitle;
232             return this;
233         }
234 
setEpisodeNumber(String episodeNumber)235         public Builder setEpisodeNumber(String episodeNumber) {
236             mEpisodeNumber = episodeNumber;
237             return this;
238         }
239 
setEpisodeTitle(String episodeTitle)240         public Builder setEpisodeTitle(String episodeTitle) {
241             mEpisodeTitle = episodeTitle;
242             return this;
243         }
244 
setStartTimeUtcMillis(long startTimeUtcMillis)245         public Builder setStartTimeUtcMillis(long startTimeUtcMillis) {
246             mStartTimeUtcMillis = startTimeUtcMillis;
247             return this;
248         }
249 
setEndTimeUtcMillis(long endTimeUtcMillis)250         public Builder setEndTimeUtcMillis(long endTimeUtcMillis) {
251             mEndTimeUtcMillis = endTimeUtcMillis;
252             return this;
253         }
254 
setBroadcastGenres(String broadcastGenres)255         public Builder setBroadcastGenres(String broadcastGenres) {
256             if (TextUtils.isEmpty(broadcastGenres)) {
257                 mBroadcastGenres = null;
258                 return this;
259             }
260             return setBroadcastGenres(TvContract.Programs.Genres.decode(broadcastGenres));
261         }
262 
setBroadcastGenres(String[] broadcastGenres)263         private Builder setBroadcastGenres(String[] broadcastGenres) {
264             mBroadcastGenres = broadcastGenres;
265             return this;
266         }
267 
setCanonicalGenres(String canonicalGenres)268         public Builder setCanonicalGenres(String canonicalGenres) {
269             if (TextUtils.isEmpty(canonicalGenres)) {
270                 mCanonicalGenres = null;
271                 return this;
272             }
273             return setCanonicalGenres(TvContract.Programs.Genres.decode(canonicalGenres));
274         }
275 
setCanonicalGenres(String[] canonicalGenres)276         private Builder setCanonicalGenres(String[] canonicalGenres) {
277             mCanonicalGenres = canonicalGenres;
278             return this;
279         }
280 
setShortDescription(String shortDescription)281         public Builder setShortDescription(String shortDescription) {
282             mShortDescription = shortDescription;
283             return this;
284         }
285 
setLongDescription(String longDescription)286         public Builder setLongDescription(String longDescription) {
287             mLongDescription = longDescription;
288             return this;
289         }
290 
setVideoWidth(int videoWidth)291         public Builder setVideoWidth(int videoWidth) {
292             mVideoWidth = videoWidth;
293             return this;
294         }
295 
setVideoHeight(int videoHeight)296         public Builder setVideoHeight(int videoHeight) {
297             mVideoHeight = videoHeight;
298             return this;
299         }
300 
setAudioLanguage(String audioLanguage)301         public Builder setAudioLanguage(String audioLanguage) {
302             mAudioLanguage = audioLanguage;
303             return this;
304         }
305 
setContentRating(String contentRating)306         public Builder setContentRating(String contentRating) {
307             mContentRating = contentRating;
308             return this;
309         }
310 
toUri(String uriString)311         private Uri toUri(String uriString) {
312             try {
313                 return uriString == null ? null : Uri.parse(uriString);
314             } catch (Exception e) {
315                 return null;
316             }
317         }
318 
setPosterArt(String posterArtUri)319         public Builder setPosterArt(String posterArtUri) {
320             return setPosterArt(toUri(posterArtUri));
321         }
322 
setPosterArt(Uri posterArt)323         public Builder setPosterArt(Uri posterArt) {
324             mPosterArt = posterArt;
325             return this;
326         }
327 
setThumbnail(String thumbnailUri)328         public Builder setThumbnail(String thumbnailUri) {
329             return setThumbnail(toUri(thumbnailUri));
330         }
331 
setThumbnail(Uri thumbnail)332         public Builder setThumbnail(Uri thumbnail) {
333             mThumbnail = thumbnail;
334             return this;
335         }
336 
setSearchable(boolean searchable)337         public Builder setSearchable(boolean searchable) {
338             mSearchable = searchable;
339             return this;
340         }
341 
setDataUri(String dataUri)342         public Builder setDataUri(String dataUri) {
343             return setDataUri(toUri(dataUri));
344         }
345 
setDataUri(Uri dataUri)346         public Builder setDataUri(Uri dataUri) {
347             mDataUri = dataUri;
348             return this;
349         }
350 
setDataBytes(long dataBytes)351         public Builder setDataBytes(long dataBytes) {
352             mDataBytes = dataBytes;
353             return this;
354         }
355 
setDurationMillis(long durationMillis)356         public Builder setDurationMillis(long durationMillis) {
357             mDurationMillis = durationMillis;
358             return this;
359         }
360 
setExpireTimeUtcMillis(long expireTimeUtcMillis)361         public Builder setExpireTimeUtcMillis(long expireTimeUtcMillis) {
362             mExpireTimeUtcMillis = expireTimeUtcMillis;
363             return this;
364         }
365 
setInternalProviderData(byte[] internalProviderData)366         public Builder setInternalProviderData(byte[] internalProviderData) {
367             mInternalProviderData = internalProviderData;
368             return this;
369         }
370 
setInternalProviderFlag1(int internalProviderFlag1)371         public Builder setInternalProviderFlag1(int internalProviderFlag1) {
372             mInternalProviderFlag1 = internalProviderFlag1;
373             return this;
374         }
375 
setInternalProviderFlag2(int internalProviderFlag2)376         public Builder setInternalProviderFlag2(int internalProviderFlag2) {
377             mInternalProviderFlag2 = internalProviderFlag2;
378             return this;
379         }
380 
setInternalProviderFlag3(int internalProviderFlag3)381         public Builder setInternalProviderFlag3(int internalProviderFlag3) {
382             mInternalProviderFlag3 = internalProviderFlag3;
383             return this;
384         }
385 
setInternalProviderFlag4(int internalProviderFlag4)386         public Builder setInternalProviderFlag4(int internalProviderFlag4) {
387             mInternalProviderFlag4 = internalProviderFlag4;
388             return this;
389         }
390 
setVersionNumber(int versionNumber)391         public Builder setVersionNumber(int versionNumber) {
392             mVersionNumber = versionNumber;
393             return this;
394         }
395 
build()396         public RecordedProgram build() {
397             return new RecordedProgram(mId, mInputId, mChannelId, mTitle, mSeasonNumber,
398                     mSeasonTitle, mEpisodeNumber, mEpisodeTitle, mStartTimeUtcMillis,
399                     mEndTimeUtcMillis, mBroadcastGenres, mCanonicalGenres, mShortDescription,
400                     mLongDescription, mVideoWidth, mVideoHeight, mAudioLanguage, mContentRating,
401                     mPosterArt, mThumbnail, mSearchable, mDataUri, mDataBytes, mDurationMillis,
402                     mExpireTimeUtcMillis, mInternalProviderData, mInternalProviderFlag1,
403                     mInternalProviderFlag2, mInternalProviderFlag3, mInternalProviderFlag4,
404                     mVersionNumber);
405         }
406     }
407 
builder()408     public static Builder builder() { return new Builder(); }
409 
buildFrom(RecordedProgram orig)410     public static Builder buildFrom(RecordedProgram orig) {
411         return builder()
412                 .setId(orig.getId())
413                 .setInputId(orig.getInputId())
414                 .setChannelId(orig.getChannelId())
415                 .setTitle(orig.getTitle())
416                 .setSeasonNumber(orig.getSeasonNumber())
417                 .setSeasonTitle(orig.getSeasonTitle())
418                 .setEpisodeNumber(orig.getEpisodeNumber())
419                 .setEpisodeTitle(orig.getEpisodeTitle())
420                 .setStartTimeUtcMillis(orig.getStartTimeUtcMillis())
421                 .setEndTimeUtcMillis(orig.getEndTimeUtcMillis())
422                 .setBroadcastGenres(orig.getBroadcastGenres())
423                 .setCanonicalGenres(orig.getCanonicalGenres())
424                 .setShortDescription(orig.getShortDescription())
425                 .setLongDescription(orig.getLongDescription())
426                 .setVideoWidth(orig.getVideoWidth())
427                 .setVideoHeight(orig.getVideoHeight())
428                 .setAudioLanguage(orig.getAudioLanguage())
429                 .setContentRating(orig.getContentRating())
430                 .setPosterArt(orig.getPosterArt())
431                 .setThumbnail(orig.getThumbnail())
432                 .setSearchable(orig.isSearchable())
433                 .setInternalProviderData(orig.getInternalProviderData())
434                 .setInternalProviderFlag1(orig.getInternalProviderFlag1())
435                 .setInternalProviderFlag2(orig.getInternalProviderFlag2())
436                 .setInternalProviderFlag3(orig.getInternalProviderFlag3())
437                 .setInternalProviderFlag4(orig.getInternalProviderFlag4())
438                 .setVersionNumber(orig.getVersionNumber());
439     }
440 
441     public static final Comparator<RecordedProgram> START_TIME_THEN_ID_COMPARATOR
442             = new Comparator<RecordedProgram>() {
443         @Override
444         public int compare(RecordedProgram lhs, RecordedProgram rhs) {
445             int res = Long.compare(lhs.getStartTimeUtcMillis(), rhs.getStartTimeUtcMillis());
446             if (res != 0) {
447                 return res;
448             }
449             return Long.compare(lhs.mId, rhs.mId);
450         }
451     };
452 
453     private final long mId;
454     private final String mInputId;
455     private final long mChannelId;
456     private final String mTitle;
457     private final String mSeasonNumber;
458     private final String mSeasonTitle;
459     private final String mEpisodeNumber;
460     private final String mEpisodeTitle;
461     private final long mStartTimeUtcMillis;
462     private final long mEndTimeUtcMillis;
463     private final String[] mBroadcastGenres;
464     private final String[] mCanonicalGenres;
465     private final String mShortDescription;
466     private final String mLongDescription;
467     private final int mVideoWidth;
468     private final int mVideoHeight;
469     private final String mAudioLanguage;
470     private final String mContentRating;
471     private final Uri mPosterArt;
472     private final Uri mThumbnail;
473     private final boolean mSearchable;
474     private final Uri mDataUri;
475     private final long mDataBytes;
476     private final long mDurationMillis;
477     private final long mExpireTimeUtcMillis;
478     private final byte[] mInternalProviderData;
479     private final int mInternalProviderFlag1;
480     private final int mInternalProviderFlag2;
481     private final int mInternalProviderFlag3;
482     private final int mInternalProviderFlag4;
483     private final int mVersionNumber;
484 
RecordedProgram(long id, String inputId, long channelId, String title, String seasonNumber, String seasonTitle, String episodeNumber, String episodeTitle, long startTimeUtcMillis, long endTimeUtcMillis, String[] broadcastGenres, String[] canonicalGenres, String shortDescription, String longDescription, int videoWidth, int videoHeight, String audioLanguage, String contentRating, Uri posterArt, Uri thumbnail, boolean searchable, Uri dataUri, long dataBytes, long durationMillis, long expireTimeUtcMillis, byte[] internalProviderData, int internalProviderFlag1, int internalProviderFlag2, int internalProviderFlag3, int internalProviderFlag4, int versionNumber)485     private RecordedProgram(long id, String inputId, long channelId, String title,
486             String seasonNumber, String seasonTitle, String episodeNumber, String episodeTitle,
487             long startTimeUtcMillis, long endTimeUtcMillis, String[] broadcastGenres,
488             String[] canonicalGenres, String shortDescription, String longDescription,
489             int videoWidth, int videoHeight, String audioLanguage, String contentRating,
490             Uri posterArt, Uri thumbnail, boolean searchable, Uri dataUri, long dataBytes,
491             long durationMillis, long expireTimeUtcMillis, byte[] internalProviderData,
492             int internalProviderFlag1, int internalProviderFlag2, int internalProviderFlag3,
493             int internalProviderFlag4, int versionNumber) {
494         mId = id;
495         mInputId = inputId;
496         mChannelId = channelId;
497         mTitle = title;
498         mSeasonNumber = seasonNumber;
499         mSeasonTitle = seasonTitle;
500         mEpisodeNumber = episodeNumber;
501         mEpisodeTitle = episodeTitle;
502         mStartTimeUtcMillis = startTimeUtcMillis;
503         mEndTimeUtcMillis = endTimeUtcMillis;
504         mBroadcastGenres = broadcastGenres;
505         mCanonicalGenres = canonicalGenres;
506         mShortDescription = shortDescription;
507         mLongDescription = longDescription;
508         mVideoWidth = videoWidth;
509         mVideoHeight = videoHeight;
510 
511         mAudioLanguage = audioLanguage;
512         mContentRating = contentRating;
513         mPosterArt = posterArt;
514         mThumbnail = thumbnail;
515         mSearchable = searchable;
516         mDataUri = dataUri;
517         mDataBytes = dataBytes;
518         mDurationMillis = durationMillis;
519         mExpireTimeUtcMillis = expireTimeUtcMillis;
520         mInternalProviderData = internalProviderData;
521         mInternalProviderFlag1 = internalProviderFlag1;
522         mInternalProviderFlag2 = internalProviderFlag2;
523         mInternalProviderFlag3 = internalProviderFlag3;
524         mInternalProviderFlag4 = internalProviderFlag4;
525         mVersionNumber = versionNumber;
526     }
527 
getAudioLanguage()528     public String getAudioLanguage() {
529         return mAudioLanguage;
530     }
531 
getBroadcastGenres()532     public String[] getBroadcastGenres() {
533         return mBroadcastGenres;
534     }
535 
getCanonicalGenres()536     public String[] getCanonicalGenres() {
537         return mCanonicalGenres;
538     }
539 
getChannelId()540     public long getChannelId() {
541         return mChannelId;
542     }
543 
getContentRating()544     public String getContentRating() {
545         return mContentRating;
546     }
547 
getDataUri()548     public Uri getDataUri() {
549         return mDataUri;
550     }
551 
getDataBytes()552     public long getDataBytes() {
553         return mDataBytes;
554     }
555 
getDurationMillis()556     public long getDurationMillis() {
557         return mDurationMillis;
558     }
559 
getEndTimeUtcMillis()560     public long getEndTimeUtcMillis() {
561         return mEndTimeUtcMillis;
562     }
563 
getEpisodeNumber()564     public String getEpisodeNumber() {
565         return mEpisodeNumber;
566     }
567 
getEpisodeTitle()568     public String getEpisodeTitle() {
569         return mEpisodeTitle;
570     }
571 
getEpisodeDisplayTitle(Context context)572     public String getEpisodeDisplayTitle(Context context) {
573         if (!TextUtils.isEmpty(mSeasonNumber) && !TextUtils.isEmpty(mEpisodeNumber)
574                 && !TextUtils.isEmpty(mEpisodeTitle)) {
575             return String.format(context.getResources().getString(R.string.episode_format),
576                     mSeasonNumber, mEpisodeNumber, mEpisodeTitle);
577         }
578         return mEpisodeTitle;
579     }
580 
getExpireTimeUtcMillis()581     public long getExpireTimeUtcMillis() {
582         return mExpireTimeUtcMillis;
583     }
584 
getId()585     public long getId() {
586         return mId;
587     }
588 
getInputId()589     public String getInputId() {
590         return mInputId;
591     }
592 
getInternalProviderData()593     public byte[] getInternalProviderData() {
594         return mInternalProviderData;
595     }
596 
getInternalProviderFlag1()597     public int getInternalProviderFlag1() {
598         return mInternalProviderFlag1;
599     }
600 
getInternalProviderFlag2()601     public int getInternalProviderFlag2() {
602         return mInternalProviderFlag2;
603     }
604 
getInternalProviderFlag3()605     public int getInternalProviderFlag3() {
606         return mInternalProviderFlag3;
607     }
608 
getInternalProviderFlag4()609     public int getInternalProviderFlag4() {
610         return mInternalProviderFlag4;
611     }
612 
getLongDescription()613     public String getLongDescription() {
614         return mLongDescription;
615     }
616 
getPosterArt()617     public Uri getPosterArt() {
618         return mPosterArt;
619     }
620 
isSearchable()621     public boolean isSearchable() {
622         return mSearchable;
623     }
624 
getSeasonNumber()625     public String getSeasonNumber() {
626         return mSeasonNumber;
627     }
628 
getSeasonTitle()629     public String getSeasonTitle() {
630         return mSeasonTitle;
631     }
632 
getShortDescription()633     public String getShortDescription() {
634         return mShortDescription;
635     }
636 
getStartTimeUtcMillis()637     public long getStartTimeUtcMillis() {
638         return mStartTimeUtcMillis;
639     }
640 
getThumbnail()641     public Uri getThumbnail() {
642         return mThumbnail;
643     }
644 
getTitle()645     public String getTitle() {
646         return mTitle;
647     }
648 
getUri()649     public Uri getUri() {
650         return ContentUris.withAppendedId(RecordedPrograms.CONTENT_URI, mId);
651     }
652 
getVersionNumber()653     public int getVersionNumber() {
654         return mVersionNumber;
655     }
656 
getVideoHeight()657     public int getVideoHeight() {
658         return mVideoHeight;
659     }
660 
getVideoWidth()661     public int getVideoWidth() {
662         return mVideoWidth;
663     }
664 
665     /**
666      * Compares everything except {@link #getInternalProviderData()}
667      */
668     @Override
equals(Object o)669     public boolean equals(Object o) {
670         if (this == o) return true;
671         if (o == null || getClass() != o.getClass()) return false;
672         RecordedProgram that = (RecordedProgram) o;
673         return Objects.equals(mId, that.mId) &&
674                 Objects.equals(mChannelId, that.mChannelId) &&
675                 Objects.equals(mSeasonNumber, that.mSeasonNumber) &&
676                 Objects.equals(mSeasonTitle, that.mSeasonTitle) &&
677                 Objects.equals(mEpisodeNumber, that.mEpisodeNumber) &&
678                 Objects.equals(mStartTimeUtcMillis, that.mStartTimeUtcMillis) &&
679                 Objects.equals(mEndTimeUtcMillis, that.mEndTimeUtcMillis) &&
680                 Objects.equals(mVideoWidth, that.mVideoWidth) &&
681                 Objects.equals(mVideoHeight, that.mVideoHeight) &&
682                 Objects.equals(mSearchable, that.mSearchable) &&
683                 Objects.equals(mDataBytes, that.mDataBytes) &&
684                 Objects.equals(mDurationMillis, that.mDurationMillis) &&
685                 Objects.equals(mExpireTimeUtcMillis, that.mExpireTimeUtcMillis) &&
686                 Objects.equals(mInternalProviderFlag1, that.mInternalProviderFlag1) &&
687                 Objects.equals(mInternalProviderFlag2, that.mInternalProviderFlag2) &&
688                 Objects.equals(mInternalProviderFlag3, that.mInternalProviderFlag3) &&
689                 Objects.equals(mInternalProviderFlag4, that.mInternalProviderFlag4) &&
690                 Objects.equals(mVersionNumber, that.mVersionNumber) &&
691                 Objects.equals(mTitle, that.mTitle) &&
692                 Objects.equals(mEpisodeTitle, that.mEpisodeTitle) &&
693                 Arrays.equals(mBroadcastGenres, that.mBroadcastGenres) &&
694                 Arrays.equals(mCanonicalGenres, that.mCanonicalGenres) &&
695                 Objects.equals(mShortDescription, that.mShortDescription) &&
696                 Objects.equals(mLongDescription, that.mLongDescription) &&
697                 Objects.equals(mAudioLanguage, that.mAudioLanguage) &&
698                 Objects.equals(mContentRating, that.mContentRating) &&
699                 Objects.equals(mPosterArt, that.mPosterArt) &&
700                 Objects.equals(mThumbnail, that.mThumbnail);
701     }
702 
703     /**
704      * Hashes based on the ID.
705      */
706     @Override
hashCode()707     public int hashCode() {
708         return Objects.hash(mId);
709     }
710 
711     @Override
toString()712     public String toString() {
713         return "RecordedProgram"
714                 + "[" +  mId +
715                 "]{ mInputId=" + mInputId +
716                 ", mChannelId='" + mChannelId + '\'' +
717                 ", mTitle='" + mTitle + '\'' +
718                 ", mEpisodeNumber=" + mEpisodeNumber +
719                 ", mEpisodeTitle='" + mEpisodeTitle + '\'' +
720                 ", mStartTimeUtcMillis=" + mStartTimeUtcMillis +
721                 ", mEndTimeUtcMillis=" + mEndTimeUtcMillis +
722                 ", mBroadcastGenres=" +
723                         (mBroadcastGenres != null ? Arrays.toString(mBroadcastGenres) : "null") +
724                 ", mCanonicalGenres=" +
725                         (mCanonicalGenres != null ? Arrays.toString(mCanonicalGenres) : "null") +
726                 ", mShortDescription='" + mShortDescription + '\'' +
727                 ", mLongDescription='" + mLongDescription + '\'' +
728                 ", mVideoHeight=" + mVideoHeight +
729                 ", mVideoWidth=" + mVideoWidth +
730                 ", mAudioLanguage='" + mAudioLanguage + '\'' +
731                 ", mContentRating='" + mContentRating + '\'' +
732                 ", mPosterArt=" + mPosterArt +
733                 ", mThumbnail=" + mThumbnail +
734                 ", mSearchable=" + mSearchable +
735                 ", mDataUri=" + mDataUri +
736                 ", mDataBytes=" + mDataBytes +
737                 ", mDurationMillis=" + mDurationMillis +
738                 ", mExpireTimeUtcMillis=" + mExpireTimeUtcMillis +
739                 ", mInternalProviderData.length=" +
740                         (mInternalProviderData == null ? "null" : mInternalProviderData.length) +
741                 ", mInternalProviderFlag1=" + mInternalProviderFlag1 +
742                 ", mInternalProviderFlag2=" + mInternalProviderFlag2 +
743                 ", mInternalProviderFlag3=" + mInternalProviderFlag3 +
744                 ", mInternalProviderFlag4=" + mInternalProviderFlag4 +
745                 ", mSeasonNumber=" + mSeasonNumber +
746                 ", mSeasonTitle=" + mSeasonTitle +
747                 ", mVersionNumber=" + mVersionNumber +
748                 '}';
749     }
750 
751     @Nullable
safeToString(@ullable Object o)752     private static String safeToString(@Nullable Object o) {
753         return o == null ? null : o.toString();
754     }
755 
756     @Nullable
safeEncode(@ullable String[] genres)757     private static String safeEncode(@Nullable String[] genres) {
758         return genres == null ? null : TvContract.Programs.Genres.encode(genres);
759     }
760 }
761