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 1948dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.annotation.TargetApi; 2048dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.content.ContentResolver; 2148dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.content.ContentUris; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context; 2348dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.database.ContentObserver; 2448dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.database.Cursor; 2548dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.media.tv.TvContract; 2648dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.net.Uri; 2748dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.os.AsyncTask; 2848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.os.Build; 2948dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.os.Handler; 3048dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.os.Looper; 31ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.MainThread; 32ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.Nullable; 331abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.support.annotation.VisibleForTesting; 3448dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport android.util.ArraySet; 35ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.util.Log; 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Range; 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.common.SoftPreconditions; 3948dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.common.recording.RecordedProgram; 4048dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.dvr.ScheduledRecording.RecordingState; 41ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.dvr.provider.AsyncDvrDbTask; 421abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQueryTask; 4348dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.util.AsyncDbTask; 4448dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.util.Clock; 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 461abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.ArrayList; 471abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.Collections; 48ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport java.util.HashMap; 4948dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.util.Iterator; 501abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.List; 5148dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport java.util.Set; 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * DVR Data manager to handle recordings and schedules. 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 56ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko@MainThread 5748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho@TargetApi(Build.VERSION_CODES.N) 581abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class DvrDataManagerImpl extends BaseDvrDataManager { 59ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko private static final String TAG = "DvrDataManagerImpl"; 6048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private static final boolean DEBUG = false; 61ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 6248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final HashMap<Long, ScheduledRecording> mScheduledRecordings = new HashMap<>(); 6348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final HashMap<Long, ScheduledRecording> mProgramId2ScheduledRecordings = 6448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho new HashMap<>(); 6548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final HashMap<Long, RecordedProgram> mRecordedPrograms = new HashMap<>(); 661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 6748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Context mContext; 6848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); 6948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final ContentObserver mContentObserver = new ContentObserver(mMainThreadHandler) { 7048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 7148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 7248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void onChange(boolean selfChange) { 7348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho onChange(selfChange, null); 7448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 7548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 7648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 7748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void onChange(boolean selfChange, @Nullable final Uri uri) { 7848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (uri == null) { 7948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // TODO reload everything. 8048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 8148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho AsyncRecordedProgramQueryTask task = new AsyncRecordedProgramQueryTask( 8248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mContext.getContentResolver(), uri); 8348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho task.executeOnDbThread(); 8448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.add(task); 8548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 8648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho }; 8748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 8848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private void onObservedChange(Uri uri, RecordedProgram recordedProgram) { 8948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho long id = ContentUris.parseId(uri); 9048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (DEBUG) { 9148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.d(TAG, "changed recorded program #" + id + " to " + recordedProgram); 9248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 9348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (recordedProgram == null) { 9448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho RecordedProgram old = mRecordedPrograms.remove(id); 9548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (old != null) { 9648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyRecordedProgramRemoved(old); 9748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 9848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.w(TAG, "Could not find old version of deleted program #" + id); 9948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 10148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho RecordedProgram old = mRecordedPrograms.put(id, recordedProgram); 10248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (old == null) { 10348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyRecordedProgramAdded(recordedProgram); 10448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } else { 10548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyRecordedProgramChanged(recordedProgram); 10648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 10948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 11048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private boolean mDvrLoadFinished; 11148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private boolean mRecordedProgramLoadFinished; 11248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Set<AsyncTask> mPendingTasks = new ArraySet<>(); 11348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 11448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public DvrDataManagerImpl(Context context, Clock clock) { 11548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super(context, clock); 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mContext = context; 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void start() { 12048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho AsyncDvrQueryTask mDvrQueryTask = new AsyncDvrQueryTask(mContext) { 12148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 1221abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 12348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onCancelled(List<ScheduledRecording> scheduledRecordings) { 12448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.remove(this); 12548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 12648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 12748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 12848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onPostExecute(List<ScheduledRecording> result) { 12948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.remove(this); 13048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mDvrLoadFinished = true; 13148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : result) { 13248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mScheduledRecordings.put(r.getId(), r); 133ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 1341abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko }; 13648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mDvrQueryTask.executeOnDbThread(); 13748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.add(mDvrQueryTask); 13848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho AsyncRecordedProgramsQueryTask mRecordedProgramQueryTask = 13948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho new AsyncRecordedProgramsQueryTask(mContext.getContentResolver()); 14048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mRecordedProgramQueryTask.executeOnDbThread(); 14148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ContentResolver cr = mContext.getContentResolver(); 14248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cr.registerContentObserver(TvContract.RecordedPrograms.CONTENT_URI, true, mContentObserver); 1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void stop() { 14648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ContentResolver cr = mContext.getContentResolver(); 14748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho cr.unregisterContentObserver(mContentObserver); 14848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Iterator<AsyncTask> i = mPendingTasks.iterator(); 14948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho while (i.hasNext()) { 15048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho AsyncTask task = i.next(); 15148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho i.remove(); 15248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho task.cancel(true); 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isInitialized() { 15848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mDvrLoadFinished && mRecordedProgramLoadFinished; 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 16148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private List<ScheduledRecording> getScheduledRecordingsPrograms() { 16248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (!mDvrLoadFinished) { 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return Collections.emptyList(); 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 16548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ArrayList<ScheduledRecording> list = new ArrayList<>(mScheduledRecordings.size()); 16648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho list.addAll(mScheduledRecordings.values()); 16748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Collections.sort(list, ScheduledRecording.START_TIME_COMPARATOR); 16848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return list; 1693a72b93e554bd22a5c64e71a6956d9604ce05108Youngsang Cho } 1703a72b93e554bd22a5c64e71a6956d9604ce05108Youngsang Cho 1713a72b93e554bd22a5c64e71a6956d9604ce05108Youngsang Cho @Override 17248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public List<RecordedProgram> getRecordedPrograms() { 17348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (!mRecordedProgramLoadFinished) { 17448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return Collections.emptyList(); 17548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 17648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return new ArrayList<>(mRecordedPrograms.values()); 1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 18048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public List<ScheduledRecording> getAllScheduledRecordings() { 18148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return new ArrayList<>(mScheduledRecordings.values()); 1821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 18448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected List<ScheduledRecording> getRecordingsWithState(@RecordingState int state) { 18548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho List<ScheduledRecording> result = new ArrayList<>(); 18648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : mScheduledRecordings.values()) { 1871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (r.getState() == state) { 1881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko result.add(r); 1891abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1901abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return result; 1921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 1951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public List<SeasonRecording> getSeasonRecordings() { 1961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // If we return dummy data here, we can implement UI part independently. 1971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return Collections.emptyList(); 1981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public long getNextScheduledStartTimeAfter(long startTime) { 20248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return getNextStartTimeAfter(getScheduledRecordingsPrograms(), startTime); 2031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @VisibleForTesting 20648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho static long getNextStartTimeAfter(List<ScheduledRecording> scheduledRecordings, long startTime) { 2071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int start = 0; 20848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho int end = scheduledRecordings.size() - 1; 2091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko while (start <= end) { 2101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko int mid = (start + end) / 2; 21148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (scheduledRecordings.get(mid).getStartTimeMs() <= startTime) { 2121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko start = mid + 1; 2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko end = mid - 1; 2151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 21748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return start < scheduledRecordings.size() ? scheduledRecordings.get(start).getStartTimeMs() 2181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko : NEXT_START_TIME_NOT_FOUND; 2191abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2211abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 22248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public List<ScheduledRecording> getRecordingsThatOverlapWith(Range<Long> period) { 22348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho List<ScheduledRecording> result = new ArrayList<>(); 22448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : mScheduledRecordings.values()) { 2251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (r.isOverLapping(period)) { 2261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko result.add(r); 2271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return result; 2301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 2311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 232ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Nullable 233ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 23448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public ScheduledRecording getScheduledRecording(long recordingId) { 23548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mDvrLoadFinished) { 23648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mScheduledRecordings.get(recordingId); 23748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 23848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return null; 23948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 24048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 24148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Nullable 24248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 24348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public ScheduledRecording getScheduledRecordingForProgramId(long programId) { 24448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (mDvrLoadFinished) { 24548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mProgramId2ScheduledRecordings.get(programId); 246ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 247ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko return null; 248ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 249ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 25048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Nullable 25148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 25248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public RecordedProgram getRecordedProgram(long recordingId) { 25348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return mRecordedPrograms.get(recordingId); 25448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 25548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 2561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 25748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void addScheduledRecording(final ScheduledRecording scheduledRecording) { 258ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko new AsyncDvrDbTask.AsyncAddRecordingTask(mContext) { 259ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 26048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onPostExecute(List<ScheduledRecording> scheduledRecordings) { 26148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super.onPostExecute(scheduledRecordings); 26248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho SoftPreconditions.checkArgument(scheduledRecordings.size() == 1); 26348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (ScheduledRecording r : scheduledRecordings) { 264ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (r.getId() != -1) { 26548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mScheduledRecordings.put(r.getId(), r); 26648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) { 26748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mProgramId2ScheduledRecordings.put(r.getProgramId(), r); 26848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 26948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyScheduledRecordingAdded(r); 270ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 271ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko Log.w(TAG, "Error adding " + r); 272ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 273ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 274ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 275ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 27648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho }.executeOnDbThread(scheduledRecording); 277ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 2781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 2801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void addSeasonRecording(SeasonRecording seasonRecording) { } 2811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 2821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 28348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void removeScheduledRecording(final ScheduledRecording scheduledRecording) { 284ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko new AsyncDvrDbTask.AsyncDeleteRecordingTask(mContext) { 285ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 286ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void onPostExecute(List<Integer> counts) { 287ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onPostExecute(counts); 288ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko SoftPreconditions.checkArgument(counts.size() == 1); 289ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko for (Integer c : counts) { 290ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (c == 1) { 29148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mScheduledRecordings.remove(scheduledRecording.getId()); 29248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (scheduledRecording.getProgramId() != ScheduledRecording.ID_NOT_SET) { 29348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mProgramId2ScheduledRecordings 29448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .remove(scheduledRecording.getProgramId()); 29548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 296ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko //TODO change to notifyRecordingUpdated 29748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyScheduledRecordingRemoved(scheduledRecording); 298ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 29948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.w(TAG, "Error removing " + scheduledRecording); 300ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 301ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 302ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 303ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 30448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho }.executeOnDbThread(scheduledRecording); 305ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 3061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 3081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void removeSeasonSchedule(SeasonRecording seasonSchedule) { } 3091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 3101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko @Override 31148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public void updateScheduledRecording(final ScheduledRecording scheduledRecording) { 312ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko new AsyncDvrDbTask.AsyncUpdateRecordingTask(mContext) { 313ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko @Override 314ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko protected void onPostExecute(List<Integer> counts) { 315ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko super.onPostExecute(counts); 316ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko SoftPreconditions.checkArgument(counts.size() == 1); 317ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko for (Integer c : counts) { 318ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko if (c == 1) { 31948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ScheduledRecording oldScheduledRecording = mScheduledRecordings 32048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .put(scheduledRecording.getId(), scheduledRecording); 32148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho long programId = scheduledRecording.getProgramId(); 32248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (oldScheduledRecording != null 32348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho && oldScheduledRecording.getProgramId() != programId 32448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho && oldScheduledRecording.getProgramId() 32548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho != ScheduledRecording.ID_NOT_SET) { 32648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho ScheduledRecording oldValueForProgramId = mProgramId2ScheduledRecordings 32748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .get(oldScheduledRecording.getProgramId()); 32848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (oldValueForProgramId.getId() == scheduledRecording.getId()) { 32948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho //Only remove the old ScheduledRecording if it has the same ID as 33048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho // the new one. 33148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mProgramId2ScheduledRecordings 33248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho .remove(oldScheduledRecording.getProgramId()); 33348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 33448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 33548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (programId != ScheduledRecording.ID_NOT_SET) { 33648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mProgramId2ScheduledRecordings.put(programId, scheduledRecording); 33748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 338ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko //TODO change to notifyRecordingUpdated 33948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho notifyScheduledRecordingStatusChanged(scheduledRecording); 340ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } else { 34148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.w(TAG, "Error updating " + scheduledRecording); 342ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 343ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 34448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 34548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho }.executeOnDbThread(scheduledRecording); 34648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 34748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 34848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final class AsyncRecordedProgramsQueryTask 34948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho extends AsyncDbTask.AsyncQueryListTask<RecordedProgram> { 35048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public AsyncRecordedProgramsQueryTask(ContentResolver contentResolver) { 35148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super(contentResolver, TvContract.RecordedPrograms.CONTENT_URI, 35248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho RecordedProgram.PROJECTION, null, null, null); 35348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 35448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 35548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 35648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected RecordedProgram fromCursor(Cursor c) { 35748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return RecordedProgram.fromCursor(c); 35848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 35948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 36048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 36148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onCancelled(List<RecordedProgram> scheduledRecordings) { 36248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.remove(this); 36348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 364ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko 36548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 36648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onPostExecute(List<RecordedProgram> result) { 36748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.remove(this); 36848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mRecordedProgramLoadFinished = true; 36948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (result != null) { 37048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho for (RecordedProgram r : result) { 37148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mRecordedPrograms.put(r.getId(), r); 37248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 373ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 37448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 37548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 37648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 37748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final class AsyncRecordedProgramQueryTask 37848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho extends AsyncDbTask.AsyncQueryItemTask<RecordedProgram> { 37948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 38048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho private final Uri mUri; 38148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 38248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public AsyncRecordedProgramQueryTask(ContentResolver contentResolver, Uri uri) { 38348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho super(contentResolver, uri, RecordedProgram.PROJECTION, null, null, null); 38448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mUri = uri; 38548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 38648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 38748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 38848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected RecordedProgram fromCursor(Cursor c) { 38948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return RecordedProgram.fromCursor(c); 39048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 39148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 39248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 39348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onCancelled(RecordedProgram recordedProgram) { 39448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.remove(this); 39548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 39648dadb49248271b01997862e1335912a4f2e189fYoungsang Cho 39748dadb49248271b01997862e1335912a4f2e189fYoungsang Cho @Override 39848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho protected void onPostExecute(RecordedProgram recordedProgram) { 39948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho mPendingTasks.remove(this); 40048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho onObservedChange(mUri, recordedProgram); 40148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 402ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko } 4031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 404