11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/* 21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project 31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License. 61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at 71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software 111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and 141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License 151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 171abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopackage com.android.tv.dvr; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context; 20ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.MainThread; 21ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.NonNull; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.support.annotation.Nullable; 231abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.support.annotation.VisibleForTesting; 241abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Range; 251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2648dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.common.SoftPreconditions; 2748dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.common.recording.RecordedProgram; 2848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.util.Clock; 29ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 301abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList; 311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Collections; 321abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.HashMap; 331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.List; 341abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Map; 35ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport java.util.concurrent.atomic.AtomicLong; 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * A DVR Data manager that stores values in memory suitable for testing. 391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko@VisibleForTesting // TODO(DVR): move to testing dir. 41ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko@MainThread 421abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager { 43ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final static String TAG = "DvrDataManagerInMemory"; 44ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private final AtomicLong mNextId = new AtomicLong(1); 4548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Map<Long, ScheduledRecording> mScheduledRecordings = new HashMap<>(); 4648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Map<Long, RecordedProgram> mRecordedPrograms = new HashMap<>(); 4748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final List<SeasonRecording> mSeasonSchedule = new ArrayList<>(); 481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 4948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public DvrDataManagerInMemoryImpl(Context context, Clock clock) { 5048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super(context, clock); 511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isInitialized() { 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return true; 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 5848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private List<ScheduledRecording> getScheduledRecordingsPrograms() { 5948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return new ArrayList(mScheduledRecordings.values()); 601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 6348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public List<RecordedProgram> getRecordedPrograms() { 6448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return new ArrayList<>(mRecordedPrograms.values()); 651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 6848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public List<ScheduledRecording> getAllScheduledRecordings() { 6948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return new ArrayList<>(mScheduledRecordings.values()); 701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public List<SeasonRecording> getSeasonRecordings() { 731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return mSeasonSchedule; 741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public long getNextScheduledStartTimeAfter(long startTime) { 781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 7948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho List<ScheduledRecording> temp = getNonStartedScheduledRecordings(); 8048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Collections.sort(temp, ScheduledRecording.START_TIME_COMPARATOR); 8148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : temp) { 821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (r.getStartTimeMs() > startTime) { 831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return r.getStartTimeMs(); 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return DvrDataManager.NEXT_START_TIME_NOT_FOUND; 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 9048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public List<ScheduledRecording> getRecordingsThatOverlapWith(Range<Long> period) { 9148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho List<ScheduledRecording> temp = getScheduledRecordingsPrograms(); 9248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho List<ScheduledRecording> result = new ArrayList<>(); 9348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : temp) { 941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (r.isOverLapping(period)) { 951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko result.add(r); 961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return result; 991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko /** 10248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho * Add a new scheduled recording. 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 10548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void addScheduledRecording(ScheduledRecording scheduledRecording) { 10648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho addScheduledRecordingInternal(scheduledRecording); 10748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 10948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 11048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void addRecordedProgram(RecordedProgram recordedProgram) { 11148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho addRecordedProgramInternal(recordedProgram); 11248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 11348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 11448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void updateRecordedProgram(RecordedProgram r) { 11548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho long id = r.getId(); 11648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mRecordedPrograms.containsKey(id)) { 11748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mRecordedPrograms.put(id, r); 11848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyRecordedProgramChanged(r); 11948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 12048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho throw new IllegalArgumentException("Recording not found:" + r); 12148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 12248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 12348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 12448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void removeRecordedProgram(RecordedProgram scheduledRecording) { 12548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mRecordedPrograms.remove(scheduledRecording.getId()); 12648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyRecordedProgramRemoved(scheduledRecording); 12748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 12848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 12948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 13048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public ScheduledRecording addScheduledRecordingInternal(ScheduledRecording scheduledRecording) { 13148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho SoftPreconditions 13248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .checkState(scheduledRecording.getId() == ScheduledRecording.ID_NOT_SET, TAG, 13348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho "expected id of " + ScheduledRecording.ID_NOT_SET + " but was " 13448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho + scheduledRecording); 13548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho scheduledRecording = ScheduledRecording.buildFrom(scheduledRecording) 13648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .setId(mNextId.incrementAndGet()) 13748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .build(); 13848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mScheduledRecordings.put(scheduledRecording.getId(), scheduledRecording); 13948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyScheduledRecordingAdded(scheduledRecording); 14048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return scheduledRecording; 141ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 142ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 14348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public RecordedProgram addRecordedProgramInternal(RecordedProgram recordedProgram) { 14448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho SoftPreconditions.checkState(recordedProgram.getId() == RecordedProgram.ID_NOT_SET, TAG, 14548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho "expected id of " + RecordedProgram.ID_NOT_SET + " but was " + recordedProgram); 14648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho recordedProgram = RecordedProgram.buildFrom(recordedProgram) 14748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .setId(mNextId.incrementAndGet()) 14848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .build(); 14948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mRecordedPrograms.put(recordedProgram.getId(), recordedProgram); 15048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyRecordedProgramAdded(recordedProgram); 15148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return recordedProgram; 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void addSeasonRecording(SeasonRecording seasonRecording) { 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mSeasonSchedule.add(seasonRecording); 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 16048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void removeScheduledRecording(ScheduledRecording scheduledRecording) { 16148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mScheduledRecordings.remove(scheduledRecording.getId()); 16248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyScheduledRecordingRemoved(scheduledRecording); 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void removeSeasonSchedule(SeasonRecording seasonSchedule) { 1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mSeasonSchedule.remove(seasonSchedule); 1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 17148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void updateScheduledRecording(ScheduledRecording r) { 1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko long id = r.getId(); 17348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mScheduledRecordings.containsKey(id)) { 17448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mScheduledRecordings.put(id, r); 17548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyScheduledRecordingStatusChanged(r); 1761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throw new IllegalArgumentException("Recording not found:" + r); 1781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Nullable 182ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 18348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public ScheduledRecording getScheduledRecording(long id) { 18448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mScheduledRecordings.get(id); 1851abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 186ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 18748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Nullable 18848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 18948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public ScheduledRecording getScheduledRecordingForProgramId(long programId) { 19048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : mScheduledRecordings.values()) { 19148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (r.getProgramId() == programId) { 19248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return r; 19348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 19448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 19548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return null; 19648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 19748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 19848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Nullable 19948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 20048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public RecordedProgram getRecordedProgram(long recordingId) { 20148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mRecordedPrograms.get(recordingId); 20248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 20348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 20448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 205ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @NonNull 20648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected List<ScheduledRecording> getRecordingsWithState(int state) { 20748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ArrayList<ScheduledRecording> result = new ArrayList<>(); 20848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : mScheduledRecordings.values()) { 209ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if(r.getState() == state){ 210ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko result.add(r); 211ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 212ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 213ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return result; 214ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 216