1816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko/* 2816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Copyright (C) 2015 The Android Open Source Project 3816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 4816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 5816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * you may not use this file except in compliance with the License. 6816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * You may obtain a copy of the License at 7816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 8816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 9816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * 10816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Unless required by applicable law or agreed to in writing, software 11816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 12816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * See the License for the specific language governing permissions and 14816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * limitations under the License. 15816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 16816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 17816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopackage com.android.tv.guide; 18816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 19ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.MainThread; 202e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.support.annotation.Nullable; 210cc0713c1bf8027642987b750b80217569d2932aLive Channels Teamimport android.support.annotation.VisibleForTesting; 222e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.util.ArraySet; 23816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport android.util.Log; 24816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ChannelDataManager; 25816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.GenreItems; 26816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.Program; 27816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.data.ProgramDataManager; 280cc0713c1bf8027642987b750b80217569d2932aLive Channels Teamimport com.android.tv.data.api.Channel; 292e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport com.android.tv.dvr.DvrDataManager; 3065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.DvrScheduleManager; 3165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport com.android.tv.dvr.DvrScheduleManager.OnConflictStateChangeListener; 32633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalkoimport com.android.tv.dvr.data.ScheduledRecording; 33816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.TvInputManagerHelper; 34816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport com.android.tv.util.Utils; 35816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.ArrayList; 36816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.HashMap; 37816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.List; 38816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.Map; 397d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalkoimport java.util.Set; 40816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkoimport java.util.concurrent.TimeUnit; 41816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 4295961816a768da387f0b5523cf4363ace2044089Nick Chalko/** Manages the channels and programs for the program guide. */ 43ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko@MainThread 44816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalkopublic class ProgramManager { 45816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final String TAG = "ProgramManager"; 46816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final boolean DEBUG = false; 47816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 48816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 49816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * If the first entry's visible duration is shorter than this value, we clip the entry out. 50816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * Note: If this value is larger than 1 min, it could cause mismatches between the entry's 51816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko * position and detailed view's time range. 52816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 53816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko static final long FIRST_ENTRY_MIN_DURATION = TimeUnit.MINUTES.toMillis(1); 54816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 55816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private static final long INVALID_ID = -1; 56816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 57816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final TvInputManagerHelper mTvInputManagerHelper; 58816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ChannelDataManager mChannelDataManager; 59816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final ProgramDataManager mProgramDataManager; 6095961816a768da387f0b5523cf4363ace2044089Nick Chalko private final DvrDataManager mDvrDataManager; // Only set if DVR is enabled 6165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final DvrScheduleManager mDvrScheduleManager; 62816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 63816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private long mStartUtcMillis; 64816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private long mEndUtcMillis; 65816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private long mFromUtcMillis; 66816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private long mToUtcMillis; 67816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 68816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private List<Channel> mChannels = new ArrayList<>(); 69816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final Map<Long, List<TableEntry>> mChannelIdEntriesMap = new HashMap<>(); 70816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final List<List<Channel>> mGenreChannelList = new ArrayList<>(); 71816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private final List<Integer> mFilteredGenreIds = new ArrayList<>(); 72816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 73816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Position of selected genre to filter channel list. 74816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private int mSelectedGenreId = GenreItems.ID_ALL_CHANNELS; 75816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Channel list after applying genre filter. 76816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Should be matched with mSelectedGenreId always. 77816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private List<Channel> mFilteredChannels = mChannels; 7865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private boolean mChannelDataLoaded; 79816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 802e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko private final Set<Listener> mListeners = new ArraySet<>(); 812e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko private final Set<TableEntriesUpdatedListener> mTableEntriesUpdatedListeners = new ArraySet<>(); 822e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 832e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko private final Set<TableEntryChangedListener> mTableEntryChangedListeners = new ArraySet<>(); 847d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 8565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final DvrDataManager.OnDvrScheduleLoadFinishedListener mDvrLoadedListener = 8665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko new DvrDataManager.OnDvrScheduleLoadFinishedListener() { 8765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Override 8865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko public void onDvrScheduleLoadFinished() { 8965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (mChannelDataLoaded) { 9065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (ScheduledRecording r : mDvrDataManager.getAllScheduledRecordings()) { 9165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mScheduledRecordingListener.onScheduledRecordingAdded(r); 9265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 9365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 9465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mDvrDataManager.removeDvrScheduleLoadFinishedListener(this); 9565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 9665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko }; 9765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 987d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko private final ChannelDataManager.Listener mChannelDataManagerListener = 997d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko new ChannelDataManager.Listener() { 1007d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 1017d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public void onLoadFinished() { 10265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mChannelDataLoaded = true; 103d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko updateChannels(false); 1047d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 1057d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 1067d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 1077d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public void onChannelListUpdated() { 108d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko updateChannels(false); 1097d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 1107d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 1117d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 1127d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public void onChannelBrowsableChanged() { 113d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko updateChannels(false); 1147d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 1157d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko }; 1167d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko 1177d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko private final ProgramDataManager.Listener mProgramDataManagerListener = 1187d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko new ProgramDataManager.Listener() { 1197d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko @Override 1207d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko public void onProgramUpdated() { 121d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko updateTableEntries(true); 1227d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 1237d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko }; 124816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 1252e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko private final DvrDataManager.ScheduledRecordingListener mScheduledRecordingListener = 1262e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko new DvrDataManager.ScheduledRecordingListener() { 12795961816a768da387f0b5523cf4363ace2044089Nick Chalko @Override 12895961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) { 12995961816a768da387f0b5523cf4363ace2044089Nick Chalko for (ScheduledRecording schedule : scheduledRecordings) { 13095961816a768da387f0b5523cf4363ace2044089Nick Chalko TableEntry oldEntry = getTableEntry(schedule); 13195961816a768da387f0b5523cf4363ace2044089Nick Chalko if (oldEntry != null) { 13295961816a768da387f0b5523cf4363ace2044089Nick Chalko TableEntry newEntry = 13395961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 13495961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.channelId, 13595961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.program, 13695961816a768da387f0b5523cf4363ace2044089Nick Chalko schedule, 13795961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.entryStartUtcMillis, 13895961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.entryEndUtcMillis, 13995961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.isBlocked()); 14095961816a768da387f0b5523cf4363ace2044089Nick Chalko updateEntry(oldEntry, newEntry); 14195961816a768da387f0b5523cf4363ace2044089Nick Chalko } 14295961816a768da387f0b5523cf4363ace2044089Nick Chalko } 14365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 1442e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 14595961816a768da387f0b5523cf4363ace2044089Nick Chalko @Override 14695961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) { 14795961816a768da387f0b5523cf4363ace2044089Nick Chalko for (ScheduledRecording schedule : scheduledRecordings) { 14895961816a768da387f0b5523cf4363ace2044089Nick Chalko TableEntry oldEntry = getTableEntry(schedule); 14995961816a768da387f0b5523cf4363ace2044089Nick Chalko if (oldEntry != null) { 15095961816a768da387f0b5523cf4363ace2044089Nick Chalko TableEntry newEntry = 15195961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 15295961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.channelId, 15395961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.program, 15495961816a768da387f0b5523cf4363ace2044089Nick Chalko null, 15595961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.entryStartUtcMillis, 15695961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.entryEndUtcMillis, 15795961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.isBlocked()); 15895961816a768da387f0b5523cf4363ace2044089Nick Chalko updateEntry(oldEntry, newEntry); 15995961816a768da387f0b5523cf4363ace2044089Nick Chalko } 16095961816a768da387f0b5523cf4363ace2044089Nick Chalko } 16165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 1622e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 16395961816a768da387f0b5523cf4363ace2044089Nick Chalko @Override 16495961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onScheduledRecordingStatusChanged( 16595961816a768da387f0b5523cf4363ace2044089Nick Chalko ScheduledRecording... scheduledRecordings) { 16695961816a768da387f0b5523cf4363ace2044089Nick Chalko for (ScheduledRecording schedule : scheduledRecordings) { 16795961816a768da387f0b5523cf4363ace2044089Nick Chalko TableEntry oldEntry = getTableEntry(schedule); 16895961816a768da387f0b5523cf4363ace2044089Nick Chalko if (oldEntry != null) { 16995961816a768da387f0b5523cf4363ace2044089Nick Chalko TableEntry newEntry = 17095961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 17195961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.channelId, 17295961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.program, 17395961816a768da387f0b5523cf4363ace2044089Nick Chalko schedule, 17495961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.entryStartUtcMillis, 17595961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.entryEndUtcMillis, 17695961816a768da387f0b5523cf4363ace2044089Nick Chalko oldEntry.isBlocked()); 17795961816a768da387f0b5523cf4363ace2044089Nick Chalko updateEntry(oldEntry, newEntry); 17895961816a768da387f0b5523cf4363ace2044089Nick Chalko } 17995961816a768da387f0b5523cf4363ace2044089Nick Chalko } 18065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 18195961816a768da387f0b5523cf4363ace2044089Nick Chalko }; 1822e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 18365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko private final OnConflictStateChangeListener mOnConflictStateChangeListener = 18465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko new OnConflictStateChangeListener() { 18565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Override 18695961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onConflictStateChange( 18795961816a768da387f0b5523cf4363ace2044089Nick Chalko boolean conflict, ScheduledRecording... schedules) { 18865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko for (ScheduledRecording schedule : schedules) { 18965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko TableEntry entry = getTableEntry(schedule); 19065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (entry != null) { 19165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko notifyTableEntryUpdated(entry); 19265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 19365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 19465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 19565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko }; 19665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko 19795961816a768da387f0b5523cf4363ace2044089Nick Chalko public ProgramManager( 19895961816a768da387f0b5523cf4363ace2044089Nick Chalko TvInputManagerHelper tvInputManagerHelper, 19995961816a768da387f0b5523cf4363ace2044089Nick Chalko ChannelDataManager channelDataManager, 20095961816a768da387f0b5523cf4363ace2044089Nick Chalko ProgramDataManager programDataManager, 20165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Nullable DvrDataManager dvrDataManager, 20265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko @Nullable DvrScheduleManager dvrScheduleManager) { 203816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTvInputManagerHelper = tvInputManagerHelper; 204816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelDataManager = channelDataManager; 205816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramDataManager = programDataManager; 2062e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mDvrDataManager = dvrDataManager; 20765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mDvrScheduleManager = dvrScheduleManager; 208816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 209816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 210633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void programGuideVisibilityChanged(boolean visible) { 211816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mProgramDataManager.setPauseProgramUpdate(visible); 2127d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (visible) { 2137d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko mChannelDataManager.addListener(mChannelDataManagerListener); 2147d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko mProgramDataManager.addListener(mProgramDataManagerListener); 2152e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko if (mDvrDataManager != null) { 21665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (!mDvrDataManager.isDvrScheduleLoadFinished()) { 21765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mDvrDataManager.addDvrScheduleLoadFinishedListener(mDvrLoadedListener); 21865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 2192e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mDvrDataManager.addScheduledRecordingListener(mScheduledRecordingListener); 2202e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 22165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (mDvrScheduleManager != null) { 22265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mDvrScheduleManager.addOnConflictStateChangeListener( 22365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mOnConflictStateChangeListener); 22465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 2257d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } else { 2267d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko mChannelDataManager.removeListener(mChannelDataManagerListener); 2277d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko mProgramDataManager.removeListener(mProgramDataManagerListener); 2282e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko if (mDvrDataManager != null) { 22965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mDvrDataManager.removeDvrScheduleLoadFinishedListener(mDvrLoadedListener); 2302e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mDvrDataManager.removeScheduledRecordingListener(mScheduledRecordingListener); 2312e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 23265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (mDvrScheduleManager != null) { 23365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mDvrScheduleManager.removeOnConflictStateChangeListener( 23465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko mOnConflictStateChangeListener); 23565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 2367d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko } 237816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 238816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 23995961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Adds a {@link Listener}. */ 240633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void addListener(Listener listener) { 241816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListeners.add(listener); 242816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 243816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 24495961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Registers a listener to be invoked when table entries are updated. */ 245633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void addTableEntriesUpdatedListener(TableEntriesUpdatedListener listener) { 246816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTableEntriesUpdatedListeners.add(listener); 247816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 248816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 24995961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Registers a listener to be invoked when a table entry is changed. */ 250633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void addTableEntryChangedListener(TableEntryChangedListener listener) { 2512e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mTableEntryChangedListeners.add(listener); 2522e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 2532e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 25495961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Removes a {@link Listener}. */ 255633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void removeListener(Listener listener) { 256816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mListeners.remove(listener); 257816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 258816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 25995961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Removes a previously installed table entries update listener. */ 260633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void removeTableEntriesUpdatedListener(TableEntriesUpdatedListener listener) { 261816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mTableEntriesUpdatedListeners.remove(listener); 262816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 263816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 26495961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Removes a previously installed table entry changed listener. */ 265633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void removeTableEntryChangedListener(TableEntryChangedListener listener) { 2662e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko mTableEntryChangedListeners.remove(listener); 2672e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 2682e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 2692e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko /** 27095961816a768da387f0b5523cf4363ace2044089Nick Chalko * Resets channel list with given genre. Caller should call {@link #buildGenreFilters()} prior 27195961816a768da387f0b5523cf4363ace2044089Nick Chalko * to call this API to make This notifies channel updates to listeners. 272816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 273633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void resetChannelListWithGenre(int genreId) { 274816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (genreId == mSelectedGenreId) { 275816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return; 276816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 277816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mFilteredChannels = mGenreChannelList.get(genreId); 278816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedGenreId = genreId; 279816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) { 28095961816a768da387f0b5523cf4363ace2044089Nick Chalko Log.d( 28195961816a768da387f0b5523cf4363ace2044089Nick Chalko TAG, 28295961816a768da387f0b5523cf4363ace2044089Nick Chalko "resetChannelListWithGenre: " 28395961816a768da387f0b5523cf4363ace2044089Nick Chalko + GenreItems.getCanonicalGenre(genreId) 28495961816a768da387f0b5523cf4363ace2044089Nick Chalko + " has " 28595961816a768da387f0b5523cf4363ace2044089Nick Chalko + mFilteredChannels.size() 28695961816a768da387f0b5523cf4363ace2044089Nick Chalko + " channels out of " 28795961816a768da387f0b5523cf4363ace2044089Nick Chalko + mChannels.size()); 288816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 289816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mGenreChannelList.get(mSelectedGenreId) == null) { 290816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko throw new IllegalStateException("Genre filter isn't ready."); 291816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 292816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyChannelsUpdated(); 293816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 294816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 29595961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Update the initial time range to manage. It updates program entries and genre as well. */ 296633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void updateInitialTimeRange(long startUtcMillis, long endUtcMillis) { 297633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mStartUtcMillis = startUtcMillis; 298633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (endUtcMillis > mEndUtcMillis) { 299633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mEndUtcMillis = endUtcMillis; 300633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 301633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 302633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mProgramDataManager.setPrefetchTimeRange(mStartUtcMillis); 303633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko updateChannels(true); 304633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko setTimeRange(startUtcMillis, endUtcMillis); 305633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 306633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 30795961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Shifts the time range by the given time. Also makes ProgramGuide scroll the views. */ 308633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void shiftTime(long timeMillisToScroll) { 309633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long fromUtcMillis = mFromUtcMillis + timeMillisToScroll; 310633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long toUtcMillis = mToUtcMillis + timeMillisToScroll; 311633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (fromUtcMillis < mStartUtcMillis) { 312633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko fromUtcMillis = mStartUtcMillis; 313633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko toUtcMillis += mStartUtcMillis - fromUtcMillis; 314633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 315633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (toUtcMillis > mEndUtcMillis) { 316633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko fromUtcMillis -= toUtcMillis - mEndUtcMillis; 317633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko toUtcMillis = mEndUtcMillis; 318633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 319633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko setTimeRange(fromUtcMillis, toUtcMillis); 320633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 321633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 32295961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returned the scrolled(shifted) time in milliseconds. */ 323633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long getShiftedTime() { 324633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mFromUtcMillis - mStartUtcMillis; 325633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 326633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 32795961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the start time set by {@link #updateInitialTimeRange}. */ 328633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long getStartTime() { 329633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mStartUtcMillis; 330633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 331633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 33295961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the program index of the program with {@code entryId} or -1 if not found. */ 333633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getProgramIdIndex(long channelId, long entryId) { 334633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko List<TableEntry> entries = mChannelIdEntriesMap.get(channelId); 335633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (entries != null) { 336633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (int i = 0; i < entries.size(); i++) { 337633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (entries.get(i).getId() == entryId) { 338633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return i; 339633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 340633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 341633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 342633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return -1; 343633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 344633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 34595961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the program index of the program at {@code time} or -1 if not found. */ 346633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getProgramIndexAtTime(long channelId, long time) { 347633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko List<TableEntry> entries = mChannelIdEntriesMap.get(channelId); 348633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (int i = 0; i < entries.size(); ++i) { 349633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko TableEntry entry = entries.get(i); 35095961816a768da387f0b5523cf4363ace2044089Nick Chalko if (entry.entryStartUtcMillis <= time && time < entry.entryEndUtcMillis) { 351633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return i; 352633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 353633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 354633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return -1; 355633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 356633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 35795961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the start time of currently managed time range, in UTC millisecond. */ 358633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long getFromUtcMillis() { 359633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mFromUtcMillis; 360633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 361633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 36295961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the end time of currently managed time range, in UTC millisecond. */ 363633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long getToUtcMillis() { 364633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mToUtcMillis; 365633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 366633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 36795961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the number of the currently managed channels. */ 368633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getChannelCount() { 369633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mFilteredChannels.size(); 370633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 371633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 372633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** 373633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * Returns a {@link Channel} at a given {@code channelIndex} of the currently managed channels. 374633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * Returns {@code null} if such a channel is not found. 375633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko */ 376633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko Channel getChannel(int channelIndex) { 377633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (channelIndex < 0 || channelIndex >= getChannelCount()) { 378633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return null; 379633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 380633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mFilteredChannels.get(channelIndex); 381633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 382633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 383633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** 38495961816a768da387f0b5523cf4363ace2044089Nick Chalko * Returns the index of provided {@link Channel} within the currently managed channels. Returns 38595961816a768da387f0b5523cf4363ace2044089Nick Chalko * -1 if such a channel is not found. 386633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko */ 387633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getChannelIndex(Channel channel) { 388633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mFilteredChannels.indexOf(channel); 389633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 390633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 391633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** 39295961816a768da387f0b5523cf4363ace2044089Nick Chalko * Returns the index of channel with {@code channelId} within the currently managed channels. 393633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * Returns -1 if such a channel is not found. 394633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko */ 395633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getChannelIndex(long channelId) { 396633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return getChannelIndex(mChannelDataManager.getChannel(channelId)); 397633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 398633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 399633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** 400633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * Returns the number of "entries", which lies within the currently managed time range, for a 401633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * given {@code channelId}. 402633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko */ 403633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getTableEntryCount(long channelId) { 404633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mChannelIdEntriesMap.get(channelId).size(); 405633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 406633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 407633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** 408633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * Returns an entry as {@link Program} for a given {@code channelId} and {@code index} of 409633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * entries within the currently managed time range. Returned {@link Program} can be a dummy one 410633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * (e.g., whose channelId is INVALID_ID), when it corresponds to a gap between programs. 411633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko */ 412633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko TableEntry getTableEntry(long channelId, int index) { 413633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mChannelIdEntriesMap.get(channelId).get(index); 414633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 415633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 41695961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns list genre ID's which has a channel. */ 417633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko List<Integer> getFilteredGenreIds() { 418816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mFilteredGenreIds; 419816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 420816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 421633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getSelectedGenreId() { 422816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return mSelectedGenreId; 423816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 424816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 425816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Note that This can be happens only if program guide isn't shown 426816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // because an user has to select channels as browsable through UI. 427d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko private void updateChannels(boolean clearPreviousTableEntries) { 428816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) Log.d(TAG, "updateChannels"); 429816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannels = mChannelDataManager.getBrowsableChannelList(); 430816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mSelectedGenreId = GenreItems.ID_ALL_CHANNELS; 431816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mFilteredChannels = mChannels; 432633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko updateTableEntriesWithoutNotification(clearPreviousTableEntries); 433633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko // Channel update notification should be called after updating table entries, so that 434633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko // the listener can get the entries. 435d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko notifyChannelsUpdated(); 436633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko notifyTableEntriesUpdated(); 437633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko buildGenreFilters(); 438816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 439816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 440d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko private void updateTableEntries(boolean clear) { 441633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko updateTableEntriesWithoutNotification(clear); 442633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko notifyTableEntriesUpdated(); 443633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko buildGenreFilters(); 444633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 445633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 44695961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Updates the table entries without notifying the change. */ 447633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void updateTableEntriesWithoutNotification(boolean clear) { 448816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (clear) { 449816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelIdEntriesMap.clear(); 450816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 45195961816a768da387f0b5523cf4363ace2044089Nick Chalko boolean parentalControlsEnabled = 45295961816a768da387f0b5523cf4363ace2044089Nick Chalko mTvInputManagerHelper.getParentalControlSettings().isParentalControlsEnabled(); 453816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko for (Channel channel : mChannels) { 454816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko long channelId = channel.getId(); 455816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Inline the updating of the mChannelIdEntriesMap here so we can only call 456816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // getParentalControlSettings once. 457816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko List<TableEntry> entries = createProgramEntries(channelId, parentalControlsEnabled); 458816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mChannelIdEntriesMap.put(channelId, entries); 459816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 460816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko int size = entries.size(); 461816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) { 46295961816a768da387f0b5523cf4363ace2044089Nick Chalko Log.d( 46395961816a768da387f0b5523cf4363ace2044089Nick Chalko TAG, 46495961816a768da387f0b5523cf4363ace2044089Nick Chalko "Programs are loaded for channel " 46595961816a768da387f0b5523cf4363ace2044089Nick Chalko + channel.getId() 46695961816a768da387f0b5523cf4363ace2044089Nick Chalko + ", loaded size = " 46795961816a768da387f0b5523cf4363ace2044089Nick Chalko + size); 468816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 469816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (size == 0) { 470816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko continue; 471816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 472816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TableEntry lastEntry = entries.get(size - 1); 473816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mEndUtcMillis < lastEntry.entryEndUtcMillis 474816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko && lastEntry.entryEndUtcMillis != Long.MAX_VALUE) { 475816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mEndUtcMillis = lastEntry.entryEndUtcMillis; 476816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 477816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 478816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mEndUtcMillis > mStartUtcMillis) { 479816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko for (Channel channel : mChannels) { 480816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko long channelId = channel.getId(); 481816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko List<TableEntry> entries = mChannelIdEntriesMap.get(channelId); 482816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (entries.isEmpty()) { 483816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko entries.add(new TableEntry(channelId, mStartUtcMillis, mEndUtcMillis)); 484816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 485816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TableEntry lastEntry = entries.get(entries.size() - 1); 486816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mEndUtcMillis > lastEntry.entryEndUtcMillis) { 48795961816a768da387f0b5523cf4363ace2044089Nick Chalko entries.add( 48895961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 48995961816a768da387f0b5523cf4363ace2044089Nick Chalko channelId, lastEntry.entryEndUtcMillis, mEndUtcMillis)); 490816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else if (lastEntry.entryEndUtcMillis == Long.MAX_VALUE) { 491816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko entries.remove(entries.size() - 1); 49295961816a768da387f0b5523cf4363ace2044089Nick Chalko entries.add( 49395961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 49495961816a768da387f0b5523cf4363ace2044089Nick Chalko lastEntry.channelId, 49595961816a768da387f0b5523cf4363ace2044089Nick Chalko lastEntry.program, 49695961816a768da387f0b5523cf4363ace2044089Nick Chalko lastEntry.scheduledRecording, 49795961816a768da387f0b5523cf4363ace2044089Nick Chalko lastEntry.entryStartUtcMillis, 49895961816a768da387f0b5523cf4363ace2044089Nick Chalko mEndUtcMillis, 49995961816a768da387f0b5523cf4363ace2044089Nick Chalko lastEntry.mIsBlocked)); 500816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 501816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 502816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 503816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 504633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 505721bd0da688cd552737fbb753a00597f95103b95Adrian Roos 506633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** 50795961816a768da387f0b5523cf4363ace2044089Nick Chalko * Build genre filters based on the current programs. This categories channels by its current 50895961816a768da387f0b5523cf4363ace2044089Nick Chalko * program's canonical genres and subsequent @{link resetChannelListWithGenre(int)} calls will 50995961816a768da387f0b5523cf4363ace2044089Nick Chalko * reset channel list with built channel list. This is expected to be called whenever program 51095961816a768da387f0b5523cf4363ace2044089Nick Chalko * guide is shown. 511633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko */ 512633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void buildGenreFilters() { 513633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (DEBUG) Log.d(TAG, "buildGenreFilters"); 514816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 515633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mGenreChannelList.clear(); 516633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (int i = 0; i < GenreItems.getGenreCount(); i++) { 517633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mGenreChannelList.add(new ArrayList<>()); 518816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 519633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (Channel channel : mChannels) { 520633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko Program currentProgram = mProgramDataManager.getCurrentProgram(channel.getId()); 521633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (currentProgram != null && currentProgram.getCanonicalGenres() != null) { 522633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (String genre : currentProgram.getCanonicalGenres()) { 523633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mGenreChannelList.get(GenreItems.getId(genre)).add(channel); 524633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 525633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 526816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 527633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mGenreChannelList.set(GenreItems.ID_ALL_CHANNELS, mChannels); 528633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mFilteredGenreIds.clear(); 529633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mFilteredGenreIds.add(0); 530633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (int i = 1; i < GenreItems.getGenreCount(); i++) { 531633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko if (mGenreChannelList.get(i).size() > 0) { 532633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mFilteredGenreIds.add(i); 533633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 5342e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 535633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mSelectedGenreId = GenreItems.ID_ALL_CHANNELS; 536633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mFilteredChannels = mChannels; 537633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko notifyGenresUpdated(); 5382e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 5392e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 5402e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko @Nullable 5412e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko private TableEntry getTableEntry(ScheduledRecording scheduledRecording) { 5422e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko return getTableEntry(scheduledRecording.getChannelId(), scheduledRecording.getProgramId()); 5432e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 5442e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 5452e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko @Nullable 5462e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko private TableEntry getTableEntry(long channelId, long entryId) { 5472e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko List<TableEntry> entries = mChannelIdEntriesMap.get(channelId); 5482e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko if (entries != null) { 5492e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko for (TableEntry entry : entries) { 5502e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko if (entry.getId() == entryId) { 5512e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko return entry; 5522e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 5532e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 5542e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 5552e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko return null; 5562e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 5572e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 558633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void updateEntry(TableEntry old, TableEntry newEntry) { 559633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko List<TableEntry> entries = mChannelIdEntriesMap.get(old.channelId); 560633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int index = entries.indexOf(old); 561633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko entries.set(index, newEntry); 562633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko notifyTableEntryUpdated(newEntry); 563816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 564816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 565816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private void setTimeRange(long fromUtcMillis, long toUtcMillis) { 566816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (DEBUG) { 56795961816a768da387f0b5523cf4363ace2044089Nick Chalko Log.d( 56895961816a768da387f0b5523cf4363ace2044089Nick Chalko TAG, 56995961816a768da387f0b5523cf4363ace2044089Nick Chalko "setTimeRange. {FromTime=" 57095961816a768da387f0b5523cf4363ace2044089Nick Chalko + Utils.toTimeString(fromUtcMillis) 57195961816a768da387f0b5523cf4363ace2044089Nick Chalko + ", ToTime=" 57295961816a768da387f0b5523cf4363ace2044089Nick Chalko + Utils.toTimeString(toUtcMillis) 57395961816a768da387f0b5523cf4363ace2044089Nick Chalko + "}"); 574816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 575816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (mFromUtcMillis != fromUtcMillis || mToUtcMillis != toUtcMillis) { 576816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mFromUtcMillis = fromUtcMillis; 577816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko mToUtcMillis = toUtcMillis; 578816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko notifyTimeRangeUpdated(); 579816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 580816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 581816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 582816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko private List<TableEntry> createProgramEntries(long channelId, boolean parentalControlsEnabled) { 583816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko List<TableEntry> entries = new ArrayList<>(); 58495961816a768da387f0b5523cf4363ace2044089Nick Chalko boolean channelLocked = 58595961816a768da387f0b5523cf4363ace2044089Nick Chalko parentalControlsEnabled && mChannelDataManager.getChannel(channelId).isLocked(); 586816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (channelLocked) { 587816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko entries.add(new TableEntry(channelId, mStartUtcMillis, Long.MAX_VALUE, true)); 588816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } else { 589816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko long lastProgramEndTime = mStartUtcMillis; 590816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko List<Program> programs = mProgramDataManager.getPrograms(channelId, mStartUtcMillis); 591816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko for (Program program : programs) { 592816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (program.getChannelId() == INVALID_ID) { 593816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Dummy program. 594816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko continue; 595816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 59695961816a768da387f0b5523cf4363ace2044089Nick Chalko long programStartTime = Math.max(program.getStartTimeUtcMillis(), mStartUtcMillis); 597816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko long programEndTime = program.getEndTimeUtcMillis(); 598816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (programStartTime > lastProgramEndTime) { 599816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // Gap since the last program. 60095961816a768da387f0b5523cf4363ace2044089Nick Chalko entries.add(new TableEntry(channelId, lastProgramEndTime, programStartTime)); 601816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko lastProgramEndTime = programStartTime; 602816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 603816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (programEndTime > lastProgramEndTime) { 60495961816a768da387f0b5523cf4363ace2044089Nick Chalko ScheduledRecording scheduledRecording = 60595961816a768da387f0b5523cf4363ace2044089Nick Chalko mDvrDataManager == null 60695961816a768da387f0b5523cf4363ace2044089Nick Chalko ? null 60795961816a768da387f0b5523cf4363ace2044089Nick Chalko : mDvrDataManager.getScheduledRecordingForProgramId( 60895961816a768da387f0b5523cf4363ace2044089Nick Chalko program.getId()); 60995961816a768da387f0b5523cf4363ace2044089Nick Chalko entries.add( 61095961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 61195961816a768da387f0b5523cf4363ace2044089Nick Chalko channelId, 61295961816a768da387f0b5523cf4363ace2044089Nick Chalko program, 61395961816a768da387f0b5523cf4363ace2044089Nick Chalko scheduledRecording, 61495961816a768da387f0b5523cf4363ace2044089Nick Chalko lastProgramEndTime, 61595961816a768da387f0b5523cf4363ace2044089Nick Chalko programEndTime, 61695961816a768da387f0b5523cf4363ace2044089Nick Chalko false)); 617816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko lastProgramEndTime = programEndTime; 618816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 619816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 620816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 621816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 622816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (entries.size() > 1) { 623816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko TableEntry secondEntry = entries.get(1); 624816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko if (secondEntry.entryStartUtcMillis < mStartUtcMillis + FIRST_ENTRY_MIN_DURATION) { 625816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // If the first entry's width doesn't have enough width, it is not good to show 626816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko // the first entry from UI perspective. So we clip it out. 627816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko entries.remove(0); 62895961816a768da387f0b5523cf4363ace2044089Nick Chalko entries.set( 62995961816a768da387f0b5523cf4363ace2044089Nick Chalko 0, 63095961816a768da387f0b5523cf4363ace2044089Nick Chalko new TableEntry( 63195961816a768da387f0b5523cf4363ace2044089Nick Chalko secondEntry.channelId, 63295961816a768da387f0b5523cf4363ace2044089Nick Chalko secondEntry.program, 63395961816a768da387f0b5523cf4363ace2044089Nick Chalko secondEntry.scheduledRecording, 63495961816a768da387f0b5523cf4363ace2044089Nick Chalko mStartUtcMillis, 63595961816a768da387f0b5523cf4363ace2044089Nick Chalko secondEntry.entryEndUtcMillis, 63695961816a768da387f0b5523cf4363ace2044089Nick Chalko secondEntry.mIsBlocked)); 637816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 638816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 639816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko return entries; 640816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 641816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 642633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void notifyGenresUpdated() { 643633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (Listener listener : mListeners) { 644633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko listener.onGenresUpdated(); 645633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 646816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 647816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 648633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void notifyChannelsUpdated() { 649633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (Listener listener : mListeners) { 650633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko listener.onChannelsUpdated(); 651633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 652816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 653816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 654633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void notifyTimeRangeUpdated() { 655633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (Listener listener : mListeners) { 656633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko listener.onTimeRangeUpdated(); 657633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 6582e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 6592e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 660633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void notifyTableEntriesUpdated() { 661633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (TableEntriesUpdatedListener listener : mTableEntriesUpdatedListeners) { 662633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko listener.onTableEntriesUpdated(); 663633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 664633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 665816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 666633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private void notifyTableEntryUpdated(TableEntry entry) { 667633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko for (TableEntryChangedListener listener : mTableEntryChangedListeners) { 668633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko listener.onTableEntryChanged(entry); 669633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 670816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 671816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 672816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko /** 673633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko * Entry for program guide table. An "entry" can be either an actual program or a gap between 67495961816a768da387f0b5523cf4363ace2044089Nick Chalko * programs. This is needed for {@link ProgramListAdapter} because {@link 67595961816a768da387f0b5523cf4363ace2044089Nick Chalko * android.support.v17.leanback.widget.HorizontalGridView} ignores margins between items. 676816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko */ 677633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko static class TableEntry { 678633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** Channel ID which this entry is included. */ 679633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko final long channelId; 680633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 681633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** Program corresponding to the entry. {@code null} means that this entry is a gap. */ 682633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko final Program program; 683633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 684633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko final ScheduledRecording scheduledRecording; 685633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 686633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** Start time of entry in UTC milliseconds. */ 687633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko final long entryStartUtcMillis; 688633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 689633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko /** End time of entry in UTC milliseconds */ 690633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko final long entryEndUtcMillis; 691633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 692633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private final boolean mIsBlocked; 693633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 694633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko private TableEntry(long channelId, long startUtcMillis, long endUtcMillis) { 695633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this(channelId, null, startUtcMillis, endUtcMillis, false); 696816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 697633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 69895961816a768da387f0b5523cf4363ace2044089Nick Chalko private TableEntry( 69995961816a768da387f0b5523cf4363ace2044089Nick Chalko long channelId, long startUtcMillis, long endUtcMillis, boolean blocked) { 700633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this(channelId, null, null, startUtcMillis, endUtcMillis, blocked); 701633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 702633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 70395961816a768da387f0b5523cf4363ace2044089Nick Chalko private TableEntry( 70495961816a768da387f0b5523cf4363ace2044089Nick Chalko long channelId, 70595961816a768da387f0b5523cf4363ace2044089Nick Chalko Program program, 70695961816a768da387f0b5523cf4363ace2044089Nick Chalko long entryStartUtcMillis, 70795961816a768da387f0b5523cf4363ace2044089Nick Chalko long entryEndUtcMillis, 70895961816a768da387f0b5523cf4363ace2044089Nick Chalko boolean isBlocked) { 709633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this(channelId, program, null, entryStartUtcMillis, entryEndUtcMillis, isBlocked); 710633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 711633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 71295961816a768da387f0b5523cf4363ace2044089Nick Chalko private TableEntry( 71395961816a768da387f0b5523cf4363ace2044089Nick Chalko long channelId, 71495961816a768da387f0b5523cf4363ace2044089Nick Chalko Program program, 71595961816a768da387f0b5523cf4363ace2044089Nick Chalko ScheduledRecording scheduledRecording, 71695961816a768da387f0b5523cf4363ace2044089Nick Chalko long entryStartUtcMillis, 71795961816a768da387f0b5523cf4363ace2044089Nick Chalko long entryEndUtcMillis, 71895961816a768da387f0b5523cf4363ace2044089Nick Chalko boolean isBlocked) { 719633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this.channelId = channelId; 720633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this.program = program; 721633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this.scheduledRecording = scheduledRecording; 722633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this.entryStartUtcMillis = entryStartUtcMillis; 723633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko this.entryEndUtcMillis = entryEndUtcMillis; 724633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko mIsBlocked = isBlocked; 725633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 726633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 72795961816a768da387f0b5523cf4363ace2044089Nick Chalko /** A stable id useful for {@link android.support.v7.widget.RecyclerView.Adapter}. */ 728633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long getId() { 729633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko // using a negative entryEndUtcMillis keeps it from conflicting with program Id 730633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return program != null ? program.getId() : -entryEndUtcMillis; 731633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 732633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 73395961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns true if this is a gap. */ 734633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko boolean isGap() { 7350cc0713c1bf8027642987b750b80217569d2932aLive Channels Team return !Program.isProgramValid(program); 736633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 737633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 73895961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns true if this channel is blocked. */ 739633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko boolean isBlocked() { 740633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return mIsBlocked; 741633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 742633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 74395961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns true if this program is on the air. */ 744633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko boolean isCurrentProgram() { 745633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko long current = System.currentTimeMillis(); 746633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return entryStartUtcMillis <= current && entryEndUtcMillis > current; 747633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 748633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 74995961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns if this program has the genre. */ 750633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko boolean hasGenre(int genreId) { 751633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return !isGap() && program.hasGenre(genreId); 752633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 753633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 75495961816a768da387f0b5523cf4363ace2044089Nick Chalko /** Returns the width of table entry, in pixels. */ 755633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko int getWidth() { 756633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return GuideUtils.convertMillisToPixel(entryStartUtcMillis, entryEndUtcMillis); 757633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko } 758633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 759633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko @Override 760633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko public String toString() { 761633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko return "TableEntry{" 76295961816a768da387f0b5523cf4363ace2044089Nick Chalko + "hashCode=" 76395961816a768da387f0b5523cf4363ace2044089Nick Chalko + hashCode() 76495961816a768da387f0b5523cf4363ace2044089Nick Chalko + ", channelId=" 76595961816a768da387f0b5523cf4363ace2044089Nick Chalko + channelId 76695961816a768da387f0b5523cf4363ace2044089Nick Chalko + ", program=" 76795961816a768da387f0b5523cf4363ace2044089Nick Chalko + program 76895961816a768da387f0b5523cf4363ace2044089Nick Chalko + ", startTime=" 76995961816a768da387f0b5523cf4363ace2044089Nick Chalko + Utils.toTimeString(entryStartUtcMillis) 77095961816a768da387f0b5523cf4363ace2044089Nick Chalko + ", endTimeTime=" 77195961816a768da387f0b5523cf4363ace2044089Nick Chalko + Utils.toTimeString(entryEndUtcMillis) 77295961816a768da387f0b5523cf4363ace2044089Nick Chalko + "}"; 773816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 774816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 775816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 7760cc0713c1bf8027642987b750b80217569d2932aLive Channels Team @VisibleForTesting 7770cc0713c1bf8027642987b750b80217569d2932aLive Channels Team public static TableEntry createTableEntryForTest( 7780cc0713c1bf8027642987b750b80217569d2932aLive Channels Team long channelId, 7790cc0713c1bf8027642987b750b80217569d2932aLive Channels Team Program program, 7800cc0713c1bf8027642987b750b80217569d2932aLive Channels Team ScheduledRecording scheduledRecording, 7810cc0713c1bf8027642987b750b80217569d2932aLive Channels Team long entryStartUtcMillis, 7820cc0713c1bf8027642987b750b80217569d2932aLive Channels Team long entryEndUtcMillis, 7830cc0713c1bf8027642987b750b80217569d2932aLive Channels Team boolean isBlocked) { 7840cc0713c1bf8027642987b750b80217569d2932aLive Channels Team return new TableEntry( 7850cc0713c1bf8027642987b750b80217569d2932aLive Channels Team channelId, 7860cc0713c1bf8027642987b750b80217569d2932aLive Channels Team program, 7870cc0713c1bf8027642987b750b80217569d2932aLive Channels Team scheduledRecording, 7880cc0713c1bf8027642987b750b80217569d2932aLive Channels Team entryStartUtcMillis, 7890cc0713c1bf8027642987b750b80217569d2932aLive Channels Team entryEndUtcMillis, 7900cc0713c1bf8027642987b750b80217569d2932aLive Channels Team isBlocked); 7910cc0713c1bf8027642987b750b80217569d2932aLive Channels Team } 7920cc0713c1bf8027642987b750b80217569d2932aLive Channels Team 793633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko interface Listener { 794633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void onGenresUpdated(); 79595961816a768da387f0b5523cf4363ace2044089Nick Chalko 796633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void onChannelsUpdated(); 79795961816a768da387f0b5523cf4363ace2044089Nick Chalko 798633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void onTimeRangeUpdated(); 799816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 800816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 801633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko interface TableEntriesUpdatedListener { 802633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void onTableEntriesUpdated(); 803816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 804816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko 805633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko interface TableEntryChangedListener { 806633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko void onTableEntryChanged(TableEntry entry); 8072e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 8082e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko 809633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko static class ListenerAdapter implements Listener { 810633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko @Override 81195961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onGenresUpdated() {} 812633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 813633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko @Override 81495961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onChannelsUpdated() {} 815633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko 816633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko @Override 81795961816a768da387f0b5523cf4363ace2044089Nick Chalko public void onTimeRangeUpdated() {} 818816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko } 819816a4be1a0f34f6a48877c8afd3dbbca19eac435Nick Chalko} 820