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 17package com.android.tv.recommendation; 18 19import android.content.Context; 20import android.os.Build; 21import android.support.annotation.RequiresApi; 22import android.text.TextUtils; 23import android.util.Log; 24 25import com.android.tv.ApplicationSingletons; 26import com.android.tv.TvApplication; 27import com.android.tv.data.PreviewDataManager; 28import com.android.tv.data.PreviewProgramContent; 29import com.android.tv.dvr.DvrDataManager; 30import com.android.tv.dvr.data.RecordedProgram; 31 32import java.util.ArrayList; 33import java.util.Collections; 34import java.util.HashSet; 35import java.util.Set; 36 37/** 38 * Class to update the preview data for {@link RecordedProgram} 39 */ 40@RequiresApi(Build.VERSION_CODES.O) 41public class RecordedProgramPreviewUpdater { 42 private static final String TAG = "RecordedProgramPreviewUpdater"; 43 // STOPSHIP: set it to false. 44 private static final boolean DEBUG = true; 45 46 private static final int RECOMMENDATION_COUNT = 6; 47 48 private static RecordedProgramPreviewUpdater sRecordedProgramPreviewUpdater; 49 50 /** 51 * Creates and returns the {@link RecordedProgramPreviewUpdater}. 52 */ 53 public static RecordedProgramPreviewUpdater getInstance(Context context) { 54 if (sRecordedProgramPreviewUpdater == null) { 55 sRecordedProgramPreviewUpdater 56 = new RecordedProgramPreviewUpdater(context.getApplicationContext()); 57 } 58 return sRecordedProgramPreviewUpdater; 59 } 60 61 private final Context mContext; 62 private final PreviewDataManager mPreviewDataManager; 63 private final DvrDataManager mDvrDataManager; 64 65 private RecordedProgramPreviewUpdater(Context context) { 66 mContext = context.getApplicationContext(); 67 ApplicationSingletons applicationSingletons = TvApplication.getSingletons(mContext); 68 mPreviewDataManager = applicationSingletons.getPreviewDataManager(); 69 mDvrDataManager = applicationSingletons.getDvrDataManager(); 70 mDvrDataManager.addRecordedProgramListener(new DvrDataManager.RecordedProgramListener() { 71 @Override 72 public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) { 73 if (DEBUG) Log.d(TAG, "Add new preview recorded programs"); 74 updatePreviewDataForRecordedPrograms(); 75 } 76 77 @Override 78 public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) { 79 if (DEBUG) Log.d(TAG, "Update preview recorded programs"); 80 updatePreviewDataForRecordedPrograms(); 81 } 82 83 @Override 84 public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) { 85 if (DEBUG) Log.d(TAG, "Delete preview recorded programs"); 86 updatePreviewDataForRecordedPrograms(); 87 } 88 }); 89 } 90 91 /** 92 * Updates the preview data for recorded programs. 93 */ 94 public void updatePreviewDataForRecordedPrograms() { 95 if (!mPreviewDataManager.isLoadFinished()) { 96 mPreviewDataManager.addListener(new PreviewDataManager.PreviewDataListener() { 97 @Override 98 public void onPreviewDataLoadFinished() { 99 mPreviewDataManager.removeListener(this); 100 updatePreviewDataForRecordedPrograms(); 101 } 102 103 @Override 104 public void onPreviewDataUpdateFinished() { } 105 }); 106 return; 107 } 108 if (!mDvrDataManager.isRecordedProgramLoadFinished()) { 109 mDvrDataManager.addRecordedProgramLoadFinishedListener( 110 new DvrDataManager.OnRecordedProgramLoadFinishedListener() { 111 @Override 112 public void onRecordedProgramLoadFinished() { 113 mDvrDataManager.removeRecordedProgramLoadFinishedListener(this); 114 updatePreviewDataForRecordedPrograms(); 115 } 116 }); 117 return; 118 } 119 updatePreviewDataForRecordedProgramsInternal(); 120 } 121 122 private void updatePreviewDataForRecordedProgramsInternal() { 123 Set<RecordedProgram> recordedPrograms = generateRecommendationRecordedPrograms(); 124 Long recordedPreviewChannelId = mPreviewDataManager.getPreviewChannelId( 125 PreviewDataManager.TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL); 126 if (recordedPreviewChannelId == PreviewDataManager.INVALID_PREVIEW_CHANNEL_ID 127 && !recordedPrograms.isEmpty()) { 128 createPreviewChannelForRecordedPrograms(); 129 } else { 130 mPreviewDataManager.updatePreviewProgramsForChannel(recordedPreviewChannelId, 131 generatePreviewProgramContentsFromRecordedPrograms( 132 recordedPreviewChannelId, recordedPrograms), null); 133 } 134 } 135 136 private void createPreviewChannelForRecordedPrograms() { 137 mPreviewDataManager.createPreviewChannel( 138 PreviewDataManager.TYPE_RECORDED_PROGRAM_PREVIEW_CHANNEL, 139 new PreviewDataManager.OnPreviewChannelCreationResultListener() { 140 @Override 141 public void onPreviewChannelCreationResult(long createdPreviewChannelId) { 142 if (createdPreviewChannelId 143 != PreviewDataManager.INVALID_PREVIEW_CHANNEL_ID) { 144 updatePreviewDataForRecordedProgramsInternal(); 145 } 146 } 147 }); 148 } 149 150 private Set<RecordedProgram> generateRecommendationRecordedPrograms() { 151 Set<RecordedProgram> programs = new HashSet<>(); 152 ArrayList<RecordedProgram> sortedRecordedPrograms = 153 new ArrayList<>(mDvrDataManager.getRecordedPrograms()); 154 Collections.sort( 155 sortedRecordedPrograms, RecordedProgram.START_TIME_THEN_ID_COMPARATOR.reversed()); 156 for (RecordedProgram recordedProgram : sortedRecordedPrograms) { 157 if (!TextUtils.isEmpty(recordedProgram.getPosterArtUri())) { 158 programs.add(recordedProgram); 159 if (programs.size() >= RECOMMENDATION_COUNT) { 160 break; 161 } 162 } 163 } 164 return programs; 165 } 166 167 private Set<PreviewProgramContent> generatePreviewProgramContentsFromRecordedPrograms( 168 long previewChannelId, Set<RecordedProgram> recordedPrograms) { 169 Set<PreviewProgramContent> result = new HashSet<>(); 170 for (RecordedProgram recordedProgram : recordedPrograms) { 171 result.add(PreviewProgramContent.createFromRecordedProgram(mContext, previewChannelId, 172 recordedProgram)); 173 } 174 return result; 175 } 176} 177