aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/guide/ProgramManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/guide/ProgramManager.java')
-rw-r--r--src/com/android/tv/guide/ProgramManager.java379
1 files changed, 205 insertions, 174 deletions
diff --git a/src/com/android/tv/guide/ProgramManager.java b/src/com/android/tv/guide/ProgramManager.java
index 4ec3f77e..3f20a837 100644
--- a/src/com/android/tv/guide/ProgramManager.java
+++ b/src/com/android/tv/guide/ProgramManager.java
@@ -18,21 +18,20 @@ package com.android.tv.guide;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
-
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.GenreItems;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.DvrScheduleManager.OnConflictStateChangeListener;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -40,9 +39,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-/**
- * Manages the channels and programs for the program guide.
- */
+/** Manages the channels and programs for the program guide. */
@MainThread
public class ProgramManager {
private static final String TAG = "ProgramManager";
@@ -60,7 +57,7 @@ public class ProgramManager {
private final TvInputManagerHelper mTvInputManagerHelper;
private final ChannelDataManager mChannelDataManager;
private final ProgramDataManager mProgramDataManager;
- private final DvrDataManager mDvrDataManager; // Only set if DVR is enabled
+ private final DvrDataManager mDvrDataManager; // Only set if DVR is enabled
private final DvrScheduleManager mDvrScheduleManager;
private long mStartUtcMillis;
@@ -127,51 +124,67 @@ public class ProgramManager {
private final DvrDataManager.ScheduledRecordingListener mScheduledRecordingListener =
new DvrDataManager.ScheduledRecordingListener() {
- @Override
- public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
- for (ScheduledRecording schedule : scheduledRecordings) {
- TableEntry oldEntry = getTableEntry(schedule);
- if (oldEntry != null) {
- TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program,
- schedule, oldEntry.entryStartUtcMillis,
- oldEntry.entryEndUtcMillis, oldEntry.isBlocked());
- updateEntry(oldEntry, newEntry);
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TableEntry oldEntry = getTableEntry(schedule);
+ if (oldEntry != null) {
+ TableEntry newEntry =
+ new TableEntry(
+ oldEntry.channelId,
+ oldEntry.program,
+ schedule,
+ oldEntry.entryStartUtcMillis,
+ oldEntry.entryEndUtcMillis,
+ oldEntry.isBlocked());
+ updateEntry(oldEntry, newEntry);
+ }
+ }
}
- }
- }
- @Override
- public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
- for (ScheduledRecording schedule : scheduledRecordings) {
- TableEntry oldEntry = getTableEntry(schedule);
- if (oldEntry != null) {
- TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program, null,
- oldEntry.entryStartUtcMillis, oldEntry.entryEndUtcMillis,
- oldEntry.isBlocked());
- updateEntry(oldEntry, newEntry);
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TableEntry oldEntry = getTableEntry(schedule);
+ if (oldEntry != null) {
+ TableEntry newEntry =
+ new TableEntry(
+ oldEntry.channelId,
+ oldEntry.program,
+ null,
+ oldEntry.entryStartUtcMillis,
+ oldEntry.entryEndUtcMillis,
+ oldEntry.isBlocked());
+ updateEntry(oldEntry, newEntry);
+ }
+ }
}
- }
- }
- @Override
- public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
- for (ScheduledRecording schedule : scheduledRecordings) {
- TableEntry oldEntry = getTableEntry(schedule);
- if (oldEntry != null) {
- TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program,
- schedule, oldEntry.entryStartUtcMillis,
- oldEntry.entryEndUtcMillis, oldEntry.isBlocked());
- updateEntry(oldEntry, newEntry);
+ @Override
+ public void onScheduledRecordingStatusChanged(
+ ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TableEntry oldEntry = getTableEntry(schedule);
+ if (oldEntry != null) {
+ TableEntry newEntry =
+ new TableEntry(
+ oldEntry.channelId,
+ oldEntry.program,
+ schedule,
+ oldEntry.entryStartUtcMillis,
+ oldEntry.entryEndUtcMillis,
+ oldEntry.isBlocked());
+ updateEntry(oldEntry, newEntry);
+ }
+ }
}
- }
- }
- };
+ };
private final OnConflictStateChangeListener mOnConflictStateChangeListener =
new OnConflictStateChangeListener() {
@Override
- public void onConflictStateChange(boolean conflict,
- ScheduledRecording... schedules) {
+ public void onConflictStateChange(
+ boolean conflict, ScheduledRecording... schedules) {
for (ScheduledRecording schedule : schedules) {
TableEntry entry = getTableEntry(schedule);
if (entry != null) {
@@ -181,8 +194,10 @@ public class ProgramManager {
}
};
- public ProgramManager(TvInputManagerHelper tvInputManagerHelper,
- ChannelDataManager channelDataManager, ProgramDataManager programDataManager,
+ public ProgramManager(
+ TvInputManagerHelper tvInputManagerHelper,
+ ChannelDataManager channelDataManager,
+ ProgramDataManager programDataManager,
@Nullable DvrDataManager dvrDataManager,
@Nullable DvrScheduleManager dvrScheduleManager) {
mTvInputManagerHelper = tvInputManagerHelper;
@@ -221,52 +236,39 @@ public class ProgramManager {
}
}
- /**
- * Adds a {@link Listener}.
- */
+ /** Adds a {@link Listener}. */
void addListener(Listener listener) {
mListeners.add(listener);
}
- /**
- * Registers a listener to be invoked when table entries are updated.
- */
+ /** Registers a listener to be invoked when table entries are updated. */
void addTableEntriesUpdatedListener(TableEntriesUpdatedListener listener) {
mTableEntriesUpdatedListeners.add(listener);
}
- /**
- * Registers a listener to be invoked when a table entry is changed.
- */
+ /** Registers a listener to be invoked when a table entry is changed. */
void addTableEntryChangedListener(TableEntryChangedListener listener) {
mTableEntryChangedListeners.add(listener);
}
- /**
- * Removes a {@link Listener}.
- */
+ /** Removes a {@link Listener}. */
void removeListener(Listener listener) {
mListeners.remove(listener);
}
- /**
- * Removes a previously installed table entries update listener.
- */
+ /** Removes a previously installed table entries update listener. */
void removeTableEntriesUpdatedListener(TableEntriesUpdatedListener listener) {
mTableEntriesUpdatedListeners.remove(listener);
}
- /**
- * Removes a previously installed table entry changed listener.
- */
+ /** Removes a previously installed table entry changed listener. */
void removeTableEntryChangedListener(TableEntryChangedListener listener) {
mTableEntryChangedListeners.remove(listener);
}
/**
- * Resets channel list with given genre.
- * Caller should call {@link #buildGenreFilters()} prior to call this API to make
- * This notifies channel updates to listeners.
+ * Resets channel list with given genre. Caller should call {@link #buildGenreFilters()} prior
+ * to call this API to make This notifies channel updates to listeners.
*/
void resetChannelListWithGenre(int genreId) {
if (genreId == mSelectedGenreId) {
@@ -275,8 +277,14 @@ public class ProgramManager {
mFilteredChannels = mGenreChannelList.get(genreId);
mSelectedGenreId = genreId;
if (DEBUG) {
- Log.d(TAG, "resetChannelListWithGenre: " + GenreItems.getCanonicalGenre(genreId)
- + " has " + mFilteredChannels.size() + " channels out of " + mChannels.size());
+ Log.d(
+ TAG,
+ "resetChannelListWithGenre: "
+ + GenreItems.getCanonicalGenre(genreId)
+ + " has "
+ + mFilteredChannels.size()
+ + " channels out of "
+ + mChannels.size());
}
if (mGenreChannelList.get(mSelectedGenreId) == null) {
throw new IllegalStateException("Genre filter isn't ready.");
@@ -284,9 +292,7 @@ public class ProgramManager {
notifyChannelsUpdated();
}
- /**
- * Update the initial time range to manage. It updates program entries and genre as well.
- */
+ /** Update the initial time range to manage. It updates program entries and genre as well. */
void updateInitialTimeRange(long startUtcMillis, long endUtcMillis) {
mStartUtcMillis = startUtcMillis;
if (endUtcMillis > mEndUtcMillis) {
@@ -298,10 +304,7 @@ public class ProgramManager {
setTimeRange(startUtcMillis, endUtcMillis);
}
-
- /**
- * Shifts the time range by the given time. Also makes ProgramGuide scroll the views.
- */
+ /** Shifts the time range by the given time. Also makes ProgramGuide scroll the views. */
void shiftTime(long timeMillisToScroll) {
long fromUtcMillis = mFromUtcMillis + timeMillisToScroll;
long toUtcMillis = mToUtcMillis + timeMillisToScroll;
@@ -316,23 +319,17 @@ public class ProgramManager {
setTimeRange(fromUtcMillis, toUtcMillis);
}
- /**
- * Returned the scrolled(shifted) time in milliseconds.
- */
+ /** Returned the scrolled(shifted) time in milliseconds. */
long getShiftedTime() {
return mFromUtcMillis - mStartUtcMillis;
}
- /**
- * Returns the start time set by {@link #updateInitialTimeRange}.
- */
+ /** Returns the start time set by {@link #updateInitialTimeRange}. */
long getStartTime() {
return mStartUtcMillis;
}
- /**
- * Returns the program index of the program with {@code entryId} or -1 if not found.
- */
+ /** Returns the program index of the program with {@code entryId} or -1 if not found. */
int getProgramIdIndex(long channelId, long entryId) {
List<TableEntry> entries = mChannelIdEntriesMap.get(channelId);
if (entries != null) {
@@ -345,38 +342,29 @@ public class ProgramManager {
return -1;
}
- /**
- * Returns the program index of the program at {@code time} or -1 if not found.
- */
+ /** Returns the program index of the program at {@code time} or -1 if not found. */
int getProgramIndexAtTime(long channelId, long time) {
List<TableEntry> entries = mChannelIdEntriesMap.get(channelId);
for (int i = 0; i < entries.size(); ++i) {
TableEntry entry = entries.get(i);
- if (entry.entryStartUtcMillis <= time
- && time < entry.entryEndUtcMillis) {
+ if (entry.entryStartUtcMillis <= time && time < entry.entryEndUtcMillis) {
return i;
}
}
return -1;
}
- /**
- * Returns the start time of currently managed time range, in UTC millisecond.
- */
+ /** Returns the start time of currently managed time range, in UTC millisecond. */
long getFromUtcMillis() {
return mFromUtcMillis;
}
- /**
- * Returns the end time of currently managed time range, in UTC millisecond.
- */
+ /** Returns the end time of currently managed time range, in UTC millisecond. */
long getToUtcMillis() {
return mToUtcMillis;
}
- /**
- * Returns the number of the currently managed channels.
- */
+ /** Returns the number of the currently managed channels. */
int getChannelCount() {
return mFilteredChannels.size();
}
@@ -393,15 +381,15 @@ public class ProgramManager {
}
/**
- * Returns the index of provided {@link Channel} within the currently managed channels.
- * Returns -1 if such a channel is not found.
+ * Returns the index of provided {@link Channel} within the currently managed channels. Returns
+ * -1 if such a channel is not found.
*/
int getChannelIndex(Channel channel) {
return mFilteredChannels.indexOf(channel);
}
/**
- * Returns the index of channel with {@code channelId} within the currently managed channels.
+ * Returns the index of channel with {@code channelId} within the currently managed channels.
* Returns -1 if such a channel is not found.
*/
int getChannelIndex(long channelId) {
@@ -425,9 +413,7 @@ public class ProgramManager {
return mChannelIdEntriesMap.get(channelId).get(index);
}
- /**
- * Returns list genre ID's which has a channel.
- */
+ /** Returns list genre ID's which has a channel. */
List<Integer> getFilteredGenreIds() {
return mFilteredGenreIds;
}
@@ -457,15 +443,13 @@ public class ProgramManager {
buildGenreFilters();
}
- /**
- * Updates the table entries without notifying the change.
- */
+ /** Updates the table entries without notifying the change. */
private void updateTableEntriesWithoutNotification(boolean clear) {
if (clear) {
mChannelIdEntriesMap.clear();
}
- boolean parentalControlsEnabled = mTvInputManagerHelper.getParentalControlSettings()
- .isParentalControlsEnabled();
+ boolean parentalControlsEnabled =
+ mTvInputManagerHelper.getParentalControlSettings().isParentalControlsEnabled();
for (Channel channel : mChannels) {
long channelId = channel.getId();
// Inline the updating of the mChannelIdEntriesMap here so we can only call
@@ -475,8 +459,12 @@ public class ProgramManager {
int size = entries.size();
if (DEBUG) {
- Log.d(TAG, "Programs are loaded for channel " + channel.getId()
- + ", loaded size = " + size);
+ Log.d(
+ TAG,
+ "Programs are loaded for channel "
+ + channel.getId()
+ + ", loaded size = "
+ + size);
}
if (size == 0) {
continue;
@@ -496,14 +484,19 @@ public class ProgramManager {
} else {
TableEntry lastEntry = entries.get(entries.size() - 1);
if (mEndUtcMillis > lastEntry.entryEndUtcMillis) {
- entries.add(new TableEntry(channelId, lastEntry.entryEndUtcMillis,
- mEndUtcMillis));
+ entries.add(
+ new TableEntry(
+ channelId, lastEntry.entryEndUtcMillis, mEndUtcMillis));
} else if (lastEntry.entryEndUtcMillis == Long.MAX_VALUE) {
entries.remove(entries.size() - 1);
- entries.add(new TableEntry(lastEntry.channelId, lastEntry.program,
- lastEntry.scheduledRecording,
- lastEntry.entryStartUtcMillis, mEndUtcMillis,
- lastEntry.mIsBlocked));
+ entries.add(
+ new TableEntry(
+ lastEntry.channelId,
+ lastEntry.program,
+ lastEntry.scheduledRecording,
+ lastEntry.entryStartUtcMillis,
+ mEndUtcMillis,
+ lastEntry.mIsBlocked));
}
}
}
@@ -511,11 +504,10 @@ public class ProgramManager {
}
/**
- * Build genre filters based on the current programs.
- * This categories channels by its current program's canonical genres
- * and subsequent @{link resetChannelListWithGenre(int)} calls will reset channel list
- * with built channel list.
- * This is expected to be called whenever program guide is shown.
+ * Build genre filters based on the current programs. This categories channels by its current
+ * program's canonical genres and subsequent @{link resetChannelListWithGenre(int)} calls will
+ * reset channel list with built channel list. This is expected to be called whenever program
+ * guide is shown.
*/
private void buildGenreFilters() {
if (DEBUG) Log.d(TAG, "buildGenreFilters");
@@ -572,9 +564,13 @@ public class ProgramManager {
private void setTimeRange(long fromUtcMillis, long toUtcMillis) {
if (DEBUG) {
- Log.d(TAG, "setTimeRange. {FromTime="
- + Utils.toTimeString(fromUtcMillis) + ", ToTime="
- + Utils.toTimeString(toUtcMillis) + "}");
+ Log.d(
+ TAG,
+ "setTimeRange. {FromTime="
+ + Utils.toTimeString(fromUtcMillis)
+ + ", ToTime="
+ + Utils.toTimeString(toUtcMillis)
+ + "}");
}
if (mFromUtcMillis != fromUtcMillis || mToUtcMillis != toUtcMillis) {
mFromUtcMillis = fromUtcMillis;
@@ -585,8 +581,8 @@ public class ProgramManager {
private List<TableEntry> createProgramEntries(long channelId, boolean parentalControlsEnabled) {
List<TableEntry> entries = new ArrayList<>();
- boolean channelLocked = parentalControlsEnabled
- && mChannelDataManager.getChannel(channelId).isLocked();
+ boolean channelLocked =
+ parentalControlsEnabled && mChannelDataManager.getChannel(channelId).isLocked();
if (channelLocked) {
entries.add(new TableEntry(channelId, mStartUtcMillis, Long.MAX_VALUE, true));
} else {
@@ -597,20 +593,27 @@ public class ProgramManager {
// Dummy program.
continue;
}
- long programStartTime = Math.max(program.getStartTimeUtcMillis(),
- mStartUtcMillis);
+ long programStartTime = Math.max(program.getStartTimeUtcMillis(), mStartUtcMillis);
long programEndTime = program.getEndTimeUtcMillis();
if (programStartTime > lastProgramEndTime) {
// Gap since the last program.
- entries.add(new TableEntry(channelId, lastProgramEndTime,
- programStartTime));
+ entries.add(new TableEntry(channelId, lastProgramEndTime, programStartTime));
lastProgramEndTime = programStartTime;
}
if (programEndTime > lastProgramEndTime) {
- ScheduledRecording scheduledRecording = mDvrDataManager == null ? null
- : mDvrDataManager.getScheduledRecordingForProgramId(program.getId());
- entries.add(new TableEntry(channelId, program, scheduledRecording,
- lastProgramEndTime, programEndTime, false));
+ ScheduledRecording scheduledRecording =
+ mDvrDataManager == null
+ ? null
+ : mDvrDataManager.getScheduledRecordingForProgramId(
+ program.getId());
+ entries.add(
+ new TableEntry(
+ channelId,
+ program,
+ scheduledRecording,
+ lastProgramEndTime,
+ programEndTime,
+ false));
lastProgramEndTime = programEndTime;
}
}
@@ -622,9 +625,15 @@ public class ProgramManager {
// If the first entry's width doesn't have enough width, it is not good to show
// the first entry from UI perspective. So we clip it out.
entries.remove(0);
- entries.set(0, new TableEntry(secondEntry.channelId, secondEntry.program,
- secondEntry.scheduledRecording, mStartUtcMillis,
- secondEntry.entryEndUtcMillis, secondEntry.mIsBlocked));
+ entries.set(
+ 0,
+ new TableEntry(
+ secondEntry.channelId,
+ secondEntry.program,
+ secondEntry.scheduledRecording,
+ mStartUtcMillis,
+ secondEntry.entryEndUtcMillis,
+ secondEntry.mIsBlocked));
}
}
return entries;
@@ -662,8 +671,8 @@ public class ProgramManager {
/**
* Entry for program guide table. An "entry" can be either an actual program or a gap between
- * programs. This is needed for {@link ProgramListAdapter} because
- * {@link android.support.v17.leanback.widget.HorizontalGridView} ignores margins between items.
+ * programs. This is needed for {@link ProgramListAdapter} because {@link
+ * android.support.v17.leanback.widget.HorizontalGridView} ignores margins between items.
*/
static class TableEntry {
/** Channel ID which this entry is included. */
@@ -686,18 +695,27 @@ public class ProgramManager {
this(channelId, null, startUtcMillis, endUtcMillis, false);
}
- private TableEntry(long channelId, long startUtcMillis, long endUtcMillis,
- boolean blocked) {
+ private TableEntry(
+ long channelId, long startUtcMillis, long endUtcMillis, boolean blocked) {
this(channelId, null, null, startUtcMillis, endUtcMillis, blocked);
}
- private TableEntry(long channelId, Program program, long entryStartUtcMillis,
- long entryEndUtcMillis, boolean isBlocked) {
+ private TableEntry(
+ long channelId,
+ Program program,
+ long entryStartUtcMillis,
+ long entryEndUtcMillis,
+ boolean isBlocked) {
this(channelId, program, null, entryStartUtcMillis, entryEndUtcMillis, isBlocked);
}
- private TableEntry(long channelId, Program program, ScheduledRecording scheduledRecording,
- long entryStartUtcMillis, long entryEndUtcMillis, boolean isBlocked) {
+ private TableEntry(
+ long channelId,
+ Program program,
+ ScheduledRecording scheduledRecording,
+ long entryStartUtcMillis,
+ long entryEndUtcMillis,
+ boolean isBlocked) {
this.channelId = channelId;
this.program = program;
this.scheduledRecording = scheduledRecording;
@@ -706,46 +724,34 @@ public class ProgramManager {
mIsBlocked = isBlocked;
}
- /**
- * A stable id useful for {@link android.support.v7.widget.RecyclerView.Adapter}.
- */
+ /** A stable id useful for {@link android.support.v7.widget.RecyclerView.Adapter}. */
long getId() {
// using a negative entryEndUtcMillis keeps it from conflicting with program Id
return program != null ? program.getId() : -entryEndUtcMillis;
}
- /**
- * Returns true if this is a gap.
- */
+ /** Returns true if this is a gap. */
boolean isGap() {
- return !Program.isValid(program);
+ return !Program.isProgramValid(program);
}
- /**
- * Returns true if this channel is blocked.
- */
+ /** Returns true if this channel is blocked. */
boolean isBlocked() {
return mIsBlocked;
}
- /**
- * Returns true if this program is on the air.
- */
+ /** Returns true if this program is on the air. */
boolean isCurrentProgram() {
long current = System.currentTimeMillis();
return entryStartUtcMillis <= current && entryEndUtcMillis > current;
}
- /**
- * Returns if this program has the genre.
- */
+ /** Returns if this program has the genre. */
boolean hasGenre(int genreId) {
return !isGap() && program.hasGenre(genreId);
}
- /**
- * Returns the width of table entry, in pixels.
- */
+ /** Returns the width of table entry, in pixels. */
int getWidth() {
return GuideUtils.convertMillisToPixel(entryStartUtcMillis, entryEndUtcMillis);
}
@@ -753,17 +759,42 @@ public class ProgramManager {
@Override
public String toString() {
return "TableEntry{"
- + "hashCode=" + hashCode()
- + ", channelId=" + channelId
- + ", program=" + program
- + ", startTime=" + Utils.toTimeString(entryStartUtcMillis)
- + ", endTimeTime=" + Utils.toTimeString(entryEndUtcMillis) + "}";
- }
+ + "hashCode="
+ + hashCode()
+ + ", channelId="
+ + channelId
+ + ", program="
+ + program
+ + ", startTime="
+ + Utils.toTimeString(entryStartUtcMillis)
+ + ", endTimeTime="
+ + Utils.toTimeString(entryEndUtcMillis)
+ + "}";
+ }
+ }
+
+ @VisibleForTesting
+ public static TableEntry createTableEntryForTest(
+ long channelId,
+ Program program,
+ ScheduledRecording scheduledRecording,
+ long entryStartUtcMillis,
+ long entryEndUtcMillis,
+ boolean isBlocked) {
+ return new TableEntry(
+ channelId,
+ program,
+ scheduledRecording,
+ entryStartUtcMillis,
+ entryEndUtcMillis,
+ isBlocked);
}
interface Listener {
void onGenresUpdated();
+
void onChannelsUpdated();
+
void onTimeRangeUpdated();
}
@@ -777,12 +808,12 @@ public class ProgramManager {
static class ListenerAdapter implements Listener {
@Override
- public void onGenresUpdated() { }
+ public void onGenresUpdated() {}
@Override
- public void onChannelsUpdated() { }
+ public void onChannelsUpdated() {}
@Override
- public void onTimeRangeUpdated() { }
+ public void onTimeRangeUpdated() {}
}
}