diff options
author | Nick Chalko <nchalko@google.com> | 2016-08-31 16:00:31 -0700 |
---|---|---|
committer | Nick Chalko <nchalko@google.com> | 2016-09-07 05:38:33 -0700 |
commit | 65fda1eaa94968bb55d5ded10dcb0b3f37fb05f2 (patch) | |
tree | ffc8e4c5a71c130d3782bf03e674f9d77ca77f72 /src/com/android/tv/dvr/DvrDataManagerImpl.java | |
parent | ad819718f80e796cf039f96537b5c8cd127c042b (diff) | |
download | TV-65fda1eaa94968bb55d5ded10dcb0b3f37fb05f2.tar.gz |
Sync to ub-tv-dev at http://ag/1415258
Bug: 30970843
Change-Id: I0aa43094d103de28956a3d9b56a594ea46a20543
Diffstat (limited to 'src/com/android/tv/dvr/DvrDataManagerImpl.java')
-rw-r--r-- | src/com/android/tv/dvr/DvrDataManagerImpl.java | 578 |
1 files changed, 411 insertions, 167 deletions
diff --git a/src/com/android/tv/dvr/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java index 02c47750..5ae2c4ea 100644 --- a/src/com/android/tv/dvr/DvrDataManagerImpl.java +++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java @@ -21,8 +21,7 @@ import android.content.ContentResolver; import android.content.ContentUris; import android.content.Context; import android.database.ContentObserver; -import android.database.Cursor; -import android.media.tv.TvContract; +import android.media.tv.TvContract.RecordedPrograms; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; @@ -31,23 +30,34 @@ import android.os.Looper; import android.support.annotation.MainThread; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Range; +import com.android.tv.TvApplication; import com.android.tv.common.SoftPreconditions; -import com.android.tv.common.recording.RecordedProgram; +import com.android.tv.data.ChannelDataManager; import com.android.tv.dvr.ScheduledRecording.RecordingState; -import com.android.tv.dvr.provider.AsyncDvrDbTask; -import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQueryTask; -import com.android.tv.util.AsyncDbTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncAddScheduleTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncAddSeriesRecordingTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDeleteScheduleTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDeleteSeriesRecordingTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQueryScheduleTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQuerySeriesRecordingTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncUpdateScheduleTask; +import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncUpdateSeriesRecordingTask; +import com.android.tv.util.AsyncDbTask.AsyncRecordedProgramQueryTask; import com.android.tv.util.Clock; +import com.android.tv.util.TvProviderUriMatcher; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import java.util.Set; /** @@ -60,66 +70,67 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { private static final boolean DEBUG = false; private final HashMap<Long, ScheduledRecording> mScheduledRecordings = new HashMap<>(); + private final HashMap<Long, RecordedProgram> mRecordedPrograms = new HashMap<>(); + private final HashMap<Long, SeriesRecording> mSeriesRecordings = new HashMap<>(); private final HashMap<Long, ScheduledRecording> mProgramId2ScheduledRecordings = new HashMap<>(); - private final HashMap<Long, RecordedProgram> mRecordedPrograms = new HashMap<>(); + private final HashMap<String, SeriesRecording> mSeriesId2SeriesRecordings = new HashMap<>(); private final Context mContext; - private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); - private final ContentObserver mContentObserver = new ContentObserver(mMainThreadHandler) { - + private final ContentObserver mContentObserver = new ContentObserver(new Handler( + Looper.getMainLooper())) { @Override public void onChange(boolean selfChange) { onChange(selfChange, null); } @Override - public void onChange(boolean selfChange, @Nullable final Uri uri) { - if (uri == null) { - // TODO reload everything. - } - AsyncRecordedProgramQueryTask task = new AsyncRecordedProgramQueryTask( + public void onChange(boolean selfChange, final @Nullable Uri uri) { + RecordedProgramsQueryTask task = new RecordedProgramsQueryTask( mContext.getContentResolver(), uri); task.executeOnDbThread(); mPendingTasks.add(task); } }; - private void onObservedChange(Uri uri, RecordedProgram recordedProgram) { - long id = ContentUris.parseId(uri); - if (DEBUG) { - Log.d(TAG, "changed recorded program #" + id + " to " + recordedProgram); - } - if (recordedProgram == null) { - RecordedProgram old = mRecordedPrograms.remove(id); - if (old != null) { - notifyRecordedProgramRemoved(old); - } else { - Log.w(TAG, "Could not find old version of deleted program #" + id); - } - } else { - RecordedProgram old = mRecordedPrograms.put(id, recordedProgram); - if (old == null) { - notifyRecordedProgramAdded(recordedProgram); - } else { - notifyRecordedProgramChanged(recordedProgram); - } - } - } - private boolean mDvrLoadFinished; private boolean mRecordedProgramLoadFinished; private final Set<AsyncTask> mPendingTasks = new ArraySet<>(); + private final DvrDbSync mDbSync; public DvrDataManagerImpl(Context context, Clock clock) { super(context, clock); mContext = context; + mDbSync = new DvrDbSync(context, this); } public void start() { - AsyncDvrQueryTask mDvrQueryTask = new AsyncDvrQueryTask(mContext) { + AsyncDvrQuerySeriesRecordingTask dvrQuerySeriesRecordingTask + = new AsyncDvrQuerySeriesRecordingTask(mContext) { + @Override + protected void onCancelled(List<SeriesRecording> seriesRecordings) { + mPendingTasks.remove(this); + } @Override + protected void onPostExecute(List<SeriesRecording> seriesRecordings) { + mPendingTasks.remove(this); + long maxId = 0; + for (SeriesRecording r : seriesRecordings) { + mSeriesRecordings.put(r.getId(), r); + mSeriesId2SeriesRecordings.put(r.getSeriesId(), r); + if (maxId < r.getId()) { + maxId = r.getId(); + } + } + IdGenerator.SERIES_RECORDING.setMaxId(maxId); + } + }; + dvrQuerySeriesRecordingTask.executeOnDbThread(); + mPendingTasks.add(dvrQuerySeriesRecordingTask); + AsyncDvrQueryScheduleTask dvrQueryRecordingTask + = new AsyncDvrQueryScheduleTask(mContext) { + @Override protected void onCancelled(List<ScheduledRecording> scheduledRecordings) { mPendingTasks.remove(this); } @@ -127,22 +138,63 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { @Override protected void onPostExecute(List<ScheduledRecording> result) { mPendingTasks.remove(this); - mDvrLoadFinished = true; + long maxId = 0; + List<ScheduledRecording> toUpdate = new ArrayList<>(); for (ScheduledRecording r : result) { - mScheduledRecordings.put(r.getId(), r); + if (r.getState() == ScheduledRecording.STATE_RECORDING_DELETED) { + getDeletedScheduleMap().put(r.getProgramId(), r); + } else { + mScheduledRecordings.put(r.getId(), r); + if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) { + mProgramId2ScheduledRecordings.put(r.getProgramId(), r); + } + // Adjust the state of the schedules before DB loading is finished. + if (r.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) { + if (r.getEndTimeMs() <= mClock.currentTimeMillis()) { + toUpdate.add(ScheduledRecording.buildFrom(r) + .setState(ScheduledRecording.STATE_RECORDING_FAILED) + .build()); + } else { + toUpdate.add(ScheduledRecording.buildFrom(r) + .setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED) + .build()); + } + } else if (r.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) { + if (r.getEndTimeMs() <= mClock.currentTimeMillis()) { + toUpdate.add(ScheduledRecording.buildFrom(r) + .setState(ScheduledRecording.STATE_RECORDING_FAILED) + .build()); + } + } + } + if (maxId < r.getId()) { + maxId = r.getId(); + } + } + if (!toUpdate.isEmpty()) { + updateScheduledRecording(true, ScheduledRecording.toArray(toUpdate)); + } + IdGenerator.SCHEDULED_RECORDING.setMaxId(maxId); + mDvrLoadFinished = true; + notifyDvrScheduleLoadFinished(); + mDbSync.start(); + if (isInitialized()) { + SeriesRecordingScheduler.getInstance(mContext).start(); } } }; - mDvrQueryTask.executeOnDbThread(); - mPendingTasks.add(mDvrQueryTask); - AsyncRecordedProgramsQueryTask mRecordedProgramQueryTask = - new AsyncRecordedProgramsQueryTask(mContext.getContentResolver()); + dvrQueryRecordingTask.executeOnDbThread(); + mPendingTasks.add(dvrQueryRecordingTask); + RecordedProgramsQueryTask mRecordedProgramQueryTask = + new RecordedProgramsQueryTask(mContext.getContentResolver(), null); mRecordedProgramQueryTask.executeOnDbThread(); ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver(TvContract.RecordedPrograms.CONTENT_URI, true, mContentObserver); + cr.registerContentObserver(RecordedPrograms.CONTENT_URI, true, mContentObserver); } public void stop() { + SeriesRecordingScheduler.getInstance(mContext).stop(); + mDbSync.stop(); ContentResolver cr = mContext.getContentResolver(); cr.unregisterContentObserver(mContentObserver); Iterator<AsyncTask> i = mPendingTasks.iterator(); @@ -153,11 +205,80 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } } + private void onRecordedProgramsLoadedFinished(Uri uri, List<RecordedProgram> recordedPrograms) { + if (uri == null) { + uri = RecordedPrograms.CONTENT_URI; + } + int match = TvProviderUriMatcher.match(uri); + if (match == TvProviderUriMatcher.MATCH_RECORDED_PROGRAM) { + if (!mRecordedProgramLoadFinished) { + for (RecordedProgram recorded : recordedPrograms) { + mRecordedPrograms.put(recorded.getId(), recorded); + } + mRecordedProgramLoadFinished = true; + notifyRecordedProgramLoadFinished(); + } else if (recordedPrograms == null || recordedPrograms.isEmpty()) { + for (RecordedProgram recorded : mRecordedPrograms.values()) { + notifyRecordedProgramRemoved(recorded); + } + mRecordedPrograms.clear(); + } else { + HashMap<Long, RecordedProgram> oldRecordedPrograms + = new HashMap<>(mRecordedPrograms); + mRecordedPrograms.clear(); + for (RecordedProgram recorded : recordedPrograms) { + mRecordedPrograms.put(recorded.getId(), recorded); + RecordedProgram old = oldRecordedPrograms.remove(recorded.getId()); + if (old == null) { + notifyRecordedProgramAdded(recorded); + } else { + notifyRecordedProgramChanged(recorded); + } + } + for (RecordedProgram recorded : oldRecordedPrograms.values()) { + notifyRecordedProgramRemoved(recorded); + } + } + if (isInitialized()) { + SeriesRecordingScheduler.getInstance(mContext).start(); + } + } else if (match == TvProviderUriMatcher.MATCH_RECORDED_PROGRAM_ID) { + long id = ContentUris.parseId(uri); + if (DEBUG) Log.d(TAG, "changed recorded program #" + id + " to " + recordedPrograms); + if (recordedPrograms == null || recordedPrograms.isEmpty()) { + RecordedProgram old = mRecordedPrograms.remove(id); + if (old != null) { + notifyRecordedProgramRemoved(old); + } else { + Log.w(TAG, "Could not find old version of deleted program #" + id); + } + } else { + RecordedProgram newRecorded = recordedPrograms.get(0); + RecordedProgram old = mRecordedPrograms.put(id, newRecorded); + if (old == null) { + notifyRecordedProgramAdded(newRecorded); + } else { + notifyRecordedProgramChanged(newRecorded); + } + } + } + } + @Override public boolean isInitialized() { return mDvrLoadFinished && mRecordedProgramLoadFinished; } + @Override + public boolean isDvrScheduleLoadFinished() { + return mDvrLoadFinished; + } + + @Override + public boolean isRecordedProgramLoadFinished() { + return mRecordedProgramLoadFinished; + } + private List<ScheduledRecording> getScheduledRecordingsPrograms() { if (!mDvrLoadFinished) { return Collections.emptyList(); @@ -177,24 +298,50 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } @Override + public List<RecordedProgram> getRecordedPrograms(long seriesRecordingId) { + SeriesRecording seriesRecording = getSeriesRecording(seriesRecordingId); + if (!mRecordedProgramLoadFinished || seriesRecording == null) { + return Collections.emptyList(); + } + return super.getRecordedPrograms(seriesRecordingId); + } + + @Override public List<ScheduledRecording> getAllScheduledRecordings() { return new ArrayList<>(mScheduledRecordings.values()); } - protected List<ScheduledRecording> getRecordingsWithState(@RecordingState int state) { + @Override + protected List<ScheduledRecording> getRecordingsWithState(@RecordingState int... states) { List<ScheduledRecording> result = new ArrayList<>(); for (ScheduledRecording r : mScheduledRecordings.values()) { - if (r.getState() == state) { - result.add(r); + for (int state : states) { + if (r.getState() == state) { + result.add(r); + break; + } } } return result; } @Override - public List<SeasonRecording> getSeasonRecordings() { - // If we return dummy data here, we can implement UI part independently. - return Collections.emptyList(); + public List<SeriesRecording> getSeriesRecordings() { + if (!mDvrLoadFinished) { + return Collections.emptyList(); + } + return new ArrayList<>(mSeriesRecordings.values()); + } + + @Override + public List<SeriesRecording> getSeriesRecordings(String inputId) { + List<SeriesRecording> result = new ArrayList<>(); + for (SeriesRecording r : mSeriesRecordings.values()) { + if (TextUtils.equals(r.getInputId(), inputId)) { + result.add(r); + } + } + return result; } @Override @@ -219,10 +366,33 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { } @Override - public List<ScheduledRecording> getRecordingsThatOverlapWith(Range<Long> period) { + public List<ScheduledRecording> getScheduledRecordings(Range<Long> period, + @RecordingState int state) { List<ScheduledRecording> result = new ArrayList<>(); for (ScheduledRecording r : mScheduledRecordings.values()) { - if (r.isOverLapping(period)) { + if (r.isOverLapping(period) && r.getState() == state) { + result.add(r); + } + } + return result; + } + + @Override + public List<ScheduledRecording> getScheduledRecordings(long seriesRecordingId) { + List<ScheduledRecording> result = new ArrayList<>(); + for (ScheduledRecording r : mScheduledRecordings.values()) { + if (r.getSeriesRecordingId() == seriesRecordingId) { + result.add(r); + } + } + return result; + } + + @Override + public List<ScheduledRecording> getScheduledRecordings(String inputId) { + List<ScheduledRecording> result = new ArrayList<>(); + for (ScheduledRecording r : mScheduledRecordings.values()) { + if (TextUtils.equals(r.getInputId(), inputId)) { result.add(r); } } @@ -232,19 +402,13 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { @Nullable @Override public ScheduledRecording getScheduledRecording(long recordingId) { - if (mDvrLoadFinished) { - return mScheduledRecordings.get(recordingId); - } - return null; + return mScheduledRecordings.get(recordingId); } @Nullable @Override public ScheduledRecording getScheduledRecordingForProgramId(long programId) { - if (mDvrLoadFinished) { - return mProgramId2ScheduledRecordings.get(programId); - } - return null; + return mProgramId2ScheduledRecordings.get(programId); } @Nullable @@ -253,151 +417,231 @@ public class DvrDataManagerImpl extends BaseDvrDataManager { return mRecordedPrograms.get(recordingId); } + @Nullable @Override - public void addScheduledRecording(final ScheduledRecording scheduledRecording) { - new AsyncDvrDbTask.AsyncAddRecordingTask(mContext) { - @Override - protected void onPostExecute(List<ScheduledRecording> scheduledRecordings) { - super.onPostExecute(scheduledRecordings); - SoftPreconditions.checkArgument(scheduledRecordings.size() == 1); - for (ScheduledRecording r : scheduledRecordings) { - if (r.getId() != -1) { - mScheduledRecordings.put(r.getId(), r); - if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) { - mProgramId2ScheduledRecordings.put(r.getProgramId(), r); - } - notifyScheduledRecordingAdded(r); - } else { - Log.w(TAG, "Error adding " + r); - } - } + public SeriesRecording getSeriesRecording(long seriesRecordingId) { + return mSeriesRecordings.get(seriesRecordingId); + } + @Nullable + @Override + public SeriesRecording getSeriesRecording(String seriesId) { + return mSeriesId2SeriesRecordings.get(seriesId); + } + + @Override + public void addScheduledRecording(ScheduledRecording... schedules) { + for (ScheduledRecording r : schedules) { + r.setId(IdGenerator.SCHEDULED_RECORDING.newId()); + mScheduledRecordings.put(r.getId(), r); + if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) { + mProgramId2ScheduledRecordings.put(r.getProgramId(), r); } - }.executeOnDbThread(scheduledRecording); + } + if (mDvrLoadFinished) { + notifyScheduledRecordingAdded(schedules); + } + new AsyncAddScheduleTask(mContext).executeOnDbThread(schedules); + removeDeletedSchedules(schedules); } @Override - public void addSeasonRecording(SeasonRecording seasonRecording) { } + public void addSeriesRecording(SeriesRecording... seriesRecordings) { + for (SeriesRecording r : seriesRecordings) { + r.setId(IdGenerator.SERIES_RECORDING.newId()); + mSeriesRecordings.put(r.getId(), r); + mSeriesId2SeriesRecordings.put(r.getSeriesId(), r); + } + if (mDvrLoadFinished) { + notifySeriesRecordingAdded(seriesRecordings); + } + new AsyncAddSeriesRecordingTask(mContext).executeOnDbThread(seriesRecordings); + } @Override - public void removeScheduledRecording(final ScheduledRecording scheduledRecording) { - new AsyncDvrDbTask.AsyncDeleteRecordingTask(mContext) { - @Override - protected void onPostExecute(List<Integer> counts) { - super.onPostExecute(counts); - SoftPreconditions.checkArgument(counts.size() == 1); - for (Integer c : counts) { - if (c == 1) { - mScheduledRecordings.remove(scheduledRecording.getId()); - if (scheduledRecording.getProgramId() != ScheduledRecording.ID_NOT_SET) { - mProgramId2ScheduledRecordings - .remove(scheduledRecording.getProgramId()); - } - //TODO change to notifyRecordingUpdated - notifyScheduledRecordingRemoved(scheduledRecording); - } else { - Log.w(TAG, "Error removing " + scheduledRecording); - } - } + public void removeScheduledRecording(ScheduledRecording... schedules) { + removeScheduledRecording(false, schedules); + } + private void removeScheduledRecording(boolean forceDelete, ScheduledRecording... schedules) { + List<ScheduledRecording> schedulesToDelete = new ArrayList<>(); + List<ScheduledRecording> schedulesNotToDelete = new ArrayList<>(); + for (ScheduledRecording r : schedules) { + mScheduledRecordings.remove(r.getId()); + if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) { + mProgramId2ScheduledRecordings.remove(r.getProgramId()); } - }.executeOnDbThread(scheduledRecording); + // If it belongs to the series recording and it's not started yet, do not delete. + // Instead mark deleted. + if (!forceDelete && r.getSeriesRecordingId() != SeriesRecording.ID_NOT_SET + && r.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) { + SoftPreconditions.checkState(r.getProgramId() != ScheduledRecording.ID_NOT_SET); + ScheduledRecording deleted = ScheduledRecording.buildFrom(r) + .setState(ScheduledRecording.STATE_RECORDING_DELETED).build(); + getDeletedScheduleMap().put(deleted.getProgramId(), deleted); + schedulesNotToDelete.add(deleted); + } else { + schedulesToDelete.add(r); + } + } + if (mDvrLoadFinished) { + notifyScheduledRecordingRemoved(schedules); + } + if (!schedulesToDelete.isEmpty()) { + new AsyncDeleteScheduleTask(mContext).executeOnDbThread( + ScheduledRecording.toArray(schedulesToDelete)); + } + if (!schedulesNotToDelete.isEmpty()) { + new AsyncUpdateScheduleTask(mContext).executeOnDbThread( + ScheduledRecording.toArray(schedulesNotToDelete)); + } } @Override - public void removeSeasonSchedule(SeasonRecording seasonSchedule) { } + public void removeSeriesRecording(final SeriesRecording... seriesRecordings) { + HashSet<Long> ids = new HashSet<>(); + for (SeriesRecording r : seriesRecordings) { + mSeriesRecordings.remove(r.getId()); + mSeriesId2SeriesRecordings.remove(r.getSeriesId()); + ids.add(r.getId()); + } + // Reset series recording ID of the scheduled recording. + List<ScheduledRecording> toUpdate = new ArrayList<>(); + List<ScheduledRecording> toDelete = new ArrayList<>(); + for (ScheduledRecording r : mScheduledRecordings.values()) { + if (ids.contains(r.getSeriesRecordingId())) { + if (r.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) { + toDelete.add(r); + } else { + toUpdate.add(ScheduledRecording.buildFrom(r) + .setSeriesRecordingId(SeriesRecording.ID_NOT_SET).build()); + } + } + } + if (!toUpdate.isEmpty()) { + // No need to update DB. It's handled in database automatically when the series + // recording is deleted. + updateScheduledRecording(false, ScheduledRecording.toArray(toUpdate)); + } + if (!toDelete.isEmpty()) { + removeScheduledRecording(true, ScheduledRecording.toArray(toDelete)); + } + if (mDvrLoadFinished) { + notifySeriesRecordingRemoved(seriesRecordings); + } + new AsyncDeleteSeriesRecordingTask(mContext).executeOnDbThread(seriesRecordings); + removeDeletedSchedules(seriesRecordings); + } @Override - public void updateScheduledRecording(final ScheduledRecording scheduledRecording) { - new AsyncDvrDbTask.AsyncUpdateRecordingTask(mContext) { - @Override - protected void onPostExecute(List<Integer> counts) { - super.onPostExecute(counts); - SoftPreconditions.checkArgument(counts.size() == 1); - for (Integer c : counts) { - if (c == 1) { - ScheduledRecording oldScheduledRecording = mScheduledRecordings - .put(scheduledRecording.getId(), scheduledRecording); - long programId = scheduledRecording.getProgramId(); - if (oldScheduledRecording != null - && oldScheduledRecording.getProgramId() != programId - && oldScheduledRecording.getProgramId() - != ScheduledRecording.ID_NOT_SET) { - ScheduledRecording oldValueForProgramId = mProgramId2ScheduledRecordings - .get(oldScheduledRecording.getProgramId()); - if (oldValueForProgramId.getId() == scheduledRecording.getId()) { - //Only remove the old ScheduledRecording if it has the same ID as - // the new one. - mProgramId2ScheduledRecordings - .remove(oldScheduledRecording.getProgramId()); - } - } - if (programId != ScheduledRecording.ID_NOT_SET) { - mProgramId2ScheduledRecordings.put(programId, scheduledRecording); - } - //TODO change to notifyRecordingUpdated - notifyScheduledRecordingStatusChanged(scheduledRecording); - } else { - Log.w(TAG, "Error updating " + scheduledRecording); - } + public void updateScheduledRecording(final ScheduledRecording... schedules) { + updateScheduledRecording(true, schedules); + } + + private void updateScheduledRecording(boolean updateDb, + final ScheduledRecording... schedules) { + List<ScheduledRecording> toUpdate = new ArrayList<>(); + for (ScheduledRecording r : schedules) { + if (!SoftPreconditions.checkState(mScheduledRecordings.containsKey(r.getId()), TAG, + "Recording not found for: " + r)) { + continue; + } + toUpdate.add(r); + ScheduledRecording oldScheduledRecording = mScheduledRecordings.put(r.getId(), r); + // The channel ID should not be changed. + SoftPreconditions.checkState(r.getChannelId() == oldScheduledRecording.getChannelId()); + if (DEBUG) Log.d(TAG, "Updating " + oldScheduledRecording + " with " + r); + long programId = r.getProgramId(); + if (oldScheduledRecording != null && oldScheduledRecording.getProgramId() != programId + && oldScheduledRecording.getProgramId() != ScheduledRecording.ID_NOT_SET) { + ScheduledRecording oldValueForProgramId = mProgramId2ScheduledRecordings + .get(oldScheduledRecording.getProgramId()); + if (oldValueForProgramId.getId() == r.getId()) { + // Only remove the old ScheduledRecording if it has the same ID as the new one. + mProgramId2ScheduledRecordings.remove(oldScheduledRecording.getProgramId()); } } - }.executeOnDbThread(scheduledRecording); + if (programId != ScheduledRecording.ID_NOT_SET) { + mProgramId2ScheduledRecordings.put(programId, r); + } + } + ScheduledRecording[] scheduleArray = ScheduledRecording.toArray(toUpdate); + if (mDvrLoadFinished) { + notifyScheduledRecordingStatusChanged(scheduleArray); + } + if (updateDb) { + new AsyncUpdateScheduleTask(mContext).executeOnDbThread(scheduleArray); + } + removeDeletedSchedules(scheduleArray); } - private final class AsyncRecordedProgramsQueryTask - extends AsyncDbTask.AsyncQueryListTask<RecordedProgram> { - public AsyncRecordedProgramsQueryTask(ContentResolver contentResolver) { - super(contentResolver, TvContract.RecordedPrograms.CONTENT_URI, - RecordedProgram.PROJECTION, null, null, null); + @Override + public void updateSeriesRecording(final SeriesRecording... seriesRecordings) { + for (SeriesRecording r : seriesRecordings) { + SeriesRecording old = mSeriesRecordings.put(r.getId(), r); + if (old != null) { + mSeriesId2SeriesRecordings.remove(old.getSeriesId()); + } + mSeriesId2SeriesRecordings.put(r.getSeriesId(), r); } - - @Override - protected RecordedProgram fromCursor(Cursor c) { - return RecordedProgram.fromCursor(c); + if (mDvrLoadFinished) { + notifySeriesRecordingChanged(seriesRecordings); } + new AsyncUpdateSeriesRecordingTask(mContext).executeOnDbThread(seriesRecordings); + } - @Override - protected void onCancelled(List<RecordedProgram> scheduledRecordings) { - mPendingTasks.remove(this); + private void removeDeletedSchedules(ScheduledRecording... addedSchedules) { + List<ScheduledRecording> schedulesToDelete = new ArrayList<>(); + for (ScheduledRecording r : addedSchedules) { + ScheduledRecording deleted = getDeletedScheduleMap().remove(r.getProgramId()); + if (deleted != null) { + schedulesToDelete.add(deleted); + } + } + if (!schedulesToDelete.isEmpty()) { + new AsyncDeleteScheduleTask(mContext).executeOnDbThread( + ScheduledRecording.toArray(schedulesToDelete)); } + } - @Override - protected void onPostExecute(List<RecordedProgram> result) { - mPendingTasks.remove(this); - mRecordedProgramLoadFinished = true; - if (result != null) { - for (RecordedProgram r : result) { - mRecordedPrograms.put(r.getId(), r); - } + private void removeDeletedSchedules(SeriesRecording... removedSeriesRecordings) { + Set<Long> seriesRecordingIds = new HashSet<>(); + for (SeriesRecording r : removedSeriesRecordings) { + seriesRecordingIds.add(r.getId()); + } + List<ScheduledRecording> schedulesToDelete = new ArrayList<>(); + Iterator<Entry<Long, ScheduledRecording>> iter = + getDeletedScheduleMap().entrySet().iterator(); + while (iter.hasNext()) { + Entry<Long, ScheduledRecording> entry = iter.next(); + if (seriesRecordingIds.contains(entry.getValue().getSeriesRecordingId())) { + schedulesToDelete.add(entry.getValue()); + iter.remove(); } } + if (!schedulesToDelete.isEmpty()) { + new AsyncDeleteScheduleTask(mContext).executeOnDbThread( + ScheduledRecording.toArray(schedulesToDelete)); + } } - private final class AsyncRecordedProgramQueryTask - extends AsyncDbTask.AsyncQueryItemTask<RecordedProgram> { - + private final class RecordedProgramsQueryTask extends AsyncRecordedProgramQueryTask { private final Uri mUri; - public AsyncRecordedProgramQueryTask(ContentResolver contentResolver, Uri uri) { - super(contentResolver, uri, RecordedProgram.PROJECTION, null, null, null); + public RecordedProgramsQueryTask(ContentResolver contentResolver, Uri uri) { + super(contentResolver, uri == null ? RecordedPrograms.CONTENT_URI : uri); mUri = uri; } @Override - protected RecordedProgram fromCursor(Cursor c) { - return RecordedProgram.fromCursor(c); - } - - @Override - protected void onCancelled(RecordedProgram recordedProgram) { + protected void onCancelled(List<RecordedProgram> scheduledRecordings) { mPendingTasks.remove(this); } @Override - protected void onPostExecute(RecordedProgram recordedProgram) { + protected void onPostExecute(List<RecordedProgram> result) { mPendingTasks.remove(this); - onObservedChange(mUri, recordedProgram); + onRecordedProgramsLoadedFinished(mUri, result); } } } |