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
1965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.annotation.TargetApi;
20d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.content.ContentProviderOperation;
212e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.content.ContentResolver;
2265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.content.ContentUris;
231abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.content.Context;
24d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.content.OperationApplicationException;
2565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.media.tv.TvContract;
262e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.media.tv.TvInputInfo;
2765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.net.Uri;
28d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.os.AsyncTask;
2965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.os.Build;
302e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.os.Handler;
31d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.os.RemoteException;
32ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.MainThread;
33ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport android.support.annotation.NonNull;
3465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.annotation.Nullable;
3565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport android.support.annotation.VisibleForTesting;
362e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport android.support.annotation.WorkerThread;
371abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.util.Log;
38d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport android.util.Range;
39944779887775bd950cf1abf348d2df461593f6abLive Channels Teamimport com.android.tv.TvSingletons;
402e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport com.android.tv.common.SoftPreconditions;
41ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport com.android.tv.common.feature.CommonFeatures;
42944779887775bd950cf1abf348d2df461593f6abLive Channels Teamimport com.android.tv.common.util.CommonUtils;
431abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.data.Program;
440cc0713c1bf8027642987b750b80217569d2932aLive Channels Teamimport com.android.tv.data.api.Channel;
45d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener;
46d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport com.android.tv.dvr.DvrDataManager.RecordedProgramListener;
47d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalkoimport com.android.tv.dvr.DvrScheduleManager.OnInitializeListener;
48633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalkoimport com.android.tv.dvr.data.RecordedProgram;
49633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalkoimport com.android.tv.dvr.data.ScheduledRecording;
50633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalkoimport com.android.tv.dvr.data.SeriesRecording;
512e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport com.android.tv.util.AsyncDbTask;
521abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.android.tv.util.Utils;
5365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.io.File;
5465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.util.ArrayList;
5565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalkoimport java.util.Arrays;
56ba5845f23b8fbc985890f892961abc8b39886611Nick Chalkoimport java.util.Collections;
572e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport java.util.HashMap;
581abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.util.List;
592e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport java.util.Map;
602e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalkoimport java.util.Map.Entry;
610645b17e2818b69b996da48fd93731bc8a01f114Live Channels Teamimport java.util.concurrent.Executor;
621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/**
641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * DVR manager class to add and remove recordings. UI can modify recording list through this class,
651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * instead of modifying them directly through {@link DvrDataManager}.
661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */
67ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko@MainThread
6865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko@TargetApi(Build.VERSION_CODES.N)
691abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class DvrManager {
7065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final String TAG = "DvrManager";
7165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private static final boolean DEBUG = false;
7265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    private final WritableDvrDataManager mDataManager;
7465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private final DvrScheduleManager mScheduleManager;
752e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    // @GuardedBy("mListener")
762e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    private final Map<Listener, Handler> mListener = new HashMap<>();
772e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    private final Context mAppContext;
780645b17e2818b69b996da48fd93731bc8a01f114Live Channels Team    private final Executor mDbExecutor;
791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public DvrManager(Context context) {
81ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        SoftPreconditions.checkFeatureEnabled(context, CommonFeatures.DVR, TAG);
82d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        mAppContext = context.getApplicationContext();
83944779887775bd950cf1abf348d2df461593f6abLive Channels Team        TvSingletons tvSingletons = TvSingletons.getSingletons(context);
840645b17e2818b69b996da48fd93731bc8a01f114Live Channels Team        mDbExecutor = tvSingletons.getDbExecutor();
85944779887775bd950cf1abf348d2df461593f6abLive Channels Team        mDataManager = (WritableDvrDataManager) tvSingletons.getDvrDataManager();
86944779887775bd950cf1abf348d2df461593f6abLive Channels Team        mScheduleManager = tvSingletons.getDvrScheduleManager();
87d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (mDataManager.isInitialized() && mScheduleManager.isInitialized()) {
88d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            createSeriesRecordingsForRecordedProgramsIfNeeded(mDataManager.getRecordedPrograms());
89d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        } else {
90d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            // No need to handle DVR schedule load finished because schedule manager is initialized
91d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            // after the all the schedules are loaded.
92d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (!mDataManager.isRecordedProgramLoadFinished()) {
93d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                mDataManager.addRecordedProgramLoadFinishedListener(
94d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        new OnRecordedProgramLoadFinishedListener() {
95d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            @Override
96d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            public void onRecordedProgramLoadFinished() {
97d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                mDataManager.removeRecordedProgramLoadFinishedListener(this);
98d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                if (mDataManager.isInitialized()
99d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                        && mScheduleManager.isInitialized()) {
100d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                    createSeriesRecordingsForRecordedProgramsIfNeeded(
101d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                            mDataManager.getRecordedPrograms());
102d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                }
103d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            }
104d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        });
105d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
106d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (!mScheduleManager.isInitialized()) {
10795961816a768da387f0b5523cf4363ace2044089Nick Chalko                mScheduleManager.addOnInitializeListener(
10895961816a768da387f0b5523cf4363ace2044089Nick Chalko                        new OnInitializeListener() {
10995961816a768da387f0b5523cf4363ace2044089Nick Chalko                            @Override
11095961816a768da387f0b5523cf4363ace2044089Nick Chalko                            public void onInitialize() {
11195961816a768da387f0b5523cf4363ace2044089Nick Chalko                                mScheduleManager.removeOnInitializeListener(this);
11295961816a768da387f0b5523cf4363ace2044089Nick Chalko                                if (mDataManager.isInitialized()
11395961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        && mScheduleManager.isInitialized()) {
11495961816a768da387f0b5523cf4363ace2044089Nick Chalko                                    createSeriesRecordingsForRecordedProgramsIfNeeded(
11595961816a768da387f0b5523cf4363ace2044089Nick Chalko                                            mDataManager.getRecordedPrograms());
11695961816a768da387f0b5523cf4363ace2044089Nick Chalko                                }
11795961816a768da387f0b5523cf4363ace2044089Nick Chalko                            }
11895961816a768da387f0b5523cf4363ace2044089Nick Chalko                        });
11995961816a768da387f0b5523cf4363ace2044089Nick Chalko            }
12095961816a768da387f0b5523cf4363ace2044089Nick Chalko        }
12195961816a768da387f0b5523cf4363ace2044089Nick Chalko        mDataManager.addRecordedProgramListener(
12295961816a768da387f0b5523cf4363ace2044089Nick Chalko                new RecordedProgramListener() {
123d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    @Override
12495961816a768da387f0b5523cf4363ace2044089Nick Chalko                    public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
12595961816a768da387f0b5523cf4363ace2044089Nick Chalko                        if (!mDataManager.isInitialized() || !mScheduleManager.isInitialized()) {
12695961816a768da387f0b5523cf4363ace2044089Nick Chalko                            return;
12795961816a768da387f0b5523cf4363ace2044089Nick Chalko                        }
12895961816a768da387f0b5523cf4363ace2044089Nick Chalko                        for (RecordedProgram recordedProgram : recordedPrograms) {
12995961816a768da387f0b5523cf4363ace2044089Nick Chalko                            createSeriesRecordingForRecordedProgramIfNeeded(recordedProgram);
130d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        }
131d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    }
132d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
13395961816a768da387f0b5523cf4363ace2044089Nick Chalko                    @Override
13495961816a768da387f0b5523cf4363ace2044089Nick Chalko                    public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {}
135d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
13695961816a768da387f0b5523cf4363ace2044089Nick Chalko                    @Override
13795961816a768da387f0b5523cf4363ace2044089Nick Chalko                    public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
13895961816a768da387f0b5523cf4363ace2044089Nick Chalko                        // Removing series recording is handled in the
13995961816a768da387f0b5523cf4363ace2044089Nick Chalko                        // SeriesRecordingDetailsFragment.
14095961816a768da387f0b5523cf4363ace2044089Nick Chalko                    }
14195961816a768da387f0b5523cf4363ace2044089Nick Chalko                });
142d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
143d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
144d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private void createSeriesRecordingsForRecordedProgramsIfNeeded(
145d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            List<RecordedProgram> recordedPrograms) {
146d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        for (RecordedProgram recordedProgram : recordedPrograms) {
147d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            createSeriesRecordingForRecordedProgramIfNeeded(recordedProgram);
148d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
149d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
150d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
151d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private void createSeriesRecordingForRecordedProgramIfNeeded(RecordedProgram recordedProgram) {
152633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        if (recordedProgram.isEpisodic()) {
153d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            SeriesRecording seriesRecording =
154d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    mDataManager.getSeriesRecording(recordedProgram.getSeriesId());
155d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (seriesRecording == null) {
156d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                addSeriesRecording(recordedProgram);
157d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
158d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
15965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
16065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
16195961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Schedules a recording for {@code program}. */
162d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public ScheduledRecording addSchedule(Program program) {
16365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
164d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return null;
16565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
16665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        SeriesRecording seriesRecording = getSeriesRecording(program);
16795961816a768da387f0b5523cf4363ace2044089Nick Chalko        return addSchedule(
16895961816a768da387f0b5523cf4363ace2044089Nick Chalko                program,
16995961816a768da387f0b5523cf4363ace2044089Nick Chalko                seriesRecording == null
17095961816a768da387f0b5523cf4363ace2044089Nick Chalko                        ? mScheduleManager.suggestNewPriority()
17195961816a768da387f0b5523cf4363ace2044089Nick Chalko                        : seriesRecording.getPriority());
1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
17595961816a768da387f0b5523cf4363ace2044089Nick Chalko     * Schedules a recording for {@code program} with the highest priority so that the schedule can
17695961816a768da387f0b5523cf4363ace2044089Nick Chalko     * be recorded.
1771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
178d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public ScheduledRecording addScheduleWithHighestPriority(Program program) {
17965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
180d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return null;
18165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
182d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        SeriesRecording seriesRecording = getSeriesRecording(program);
18395961816a768da387f0b5523cf4363ace2044089Nick Chalko        return addSchedule(
18495961816a768da387f0b5523cf4363ace2044089Nick Chalko                program,
18595961816a768da387f0b5523cf4363ace2044089Nick Chalko                seriesRecording == null
18695961816a768da387f0b5523cf4363ace2044089Nick Chalko                        ? mScheduleManager.suggestNewPriority()
18795961816a768da387f0b5523cf4363ace2044089Nick Chalko                        : mScheduleManager.suggestHighestPriority(
18895961816a768da387f0b5523cf4363ace2044089Nick Chalko                                seriesRecording.getInputId(),
18995961816a768da387f0b5523cf4363ace2044089Nick Chalko                                new Range(
19095961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        program.getStartTimeUtcMillis(),
19195961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        program.getEndTimeUtcMillis()),
19295961816a768da387f0b5523cf4363ace2044089Nick Chalko                                seriesRecording.getPriority()));
193d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
194d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
195d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private ScheduledRecording addSchedule(Program program, long priority) {
19665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        TvInputInfo input = Utils.getTvInputInfoForProgram(mAppContext, program);
19765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (input == null) {
19865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Log.e(TAG, "Can't find input for program: " + program);
199d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return null;
20065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
201d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        ScheduledRecording schedule;
202d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        SeriesRecording seriesRecording = getSeriesRecording(program);
20395961816a768da387f0b5523cf4363ace2044089Nick Chalko        schedule =
20495961816a768da387f0b5523cf4363ace2044089Nick Chalko                createScheduledRecordingBuilder(input.getId(), program)
20595961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .setPriority(priority)
20695961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .setSeriesRecordingId(
20795961816a768da387f0b5523cf4363ace2044089Nick Chalko                                seriesRecording == null
20895961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        ? SeriesRecording.ID_NOT_SET
20995961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        : seriesRecording.getId())
21095961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .build();
211d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        mDataManager.addScheduledRecording(schedule);
212d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        return schedule;
2131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
2141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
21595961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Adds a recording schedule with a time range. */
2161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    public void addSchedule(Channel channel, long startTime, long endTime) {
21795961816a768da387f0b5523cf4363ace2044089Nick Chalko        Log.i(
21895961816a768da387f0b5523cf4363ace2044089Nick Chalko                TAG,
21995961816a768da387f0b5523cf4363ace2044089Nick Chalko                "Adding scheduled recording of channel "
22095961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + channel
22195961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + " starting at "
22295961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + Utils.toTimeString(startTime)
22395961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + " and ending at "
22495961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + Utils.toTimeString(endTime));
22565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
22665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
22765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
22865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        TvInputInfo input = Utils.getTvInputInfoForChannelId(mAppContext, channel.getId());
22965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (input == null) {
23065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Log.e(TAG, "Can't find input for channel: " + channel);
23165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
23265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
23365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        addScheduleInternal(input.getId(), channel.getId(), startTime, endTime);
23465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
23565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
23695961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Adds the schedule. */
237d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public void addSchedule(ScheduledRecording schedule) {
238d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (mDataManager.isDvrScheduleLoadFinished()) {
239d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            mDataManager.addScheduledRecording(schedule);
240d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
241d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
242d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
24365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void addScheduleInternal(String inputId, long channelId, long startTime, long endTime) {
24495961816a768da387f0b5523cf4363ace2044089Nick Chalko        mDataManager.addScheduledRecording(
24595961816a768da387f0b5523cf4363ace2044089Nick Chalko                ScheduledRecording.builder(inputId, channelId, startTime, endTime)
24695961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .setPriority(mScheduleManager.suggestNewPriority())
24795961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .build());
24865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
24965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
25095961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Adds a new series recording and schedules for the programs with the initial state. */
25195961816a768da387f0b5523cf4363ace2044089Nick Chalko    public SeriesRecording addSeriesRecording(
25295961816a768da387f0b5523cf4363ace2044089Nick Chalko            Program selectedProgram,
25395961816a768da387f0b5523cf4363ace2044089Nick Chalko            List<Program> programsToSchedule,
25495961816a768da387f0b5523cf4363ace2044089Nick Chalko            @SeriesRecording.SeriesState int initialState) {
25595961816a768da387f0b5523cf4363ace2044089Nick Chalko        Log.i(
25695961816a768da387f0b5523cf4363ace2044089Nick Chalko                TAG,
25795961816a768da387f0b5523cf4363ace2044089Nick Chalko                "Adding series recording for program "
25895961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + selectedProgram
25995961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + ", and schedules: "
26095961816a768da387f0b5523cf4363ace2044089Nick Chalko                        + programsToSchedule);
26165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
26265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return null;
26365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
26465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        TvInputInfo input = Utils.getTvInputInfoForProgram(mAppContext, selectedProgram);
26565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (input == null) {
26665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Log.e(TAG, "Can't find input for program: " + selectedProgram);
26765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return null;
26865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
26995961816a768da387f0b5523cf4363ace2044089Nick Chalko        SeriesRecording seriesRecording =
27095961816a768da387f0b5523cf4363ace2044089Nick Chalko                SeriesRecording.builder(input.getId(), selectedProgram)
27195961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .setPriority(mScheduleManager.suggestNewSeriesPriority())
27295961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .setState(initialState)
27395961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .build();
27465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mDataManager.addSeriesRecording(seriesRecording);
27565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        // The schedules for the recorded programs should be added not to create the schedule the
27665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        // duplicate episodes.
27765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        addRecordedProgramToSeriesRecording(seriesRecording);
27865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        addScheduleToSeriesRecording(seriesRecording, programsToSchedule);
27965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return seriesRecording;
28065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
28165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
282d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private void addSeriesRecording(RecordedProgram recordedProgram) {
283d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        SeriesRecording seriesRecording =
284d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                SeriesRecording.builder(recordedProgram.getInputId(), recordedProgram)
285d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        .setPriority(mScheduleManager.suggestNewSeriesPriority())
286d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        .setState(SeriesRecording.STATE_SERIES_STOPPED)
287d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        .build();
288d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        mDataManager.addSeriesRecording(seriesRecording);
289d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        // The schedules for the recorded programs should be added not to create the schedule the
290d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        // duplicate episodes.
291d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        addRecordedProgramToSeriesRecording(seriesRecording);
292d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
293d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
29465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    private void addRecordedProgramToSeriesRecording(SeriesRecording series) {
29565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        List<ScheduledRecording> toAdd = new ArrayList<>();
29665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (RecordedProgram recordedProgram : mDataManager.getRecordedPrograms()) {
29765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (series.getSeriesId().equals(recordedProgram.getSeriesId())
29865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    && !recordedProgram.isClipped()) {
29965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                // Duplicate schedules can exist, but they will be deleted in a few days. And it's
30065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                // also guaranteed that the schedules don't belong to any series recordings because
30165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                // there are no more than one series recordings which have the same program title.
30295961816a768da387f0b5523cf4363ace2044089Nick Chalko                toAdd.add(
30395961816a768da387f0b5523cf4363ace2044089Nick Chalko                        ScheduledRecording.builder(recordedProgram)
30495961816a768da387f0b5523cf4363ace2044089Nick Chalko                                .setPriority(series.getPriority())
30595961816a768da387f0b5523cf4363ace2044089Nick Chalko                                .setSeriesRecordingId(series.getId())
30695961816a768da387f0b5523cf4363ace2044089Nick Chalko                                .build());
30765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
30865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
30965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!toAdd.isEmpty()) {
31065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mDataManager.addScheduledRecording(ScheduledRecording.toArray(toAdd));
31165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
31265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
31365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
31465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
31565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Adds {@link ScheduledRecording}s for the series recording.
31695961816a768da387f0b5523cf4363ace2044089Nick Chalko     *
31795961816a768da387f0b5523cf4363ace2044089Nick Chalko     * <p>This method doesn't add the series recording.
31865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
31995961816a768da387f0b5523cf4363ace2044089Nick Chalko    public void addScheduleToSeriesRecording(
32095961816a768da387f0b5523cf4363ace2044089Nick Chalko            SeriesRecording series, List<Program> programsToSchedule) {
32165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
32265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
32365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
32465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        TvInputInfo input = Utils.getTvInputInfoForInputId(mAppContext, series.getInputId());
32565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (input == null) {
32665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Log.e(TAG, "Can't find input with ID: " + series.getInputId());
32765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
32865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
32965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        List<ScheduledRecording> toAdd = new ArrayList<>();
33065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        List<ScheduledRecording> toUpdate = new ArrayList<>();
33165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (Program program : programsToSchedule) {
33265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            ScheduledRecording scheduleWithSameProgram =
33365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    mDataManager.getScheduledRecordingForProgramId(program.getId());
33465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (scheduleWithSameProgram != null) {
335633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                if (scheduleWithSameProgram.isNotStarted()) {
33695961816a768da387f0b5523cf4363ace2044089Nick Chalko                    ScheduledRecording r =
33795961816a768da387f0b5523cf4363ace2044089Nick Chalko                            ScheduledRecording.buildFrom(scheduleWithSameProgram)
33895961816a768da387f0b5523cf4363ace2044089Nick Chalko                                    .setSeriesRecordingId(series.getId())
33995961816a768da387f0b5523cf4363ace2044089Nick Chalko                                    .build();
34065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    if (!r.equals(scheduleWithSameProgram)) {
34165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                        toUpdate.add(r);
34265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    }
34365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
34465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            } else {
34595961816a768da387f0b5523cf4363ace2044089Nick Chalko                toAdd.add(
34695961816a768da387f0b5523cf4363ace2044089Nick Chalko                        createScheduledRecordingBuilder(input.getId(), program)
34795961816a768da387f0b5523cf4363ace2044089Nick Chalko                                .setPriority(series.getPriority())
34895961816a768da387f0b5523cf4363ace2044089Nick Chalko                                .setSeriesRecordingId(series.getId())
34995961816a768da387f0b5523cf4363ace2044089Nick Chalko                                .build());
35065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
35165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
35265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!toAdd.isEmpty()) {
35365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mDataManager.addScheduledRecording(ScheduledRecording.toArray(toAdd));
35465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
35565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!toUpdate.isEmpty()) {
35665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mDataManager.updateScheduledRecording(ScheduledRecording.toArray(toUpdate));
35765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
35865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
35965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
36095961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Updates the series recording. */
36165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void updateSeriesRecording(SeriesRecording series) {
36265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
36365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            SeriesRecording previousSeries = mDataManager.getSeriesRecording(series.getId());
36465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (previousSeries != null) {
365633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                // If the channel option of series changed, remove the existing schedules. The new
366633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                // schedules will be added by SeriesRecordingScheduler or by SeriesSettingsFragment.
367d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                if (previousSeries.getChannelOption() != series.getChannelOption()
368d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        || (previousSeries.getChannelOption() == SeriesRecording.OPTION_CHANNEL_ONE
36995961816a768da387f0b5523cf4363ace2044089Nick Chalko                                && previousSeries.getChannelId() != series.getChannelId())) {
370d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    List<ScheduledRecording> schedules =
371d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            mDataManager.getScheduledRecordings(series.getId());
372d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    List<ScheduledRecording> schedulesToRemove = new ArrayList<>();
373d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    for (ScheduledRecording schedule : schedules) {
374d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        if (schedule.isNotStarted()) {
375d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            schedulesToRemove.add(schedule);
376633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                        } else if (schedule.isInProgress()
377633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                                && series.getChannelOption() == SeriesRecording.OPTION_CHANNEL_ONE
378633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                                && schedule.getChannelId() != series.getChannelId()) {
379633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                            stopRecording(schedule);
380633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                        }
381633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                    }
382633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                    List<ScheduledRecording> deletedSchedules =
383633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                            new ArrayList<>(mDataManager.getDeletedSchedules());
384633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                    for (ScheduledRecording deletedSchedule : deletedSchedules) {
385633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                        if (deletedSchedule.getSeriesRecordingId() == series.getId()
386633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                                && deletedSchedule.getEndTimeMs() > System.currentTimeMillis()) {
387633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                            schedulesToRemove.add(deletedSchedule);
388d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        }
389d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    }
39095961816a768da387f0b5523cf4363ace2044089Nick Chalko                    mDataManager.removeScheduledRecording(
39195961816a768da387f0b5523cf4363ace2044089Nick Chalko                            true, ScheduledRecording.toArray(schedulesToRemove));
392d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                }
39365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
39465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mDataManager.updateSeriesRecording(series);
39595961816a768da387f0b5523cf4363ace2044089Nick Chalko            if (previousSeries == null || previousSeries.getPriority() != series.getPriority()) {
39665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                long priority = series.getPriority();
39765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                List<ScheduledRecording> schedulesToUpdate = new ArrayList<>();
39895961816a768da387f0b5523cf4363ace2044089Nick Chalko                for (ScheduledRecording schedule :
39995961816a768da387f0b5523cf4363ace2044089Nick Chalko                        mDataManager.getScheduledRecordings(series.getId())) {
400633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                    if (schedule.isNotStarted() || schedule.isInProgress()) {
40195961816a768da387f0b5523cf4363ace2044089Nick Chalko                        schedulesToUpdate.add(
40295961816a768da387f0b5523cf4363ace2044089Nick Chalko                                ScheduledRecording.buildFrom(schedule)
40395961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        .setPriority(priority)
40495961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        .build());
40565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    }
40665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
40765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (!schedulesToUpdate.isEmpty()) {
40865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    mDataManager.updateScheduledRecording(
40965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                            ScheduledRecording.toArray(schedulesToUpdate));
41065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
41165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
41265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
41365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
41465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
41565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
41665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Removes the series recording and all the corresponding schedules which are not started yet.
41765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
41865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void removeSeriesRecording(long seriesRecordingId) {
41965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
42065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
42165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
42265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        SeriesRecording series = mDataManager.getSeriesRecording(seriesRecordingId);
42365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (series == null) {
42465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
42565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
42665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (ScheduledRecording schedule : mDataManager.getAllScheduledRecordings()) {
42765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (schedule.getSeriesRecordingId() == seriesRecordingId) {
42865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
42965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    stopRecording(schedule);
43065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    break;
43165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
43265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
43365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
43465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        mDataManager.removeSeriesRecording(series);
4351abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
4361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
43795961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Stops the currently recorded program */
4382e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    public void stopRecording(final ScheduledRecording recording) {
43965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
44065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
44165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
4422e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        synchronized (mListener) {
4432e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko            for (final Entry<Listener, Handler> entry : mListener.entrySet()) {
44495961816a768da387f0b5523cf4363ace2044089Nick Chalko                entry.getValue()
44595961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .post(
44695961816a768da387f0b5523cf4363ace2044089Nick Chalko                                new Runnable() {
44795961816a768da387f0b5523cf4363ace2044089Nick Chalko                                    @Override
44895961816a768da387f0b5523cf4363ace2044089Nick Chalko                                    public void run() {
44995961816a768da387f0b5523cf4363ace2044089Nick Chalko                                        entry.getKey().onStopRecordingRequested(recording);
45095961816a768da387f0b5523cf4363ace2044089Nick Chalko                                    }
45195961816a768da387f0b5523cf4363ace2044089Nick Chalko                                });
4522e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko            }
4532e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        }
4542e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    }
4552e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko
45695961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Removes scheduled recordings or an existing recordings. */
45765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void removeScheduledRecording(ScheduledRecording... schedules) {
45865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        Log.i(TAG, "Removing " + Arrays.asList(schedules));
45965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
46065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
46165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
46265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (ScheduledRecording r : schedules) {
46365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (r.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
46465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                stopRecording(r);
46565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            } else {
46665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                mDataManager.removeScheduledRecording(r);
46765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
46865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
46965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
47065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
47195961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Removes scheduled recordings without changing to the DELETED state. */
472d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public void forceRemoveScheduledRecording(ScheduledRecording... schedules) {
473d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        Log.i(TAG, "Force removing " + Arrays.asList(schedules));
474d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
475d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return;
476d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
477d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        for (ScheduledRecording r : schedules) {
478d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (r.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
479d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                stopRecording(r);
480d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            } else {
481d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                mDataManager.removeScheduledRecording(true, r);
482d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
483d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
484d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
485d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
48695961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Removes the recorded program. It deletes the file if possible. */
48765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void removeRecordedProgram(Uri recordedProgramUri) {
48865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
48965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
49065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
49165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        removeRecordedProgram(ContentUris.parseId(recordedProgramUri));
49265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
49365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
49495961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Removes the recorded program. It deletes the file if possible. */
49565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void removeRecordedProgram(long recordedProgramId) {
49665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
49765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
49865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
49965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        RecordedProgram recordedProgram = mDataManager.getRecordedProgram(recordedProgramId);
50065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (recordedProgram != null) {
50165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            removeRecordedProgram(recordedProgram);
50265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
5032e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    }
5042e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko
50595961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Removes the recorded program. It deletes the file if possible. */
5062e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    public void removeRecordedProgram(final RecordedProgram recordedProgram) {
50765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
50865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return;
50965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
5100645b17e2818b69b996da48fd93731bc8a01f114Live Channels Team        new AsyncDbTask<Void, Void, Integer>(mDbExecutor) {
5112e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko            @Override
512633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            protected Integer doInBackground(Void... params) {
5132e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko                ContentResolver resolver = mAppContext.getContentResolver();
514633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                return resolver.delete(recordedProgram.getUri(), null, null);
515633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            }
516633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko
517633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            @Override
518633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            protected void onPostExecute(Integer deletedCounts) {
519d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                if (deletedCounts > 0) {
520d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    new AsyncTask<Void, Void, Void>() {
521d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        @Override
522d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        protected Void doInBackground(Void... params) {
523d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            removeRecordedData(recordedProgram.getDataUri());
524d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            return null;
52565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                        }
526d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
52765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                }
5282e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko            }
52965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }.executeOnDbThread();
5301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
5311abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
532d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public void removeRecordedPrograms(List<Long> recordedProgramIds) {
533d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        final ArrayList<ContentProviderOperation> dbOperations = new ArrayList<>();
534d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        final List<Uri> dataUris = new ArrayList<>();
535d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        for (Long rId : recordedProgramIds) {
536d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            RecordedProgram r = mDataManager.getRecordedProgram(rId);
537d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (r != null) {
538d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                dataUris.add(r.getDataUri());
539d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                dbOperations.add(ContentProviderOperation.newDelete(r.getUri()).build());
540d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
54165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
5420645b17e2818b69b996da48fd93731bc8a01f114Live Channels Team        new AsyncDbTask<Void, Void, Boolean>(mDbExecutor) {
54365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            @Override
544633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            protected Boolean doInBackground(Void... params) {
54565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                ContentResolver resolver = mAppContext.getContentResolver();
546d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                try {
547d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    resolver.applyBatch(TvContract.AUTHORITY, dbOperations);
548633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                } catch (RemoteException | OperationApplicationException e) {
549633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                    Log.w(TAG, "Remove recorded programs from DB failed.", e);
550633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                    return false;
551633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                }
552633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                return true;
553633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            }
554633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko
555633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            @Override
556633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            protected void onPostExecute(Boolean success) {
557633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                if (success) {
558d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    new AsyncTask<Void, Void, Void>() {
559d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        @Override
560d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        protected Void doInBackground(Void... params) {
561d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            for (Uri dataUri : dataUris) {
562d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                                removeRecordedData(dataUri);
563d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            }
564d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                            return null;
565d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        }
566d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
567d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                }
56865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
56965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }.executeOnDbThread();
57065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
57165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
57295961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Updates the scheduled recording. */
57365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void updateScheduledRecording(ScheduledRecording recording) {
57465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
57565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            mDataManager.updateScheduledRecording(recording);
57665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
57765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
57865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
57965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
58095961816a768da387f0b5523cf4363ace2044089Nick Chalko     * Returns priority ordered list of all scheduled recordings that will not be recorded if this
58195961816a768da387f0b5523cf4363ace2044089Nick Chalko     * program is.
582ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     *
58365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * @see DvrScheduleManager#getConflictingSchedules(Program)
58465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
58565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public List<ScheduledRecording> getConflictingSchedules(Program program) {
58665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
58765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return Collections.emptyList();
58865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
58965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mScheduleManager.getConflictingSchedules(program);
59065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
59165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
59265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
59395961816a768da387f0b5523cf4363ace2044089Nick Chalko     * Returns priority ordered list of all scheduled recordings that will not be recorded if this
59495961816a768da387f0b5523cf4363ace2044089Nick Chalko     * channel is.
59565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     *
59665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * @see DvrScheduleManager#getConflictingSchedules(long, long, long)
59765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
59895961816a768da387f0b5523cf4363ace2044089Nick Chalko    public List<ScheduledRecording> getConflictingSchedules(
59995961816a768da387f0b5523cf4363ace2044089Nick Chalko            long channelId, long startTimeMs, long endTimeMs) {
60065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
60165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return Collections.emptyList();
60265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
60365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mScheduleManager.getConflictingSchedules(channelId, startTimeMs, endTimeMs);
60465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
60565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
60665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
60765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Checks if the schedule is conflicting.
60865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     *
60995961816a768da387f0b5523cf4363ace2044089Nick Chalko     * <p>Note that the {@code schedule} should be the existing one. If not, this returns {@code
61095961816a768da387f0b5523cf4363ace2044089Nick Chalko     * false}.
61165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
61265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public boolean isConflicting(ScheduledRecording schedule) {
613d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        return schedule != null
614d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                && SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())
615d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                && mScheduleManager.isConflicting(schedule);
61665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
61765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
61865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
61995961816a768da387f0b5523cf4363ace2044089Nick Chalko     * Returns priority ordered list of all scheduled recording that will not be recorded if this
62095961816a768da387f0b5523cf4363ace2044089Nick Chalko     * channel is tuned to.
62165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     *
62265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * @see DvrScheduleManager#getConflictingSchedulesForTune
62365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
62465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public List<ScheduledRecording> getConflictingSchedulesForTune(long channelId) {
62565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
62665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return Collections.emptyList();
62765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
62865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mScheduleManager.getConflictingSchedulesForTune(channelId);
62965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
63065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
63195961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Sets the highest priority to the schedule. */
632d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public void setHighestPriority(ScheduledRecording schedule) {
633d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
634d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            long newPriority = mScheduleManager.suggestHighestPriority(schedule);
635d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (newPriority != schedule.getPriority()) {
63695961816a768da387f0b5523cf4363ace2044089Nick Chalko                mDataManager.updateScheduledRecording(
63795961816a768da387f0b5523cf4363ace2044089Nick Chalko                        ScheduledRecording.buildFrom(schedule).setPriority(newPriority).build());
638ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko            }
639ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko        }
640d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
641d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
64295961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Suggests the higher priority than the schedules which overlap with {@code schedule}. */
643d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public long suggestHighestPriority(ScheduledRecording schedule) {
644d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
645d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return mScheduleManager.suggestHighestPriority(schedule);
646d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
647d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        return DvrScheduleManager.DEFAULT_PRIORITY;
648ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
649ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
65065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
65165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns {@code true} if the channel can be recorded.
65295961816a768da387f0b5523cf4363ace2044089Nick Chalko     *
65395961816a768da387f0b5523cf4363ace2044089Nick Chalko     * <p>Note that this method doesn't check the conflict of the schedule or available tuners. This
65495961816a768da387f0b5523cf4363ace2044089Nick Chalko     * can be called from the UI before the schedules are loaded.
65565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
65665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public boolean isChannelRecordable(Channel channel) {
65765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!mDataManager.isDvrScheduleLoadFinished() || channel == null) {
65865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return false;
65965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
660633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        if (channel.isRecordingProhibited()) {
661633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            return false;
662633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        }
66365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        TvInputInfo info = Utils.getTvInputInfoForChannelId(mAppContext, channel.getId());
66465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (info == null) {
66565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Log.w(TAG, "Could not find TvInputInfo for " + channel);
66665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return false;
66765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
66865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!info.canRecord()) {
66965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return false;
67065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
67195961816a768da387f0b5523cf4363ace2044089Nick Chalko        Program program =
672944779887775bd950cf1abf348d2df461593f6abLive Channels Team                TvSingletons.getSingletons(mAppContext)
67395961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .getProgramDataManager()
67495961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .getCurrentProgram(channel.getId());
67565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return program == null || !program.isRecordingProhibited();
6761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
6771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko
6781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    /**
67965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns {@code true} if the program can be recorded.
68095961816a768da387f0b5523cf4363ace2044089Nick Chalko     *
68195961816a768da387f0b5523cf4363ace2044089Nick Chalko     * <p>Note that this method doesn't check the conflict of the schedule or available tuners. This
68295961816a768da387f0b5523cf4363ace2044089Nick Chalko     * can be called from the UI before the schedules are loaded.
6831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko     */
68465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public boolean isProgramRecordable(Program program) {
68565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!mDataManager.isInitialized()) {
68665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return false;
68765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
68895961816a768da387f0b5523cf4363ace2044089Nick Chalko        Channel channel =
689944779887775bd950cf1abf348d2df461593f6abLive Channels Team                TvSingletons.getSingletons(mAppContext)
69095961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .getChannelDataManager()
69195961816a768da387f0b5523cf4363ace2044089Nick Chalko                        .getChannel(program.getChannelId());
692633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        if (channel == null || channel.isRecordingProhibited()) {
693633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko            return false;
694633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        }
695633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        TvInputInfo info = Utils.getTvInputInfoForChannelId(mAppContext, channel.getId());
69665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (info == null) {
69765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            Log.w(TAG, "Could not find TvInputInfo for " + program);
69865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return false;
69965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
70065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return info.canRecord() && !program.isRecordingProhibited();
7011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko    }
702ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko
703ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    /**
70465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns the current recording for the channel.
70595961816a768da387f0b5523cf4363ace2044089Nick Chalko     *
70695961816a768da387f0b5523cf4363ace2044089Nick Chalko     * <p>This can be called from the UI before the schedules are loaded.
707ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko     */
70865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public ScheduledRecording getCurrentRecording(long channelId) {
70965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!mDataManager.isDvrScheduleLoadFinished()) {
71065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return null;
71165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
71265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (ScheduledRecording recording : mDataManager.getStartedRecordings()) {
71365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (recording.getChannelId() == channelId) {
71465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                return recording;
71565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
71665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
71765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return null;
71865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
71965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
72065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
72195961816a768da387f0b5523cf4363ace2044089Nick Chalko     * Returns schedules which is available (i.e., isNotStarted or isInProgress) and belongs to the
72295961816a768da387f0b5523cf4363ace2044089Nick Chalko     * series recording {@code seriesRecordingId}.
723d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko     */
724d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public List<ScheduledRecording> getAvailableScheduledRecording(long seriesRecordingId) {
725d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (!mDataManager.isDvrScheduleLoadFinished()) {
726d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            return Collections.emptyList();
727d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
728d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        List<ScheduledRecording> schedules = new ArrayList<>();
729d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        for (ScheduledRecording schedule : mDataManager.getScheduledRecordings(seriesRecordingId)) {
730d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (schedule.isInProgress() || schedule.isNotStarted()) {
731d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                schedules.add(schedule);
732d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
733d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
734d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        return schedules;
735d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
736d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
73795961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Returns the series recording related to the program. */
73865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @Nullable
73965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public SeriesRecording getSeriesRecording(Program program) {
74065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
74165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return null;
74265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
74365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return mDataManager.getSeriesRecording(program.getSeriesId());
7442e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    }
7452e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko
746633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko    /**
74795961816a768da387f0b5523cf4363ace2044089Nick Chalko     * Returns if there are valid items. Valid item contains {@link RecordedProgram}, available
74895961816a768da387f0b5523cf4363ace2044089Nick Chalko     * {@link ScheduledRecording} and {@link SeriesRecording}.
749633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko     */
750633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko    public boolean hasValidItems() {
751633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko        return !(mDataManager.getRecordedPrograms().isEmpty()
752633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                && mDataManager.getStartedRecordings().isEmpty()
753633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                && mDataManager.getNonStartedScheduledRecordings().isEmpty()
754633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko                && mDataManager.getSeriesRecordings().isEmpty());
755633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko    }
756633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko
7572e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    @WorkerThread
75865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @VisibleForTesting
75965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    // Should be public to use mock DvrManager object.
76065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void addListener(Listener listener, @NonNull Handler handler) {
7612e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        SoftPreconditions.checkNotNull(handler);
7622e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        synchronized (mListener) {
7632e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko            mListener.put(listener, handler);
7642e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        }
7652e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    }
7662e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko
7672e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    @WorkerThread
76865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    @VisibleForTesting
76965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    // Should be public to use mock DvrManager object.
77065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    public void removeListener(Listener listener) {
7712e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        synchronized (mListener) {
7722e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko            mListener.remove(listener);
7732e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        }
7742e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    }
7752e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko
7762e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko    /**
77765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * Returns ScheduledRecording.builder based on {@code program}. If program is already started,
77865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     * recording started time is clipped to the current time.
77965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko     */
78095961816a768da387f0b5523cf4363ace2044089Nick Chalko    private ScheduledRecording.Builder createScheduledRecordingBuilder(
78195961816a768da387f0b5523cf4363ace2044089Nick Chalko            String inputId, Program program) {
78265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        ScheduledRecording.Builder builder = ScheduledRecording.builder(inputId, program);
78365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        long time = System.currentTimeMillis();
78465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        if (program.getStartTimeUtcMillis() < time && time < program.getEndTimeUtcMillis()) {
78565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            builder.setStartTimeMs(time);
78665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
78765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return builder;
78865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
78965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
79095961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Returns a schedule which matches to the given episode. */
79195961816a768da387f0b5523cf4363ace2044089Nick Chalko    public ScheduledRecording getScheduledRecording(
79295961816a768da387f0b5523cf4363ace2044089Nick Chalko            String title, String seasonNumber, String episodeNumber) {
79395961816a768da387f0b5523cf4363ace2044089Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isInitialized())
79495961816a768da387f0b5523cf4363ace2044089Nick Chalko                || title == null
79595961816a768da387f0b5523cf4363ace2044089Nick Chalko                || seasonNumber == null
79695961816a768da387f0b5523cf4363ace2044089Nick Chalko                || episodeNumber == null) {
79765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return null;
79865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
79965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (ScheduledRecording r : mDataManager.getAllScheduledRecordings()) {
80065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (title.equals(r.getProgramTitle())
80165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    && seasonNumber.equals(r.getSeasonNumber())
80265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    && episodeNumber.equals(r.getEpisodeNumber())) {
80365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                return r;
80465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
80565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
80665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return null;
80765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
80865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
80995961816a768da387f0b5523cf4363ace2044089Nick Chalko    /** Returns a recorded program which is the same episode as the given {@code program}. */
81095961816a768da387f0b5523cf4363ace2044089Nick Chalko    public RecordedProgram getRecordedProgram(
81195961816a768da387f0b5523cf4363ace2044089Nick Chalko            String title, String seasonNumber, String episodeNumber) {
81295961816a768da387f0b5523cf4363ace2044089Nick Chalko        if (!SoftPreconditions.checkState(mDataManager.isInitialized())
81395961816a768da387f0b5523cf4363ace2044089Nick Chalko                || title == null
81495961816a768da387f0b5523cf4363ace2044089Nick Chalko                || seasonNumber == null
81595961816a768da387f0b5523cf4363ace2044089Nick Chalko                || episodeNumber == null) {
81665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            return null;
81765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
81865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        for (RecordedProgram r : mDataManager.getRecordedPrograms()) {
81965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            if (title.equals(r.getTitle())
82065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    && seasonNumber.equals(r.getSeasonNumber())
82165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    && episodeNumber.equals(r.getEpisodeNumber())
82265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                    && !r.isClipped()) {
82365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko                return r;
82465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko            }
82565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        }
82665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko        return null;
82765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    }
82865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko
829d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    @WorkerThread
830d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    private void removeRecordedData(Uri dataUri) {
831d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        try {
83295961816a768da387f0b5523cf4363ace2044089Nick Chalko            if (dataUri != null
83395961816a768da387f0b5523cf4363ace2044089Nick Chalko                    && ContentResolver.SCHEME_FILE.equals(dataUri.getScheme())
834d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    && dataUri.getPath() != null) {
835d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                File recordedProgramPath = new File(dataUri.getPath());
836d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                if (!recordedProgramPath.exists()) {
837d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    if (DEBUG) Log.d(TAG, "File to delete not exist: " + recordedProgramPath);
838d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                } else {
839944779887775bd950cf1abf348d2df461593f6abLive Channels Team                    CommonUtils.deleteDirOrFile(recordedProgramPath);
840d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    if (DEBUG) {
841d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                        Log.d(TAG, "Sucessfully deleted files of the recorded program: " + dataUri);
842d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                    }
843d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko                }
844d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
845d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        } catch (SecurityException e) {
846d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            if (DEBUG) {
84795961816a768da387f0b5523cf4363ace2044089Nick Chalko                Log.d(
84895961816a768da387f0b5523cf4363ace2044089Nick Chalko                        TAG,
84995961816a768da387f0b5523cf4363ace2044089Nick Chalko                        "To delete this recorded program, please manually delete video data at"
85095961816a768da387f0b5523cf4363ace2044089Nick Chalko                                + "\nadb shell rm -rf "
85195961816a768da387f0b5523cf4363ace2044089Nick Chalko                                + dataUri);
852d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            }
853d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
854d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
855d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
856d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    /**
857d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko     * Remove all the records related to the input.
85895961816a768da387f0b5523cf4363ace2044089Nick Chalko     *
85995961816a768da387f0b5523cf4363ace2044089Nick Chalko     * <p>Note that this should be called after the input was removed.
860d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko     */
861d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    public void forgetStorage(String inputId) {
862d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        if (mDataManager.isInitialized()) {
863d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko            mDataManager.forgetStorage(inputId);
864d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko        }
865d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko    }
866d41f0075a7d2ea826204e81fcec57d0aa57171a9Nick Chalko
86765fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko    /**
868633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko     * Listener to stop recording request. Should only be internally used inside dvr and its
869633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko     * sub-package.
8702e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko     */
871633eb826b8c97731dfc5ef12c7bf78a63734275dNick Chalko    public interface Listener {
8722e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko        void onStopRecordingRequested(ScheduledRecording scheduledRecording);
873ba5845f23b8fbc985890f892961abc8b39886611Nick Chalko    }
8741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko}
875