1 /* 2 * Copyright (C) 2017 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.data; 18 19 import android.annotation.TargetApi; 20 import android.content.ContentResolver; 21 import android.content.ContentUris; 22 import android.content.Context; 23 import android.database.Cursor; 24 import android.database.SQLException; 25 import android.graphics.Bitmap; 26 import android.graphics.drawable.BitmapDrawable; 27 import android.graphics.drawable.Drawable; 28 import android.media.tv.TvContract; 29 import android.net.Uri; 30 import android.os.AsyncTask; 31 import android.os.Build; 32 import android.support.annotation.IntDef; 33 import android.support.annotation.MainThread; 34 import android.support.media.tv.ChannelLogoUtils; 35 import android.support.media.tv.PreviewProgram; 36 import android.util.Log; 37 import android.util.Pair; 38 39 import com.android.tv.R; 40 import com.android.tv.util.PermissionUtils; 41 42 import java.lang.annotation.Retention; 43 import java.lang.annotation.RetentionPolicy; 44 import java.util.HashMap; 45 import java.util.Map; 46 import java.util.Set; 47 import java.util.concurrent.CopyOnWriteArraySet; 48 49 /** 50 * Class to manage the preview data. 51 */ 52 @TargetApi(Build.VERSION_CODES.O) 53 @MainThread 54 public class PreviewDataManager { 55 private static final String TAG = "PreviewDataManager"; 56 // STOPSHIP: set it to false. 57 private static final boolean DEBUG = true; 58 59 /** 60 * Invalid preview channel ID. 61 */ 62 public static final long INVALID_PREVIEW_CHANNEL_ID = -1; 63 @IntDef({TYPE_DEFAULT_PREVIEW_CHANNEL, TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL}) 64 @Retention(RetentionPolicy.SOURCE) 65 public @interface PreviewChannelType{} 66 67 /** 68 * Type of default preview channel 69 */ 70 public static final long TYPE_DEFAULT_PREVIEW_CHANNEL = 1; 71 /** 72 * Type of recorded program channel 73 */ 74 public static final long TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL = 2; 75 76 private final Context mContext; 77 private final ContentResolver mContentResolver; 78 private boolean mLoadFinished; 79 private PreviewData mPreviewData = new PreviewData(); 80 private final Set<PreviewDataListener> mPreviewDataListeners = new CopyOnWriteArraySet<>(); 81 82 private QueryPreviewDataTask mQueryPreviewTask; 83 private final Map<Long, CreatePreviewChannelTask> mCreatePreviewChannelTasks = 84 new HashMap<>(); 85 private final Map<Long, UpdatePreviewProgramTask> mUpdatePreviewProgramTasks = new HashMap<>(); 86 87 private final int mPreviewChannelLogoWidth; 88 private final int mPreviewChannelLogoHeight; 89 PreviewDataManager(Context context)90 public PreviewDataManager(Context context) { 91 mContext = context.getApplicationContext(); 92 mContentResolver = context.getContentResolver(); 93 mPreviewChannelLogoWidth = mContext.getResources().getDimensionPixelSize( 94 R.dimen.preview_channel_logo_width); 95 mPreviewChannelLogoHeight = mContext.getResources().getDimensionPixelSize( 96 R.dimen.preview_channel_logo_height); 97 } 98 99 /** 100 * Starts the preview data manager. 101 */ start()102 public void start() { 103 if (mQueryPreviewTask == null) { 104 mQueryPreviewTask = new QueryPreviewDataTask(); 105 mQueryPreviewTask.execute(); 106 } 107 } 108 109 /** 110 * Stops the preview data manager. 111 */ stop()112 public void stop() { 113 if (mQueryPreviewTask != null) { 114 mQueryPreviewTask.cancel(true); 115 } 116 for (CreatePreviewChannelTask createPreviewChannelTask 117 : mCreatePreviewChannelTasks.values()) { 118 createPreviewChannelTask.cancel(true); 119 } 120 for (UpdatePreviewProgramTask updatePreviewProgramTask 121 : mUpdatePreviewProgramTasks.values()) { 122 updatePreviewProgramTask.cancel(true); 123 } 124 125 mQueryPreviewTask = null; 126 mCreatePreviewChannelTasks.clear(); 127 mUpdatePreviewProgramTasks.clear(); 128 } 129 130 /** 131 * Gets preview channel ID from the preview channel type. 132 */ getPreviewChannelId(long previewChannelType)133 public @PreviewChannelType long getPreviewChannelId(long previewChannelType) { 134 return mPreviewData.getPreviewChannelId(previewChannelType); 135 } 136 137 /** 138 * Creates default preview channel. 139 */ createDefaultPreviewChannel( OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener)140 public void createDefaultPreviewChannel( 141 OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener) { 142 createPreviewChannel(TYPE_DEFAULT_PREVIEW_CHANNEL, onPreviewChannelCreationResultListener); 143 } 144 145 /** 146 * Creates a preview channel for specific channel type. 147 */ createPreviewChannel(@reviewChannelType long previewChannelType, OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener)148 public void createPreviewChannel(@PreviewChannelType long previewChannelType, 149 OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener) { 150 CreatePreviewChannelTask currentRunningCreateTask = 151 mCreatePreviewChannelTasks.get(previewChannelType); 152 if (currentRunningCreateTask == null) { 153 CreatePreviewChannelTask createPreviewChannelTask = new CreatePreviewChannelTask( 154 previewChannelType); 155 createPreviewChannelTask.addOnPreviewChannelCreationResultListener( 156 onPreviewChannelCreationResultListener); 157 createPreviewChannelTask.execute(); 158 mCreatePreviewChannelTasks.put(previewChannelType, createPreviewChannelTask); 159 } else { 160 currentRunningCreateTask.addOnPreviewChannelCreationResultListener( 161 onPreviewChannelCreationResultListener); 162 } 163 } 164 165 /** 166 * Returns {@code true} if the preview data is loaded. 167 */ isLoadFinished()168 public boolean isLoadFinished() { 169 return mLoadFinished; 170 } 171 172 /** 173 * Adds listener. 174 */ addListener(PreviewDataListener previewDataListener)175 public void addListener(PreviewDataListener previewDataListener) { 176 mPreviewDataListeners.add(previewDataListener); 177 } 178 179 /** 180 * Removes listener. 181 */ removeListener(PreviewDataListener previewDataListener)182 public void removeListener(PreviewDataListener previewDataListener) { 183 mPreviewDataListeners.remove(previewDataListener); 184 } 185 186 /** 187 * Updates the preview programs table for a specific preview channel. 188 */ updatePreviewProgramsForChannel(long previewChannelId, Set<PreviewProgramContent> programs, PreviewDataListener previewDataListener)189 public void updatePreviewProgramsForChannel(long previewChannelId, 190 Set<PreviewProgramContent> programs, PreviewDataListener previewDataListener) { 191 UpdatePreviewProgramTask currentRunningUpdateTask = 192 mUpdatePreviewProgramTasks.get(previewChannelId); 193 if (currentRunningUpdateTask != null 194 && currentRunningUpdateTask.getPrograms().equals(programs)) { 195 currentRunningUpdateTask.addPreviewDataListener(previewDataListener); 196 return; 197 } 198 UpdatePreviewProgramTask updatePreviewProgramTask = 199 new UpdatePreviewProgramTask(previewChannelId, programs); 200 updatePreviewProgramTask.addPreviewDataListener(previewDataListener); 201 if (currentRunningUpdateTask != null) { 202 currentRunningUpdateTask.cancel(true); 203 currentRunningUpdateTask.saveStatus(); 204 updatePreviewProgramTask.addPreviewDataListeners( 205 currentRunningUpdateTask.getPreviewDataListeners()); 206 } 207 updatePreviewProgramTask.execute(); 208 mUpdatePreviewProgramTasks.put(previewChannelId, updatePreviewProgramTask); 209 } 210 notifyPreviewDataLoadFinished()211 private void notifyPreviewDataLoadFinished() { 212 for (PreviewDataListener l : mPreviewDataListeners) { 213 l.onPreviewDataLoadFinished(); 214 } 215 } 216 217 public interface PreviewDataListener { 218 /** 219 * Called when the preview data is loaded. 220 */ onPreviewDataLoadFinished()221 void onPreviewDataLoadFinished(); 222 223 /** 224 * Called when the preview data is updated. 225 */ onPreviewDataUpdateFinished()226 void onPreviewDataUpdateFinished(); 227 } 228 229 public interface OnPreviewChannelCreationResultListener { 230 /** 231 * Called when the creation of preview channel is finished. 232 * @param createdPreviewChannelId The preview channel ID if created successfully, 233 * otherwise it's {@value #INVALID_PREVIEW_CHANNEL_ID}. 234 */ onPreviewChannelCreationResult(long createdPreviewChannelId)235 void onPreviewChannelCreationResult(long createdPreviewChannelId); 236 } 237 238 private final class QueryPreviewDataTask extends AsyncTask<Void, Void, PreviewData> { 239 private final String PARAM_PREVIEW = "preview"; 240 private final String mChannelSelection = TvContract.Channels.COLUMN_PACKAGE_NAME + "=?"; 241 242 @Override doInBackground(Void... voids)243 protected PreviewData doInBackground(Void... voids) { 244 // Query preview channels and programs. 245 if (DEBUG) Log.d(TAG, "QueryPreviewDataTask.doInBackground"); 246 PreviewData previewData = new PreviewData(); 247 try { 248 Uri previewChannelsUri = 249 PreviewDataUtils.addQueryParamToUri( 250 TvContract.Channels.CONTENT_URI, 251 new Pair<>(PARAM_PREVIEW, String.valueOf(true))); 252 String packageName = mContext.getPackageName(); 253 if (PermissionUtils.hasAccessAllEpg(mContext)) { 254 try (Cursor cursor = 255 mContentResolver.query( 256 previewChannelsUri, 257 android.support.media.tv.Channel.PROJECTION, 258 mChannelSelection, 259 new String[] {packageName}, 260 null)) { 261 if (cursor != null) { 262 while (cursor.moveToNext()) { 263 android.support.media.tv.Channel previewChannel = 264 android.support.media.tv.Channel.fromCursor(cursor); 265 Long previewChannelType = previewChannel.getInternalProviderFlag1(); 266 if (previewChannelType != null) { 267 previewData.addPreviewChannelId( 268 previewChannelType, previewChannel.getId()); 269 } 270 } 271 } 272 } 273 } else { 274 try (Cursor cursor = 275 mContentResolver.query( 276 previewChannelsUri, 277 android.support.media.tv.Channel.PROJECTION, 278 null, 279 null, 280 null)) { 281 if (cursor != null) { 282 while (cursor.moveToNext()) { 283 android.support.media.tv.Channel previewChannel = 284 android.support.media.tv.Channel.fromCursor(cursor); 285 Long previewChannelType = previewChannel.getInternalProviderFlag1(); 286 if (previewChannel.getPackageName() == packageName 287 && previewChannelType != null) { 288 previewData.addPreviewChannelId( 289 previewChannelType, previewChannel.getId()); 290 } 291 } 292 } 293 } 294 } 295 296 for (long previewChannelId : previewData.getAllPreviewChannelIds().values()) { 297 Uri previewProgramsUriForPreviewChannel = 298 TvContract.buildPreviewProgramsUriForChannel(previewChannelId); 299 try (Cursor previewProgramCursor = 300 mContentResolver.query( 301 previewProgramsUriForPreviewChannel, 302 PreviewProgram.PROJECTION, 303 null, 304 null, 305 null)) { 306 if (previewProgramCursor != null) { 307 while (previewProgramCursor.moveToNext()) { 308 PreviewProgram previewProgram = 309 PreviewProgram.fromCursor(previewProgramCursor); 310 previewData.addPreviewProgram(previewProgram); 311 } 312 } 313 } 314 } 315 } catch (SQLException e) { 316 Log.w(TAG, "Unable to get preview data", e); 317 } 318 return previewData; 319 } 320 321 @Override onPostExecute(PreviewData result)322 protected void onPostExecute(PreviewData result) { 323 super.onPostExecute(result); 324 if (mQueryPreviewTask == this) { 325 mQueryPreviewTask = null; 326 mPreviewData = new PreviewData(result); 327 mLoadFinished = true; 328 notifyPreviewDataLoadFinished(); 329 } 330 } 331 } 332 333 private final class CreatePreviewChannelTask extends AsyncTask<Void, Void, Long> { 334 private final long mPreviewChannelType; 335 private Set<OnPreviewChannelCreationResultListener> 336 mOnPreviewChannelCreationResultListeners = new CopyOnWriteArraySet<>(); 337 CreatePreviewChannelTask(long previewChannelType)338 public CreatePreviewChannelTask(long previewChannelType) { 339 mPreviewChannelType = previewChannelType; 340 } 341 addOnPreviewChannelCreationResultListener( OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener)342 public void addOnPreviewChannelCreationResultListener( 343 OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener) { 344 if (onPreviewChannelCreationResultListener != null) { 345 mOnPreviewChannelCreationResultListeners.add( 346 onPreviewChannelCreationResultListener); 347 } 348 } 349 350 @Override doInBackground(Void... params)351 protected Long doInBackground(Void... params) { 352 if (DEBUG) Log.d(TAG, "CreatePreviewChannelTask.doInBackground"); 353 long previewChannelId; 354 try { 355 Uri channelUri = mContentResolver.insert(TvContract.Channels.CONTENT_URI, 356 PreviewDataUtils.createPreviewChannel(mContext, mPreviewChannelType) 357 .toContentValues()); 358 if (channelUri != null) { 359 previewChannelId = ContentUris.parseId(channelUri); 360 } else { 361 Log.e(TAG, "Fail to insert preview channel"); 362 return INVALID_PREVIEW_CHANNEL_ID; 363 } 364 } catch (UnsupportedOperationException | NumberFormatException e) { 365 Log.e(TAG, "Fail to get channel ID"); 366 return INVALID_PREVIEW_CHANNEL_ID; 367 } 368 Drawable appIcon = mContext.getApplicationInfo().loadIcon(mContext.getPackageManager()); 369 if (appIcon != null && appIcon instanceof BitmapDrawable) { 370 ChannelLogoUtils.storeChannelLogo(mContext, previewChannelId, 371 Bitmap.createScaledBitmap(((BitmapDrawable) appIcon).getBitmap(), 372 mPreviewChannelLogoWidth, mPreviewChannelLogoHeight, false)); 373 } 374 return previewChannelId; 375 } 376 377 @Override onPostExecute(Long result)378 protected void onPostExecute(Long result) { 379 super.onPostExecute(result); 380 if (result != INVALID_PREVIEW_CHANNEL_ID) { 381 mPreviewData.addPreviewChannelId(mPreviewChannelType, result); 382 } 383 for (OnPreviewChannelCreationResultListener onPreviewChannelCreationResultListener 384 : mOnPreviewChannelCreationResultListeners) { 385 onPreviewChannelCreationResultListener.onPreviewChannelCreationResult(result); 386 } 387 mCreatePreviewChannelTasks.remove(mPreviewChannelType); 388 } 389 } 390 391 /** 392 * Updates the whole data which belongs to the package in preview programs table for a 393 * specific preview channel with a set of {@link PreviewProgramContent}. 394 */ 395 private final class UpdatePreviewProgramTask extends AsyncTask<Void, Void, Void> { 396 private long mPreviewChannelId; 397 private Set<PreviewProgramContent> mPrograms; 398 private Map<Long, Long> mCurrentProgramId2PreviewProgramId; 399 private Set<PreviewDataListener> mPreviewDataListeners = new CopyOnWriteArraySet<>(); 400 UpdatePreviewProgramTask(long previewChannelId, Set<PreviewProgramContent> programs)401 public UpdatePreviewProgramTask(long previewChannelId, 402 Set<PreviewProgramContent> programs) { 403 mPreviewChannelId = previewChannelId; 404 mPrograms = programs; 405 if (mPreviewData.getPreviewProgramIds(previewChannelId) == null) { 406 mCurrentProgramId2PreviewProgramId = new HashMap<>(); 407 } else { 408 mCurrentProgramId2PreviewProgramId = new HashMap<>( 409 mPreviewData.getPreviewProgramIds(previewChannelId)); 410 } 411 } 412 addPreviewDataListener(PreviewDataListener previewDataListener)413 public void addPreviewDataListener(PreviewDataListener previewDataListener) { 414 if (previewDataListener != null) { 415 mPreviewDataListeners.add(previewDataListener); 416 } 417 } 418 addPreviewDataListeners(Set<PreviewDataListener> previewDataListeners)419 public void addPreviewDataListeners(Set<PreviewDataListener> previewDataListeners) { 420 if (previewDataListeners != null) { 421 mPreviewDataListeners.addAll(previewDataListeners); 422 } 423 } 424 getPrograms()425 public Set<PreviewProgramContent> getPrograms() { 426 return mPrograms; 427 } 428 getPreviewDataListeners()429 public Set<PreviewDataListener> getPreviewDataListeners() { 430 return mPreviewDataListeners; 431 } 432 433 @Override doInBackground(Void... params)434 protected Void doInBackground(Void... params) { 435 if (DEBUG) Log.d(TAG, "UpdatePreviewProgamTask.doInBackground"); 436 Map<Long, Long> uncheckedPrograms = new HashMap<>(mCurrentProgramId2PreviewProgramId); 437 for (PreviewProgramContent program : mPrograms) { 438 if (isCancelled()) { 439 return null; 440 } 441 Long existingPreviewProgramId = uncheckedPrograms.remove(program.getId()); 442 if (existingPreviewProgramId != null) { 443 if (DEBUG) Log.d(TAG, "Preview program " + existingPreviewProgramId + " " + 444 "already exists for program " + program.getId()); 445 continue; 446 } 447 try { 448 Uri programUri = mContentResolver.insert(TvContract.PreviewPrograms.CONTENT_URI, 449 PreviewDataUtils.createPreviewProgramFromContent(program) 450 .toContentValues()); 451 if (programUri != null) { 452 long previewProgramId = ContentUris.parseId(programUri); 453 mCurrentProgramId2PreviewProgramId.put(program.getId(), previewProgramId); 454 if (DEBUG) Log.d(TAG, "Add new preview program " + previewProgramId); 455 } else { 456 Log.e(TAG, "Fail to insert preview program"); 457 } 458 } catch (Exception e) { 459 Log.e(TAG, "Fail to get preview program ID"); 460 } 461 } 462 463 for (Long key : uncheckedPrograms.keySet()) { 464 if (isCancelled()) { 465 return null; 466 } 467 try { 468 if (DEBUG) Log.d(TAG, "Remove preview program " + uncheckedPrograms.get(key)); 469 mContentResolver.delete(TvContract.buildPreviewProgramUri( 470 uncheckedPrograms.get(key)), null, null); 471 mCurrentProgramId2PreviewProgramId.remove(key); 472 } catch (Exception e) { 473 Log.e(TAG, "Fail to remove preview program " + uncheckedPrograms.get(key)); 474 } 475 } 476 return null; 477 } 478 479 @Override onPostExecute(Void result)480 protected void onPostExecute(Void result) { 481 super.onPostExecute(result); 482 mPreviewData.setPreviewProgramIds( 483 mPreviewChannelId, mCurrentProgramId2PreviewProgramId); 484 mUpdatePreviewProgramTasks.remove(mPreviewChannelId); 485 for (PreviewDataListener previewDataListener : mPreviewDataListeners) { 486 previewDataListener.onPreviewDataUpdateFinished(); 487 } 488 } 489 saveStatus()490 public void saveStatus() { 491 mPreviewData.setPreviewProgramIds( 492 mPreviewChannelId, mCurrentProgramId2PreviewProgramId); 493 } 494 } 495 496 /** 497 * Class to store the query result of preview data. 498 */ 499 private static final class PreviewData { 500 private Map<Long, Long> mPreviewChannelType2Id = new HashMap<>(); 501 private Map<Long, Map<Long, Long>> mProgramId2PreviewProgramId = new HashMap<>(); 502 PreviewData()503 PreviewData() { 504 mPreviewChannelType2Id = new HashMap<>(); 505 mProgramId2PreviewProgramId = new HashMap<>(); 506 } 507 PreviewData(PreviewData previewData)508 PreviewData(PreviewData previewData) { 509 mPreviewChannelType2Id = new HashMap<>(previewData.mPreviewChannelType2Id); 510 mProgramId2PreviewProgramId = new HashMap<>(previewData.mProgramId2PreviewProgramId); 511 } 512 addPreviewProgram(PreviewProgram previewProgram)513 public void addPreviewProgram(PreviewProgram previewProgram) { 514 long previewChannelId = previewProgram.getChannelId(); 515 Map<Long, Long> programId2PreviewProgram = 516 mProgramId2PreviewProgramId.get(previewChannelId); 517 if (programId2PreviewProgram == null) { 518 programId2PreviewProgram = new HashMap<>(); 519 } 520 mProgramId2PreviewProgramId.put(previewChannelId, programId2PreviewProgram); 521 if (previewProgram.getInternalProviderId() != null) { 522 programId2PreviewProgram.put( 523 Long.parseLong(previewProgram.getInternalProviderId()), 524 previewProgram.getId()); 525 } 526 } 527 getPreviewChannelId(long previewChannelType)528 public @PreviewChannelType long getPreviewChannelId(long previewChannelType) { 529 Long result = mPreviewChannelType2Id.get(previewChannelType); 530 return result == null ? INVALID_PREVIEW_CHANNEL_ID : result; 531 } 532 getAllPreviewChannelIds()533 public Map<Long, Long> getAllPreviewChannelIds() { 534 return mPreviewChannelType2Id; 535 } 536 addPreviewChannelId(long previewChannelType, long previewChannelId)537 public void addPreviewChannelId(long previewChannelType, long previewChannelId) { 538 mPreviewChannelType2Id.put(previewChannelType, previewChannelId); 539 } 540 removePreviewChannelId(long previewChannelType)541 public void removePreviewChannelId(long previewChannelType) { 542 mPreviewChannelType2Id.remove(previewChannelType); 543 } 544 removePreviewChannel(long previewChannelId)545 public void removePreviewChannel(long previewChannelId) { 546 removePreviewChannelId(previewChannelId); 547 removePreviewProgramIds(previewChannelId); 548 } 549 getPreviewProgramIds(long previewChannelId)550 public Map<Long, Long> getPreviewProgramIds(long previewChannelId) { 551 return mProgramId2PreviewProgramId.get(previewChannelId); 552 } 553 getAllPreviewProgramIds()554 public Map<Long, Map<Long, Long>> getAllPreviewProgramIds() { 555 return mProgramId2PreviewProgramId; 556 } 557 setPreviewProgramIds( long previewChannelId, Map<Long, Long> programId2PreviewProgramId)558 public void setPreviewProgramIds( 559 long previewChannelId, Map<Long, Long> programId2PreviewProgramId) { 560 mProgramId2PreviewProgramId.put(previewChannelId, programId2PreviewProgramId); 561 } 562 removePreviewProgramIds(long previewChannelId)563 public void removePreviewProgramIds(long previewChannelId) { 564 mProgramId2PreviewProgramId.remove(previewChannelId); 565 } 566 } 567 568 /** 569 * A utils class for preview data. 570 */ 571 public final static class PreviewDataUtils { 572 /** 573 * Creates a preview channel. 574 */ createPreviewChannel( Context context, @PreviewChannelType long previewChannelType)575 public static android.support.media.tv.Channel createPreviewChannel( 576 Context context, @PreviewChannelType long previewChannelType) { 577 if (previewChannelType == TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL) { 578 return createRecordedProgramPreviewChannel(context, previewChannelType); 579 } 580 return createDefaultPreviewChannel(context, previewChannelType); 581 } 582 createDefaultPreviewChannel( Context context, @PreviewChannelType long previewChannelType)583 private static android.support.media.tv.Channel createDefaultPreviewChannel( 584 Context context, @PreviewChannelType long previewChannelType) { 585 android.support.media.tv.Channel.Builder builder = 586 new android.support.media.tv.Channel.Builder(); 587 CharSequence appLabel = 588 context.getApplicationInfo().loadLabel(context.getPackageManager()); 589 CharSequence appDescription = 590 context.getApplicationInfo().loadDescription(context.getPackageManager()); 591 builder.setType(TvContract.Channels.TYPE_PREVIEW) 592 .setDisplayName(appLabel == null ? null : appLabel.toString()) 593 .setDescription(appDescription == null ? null : appDescription.toString()) 594 .setAppLinkIntentUri(TvContract.Channels.CONTENT_URI) 595 .setInternalProviderFlag1(previewChannelType); 596 return builder.build(); 597 } 598 createRecordedProgramPreviewChannel( Context context, @PreviewChannelType long previewChannelType)599 private static android.support.media.tv.Channel createRecordedProgramPreviewChannel( 600 Context context, @PreviewChannelType long previewChannelType) { 601 android.support.media.tv.Channel.Builder builder = 602 new android.support.media.tv.Channel.Builder(); 603 builder.setType(TvContract.Channels.TYPE_PREVIEW) 604 .setDisplayName(context.getResources().getString( 605 R.string.recorded_programs_preview_channel)) 606 .setAppLinkIntentUri(TvContract.Channels.CONTENT_URI) 607 .setInternalProviderFlag1(previewChannelType); 608 return builder.build(); 609 } 610 611 /** 612 * Creates a preview program. 613 */ createPreviewProgramFromContent( PreviewProgramContent program)614 public static PreviewProgram createPreviewProgramFromContent( 615 PreviewProgramContent program) { 616 PreviewProgram.Builder builder = new PreviewProgram.Builder(); 617 builder.setChannelId(program.getPreviewChannelId()) 618 .setType(program.getType()) 619 .setLive(program.getLive()) 620 .setTitle(program.getTitle()) 621 .setDescription(program.getDescription()) 622 .setPosterArtUri(program.getPosterArtUri()) 623 .setIntentUri(program.getIntentUri()) 624 .setPreviewVideoUri(program.getPreviewVideoUri()) 625 .setInternalProviderId(Long.toString(program.getId())); 626 return builder.build(); 627 } 628 629 /** 630 * Appends query parameters to a Uri. 631 */ addQueryParamToUri(Uri uri, Pair<String, String> param)632 public static Uri addQueryParamToUri(Uri uri, Pair<String, String> param) { 633 return uri.buildUpon().appendQueryParameter(param.first, param.second).build(); 634 } 635 } 636 } 637