aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tv/dvr/EpisodicProgramLoadTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/tv/dvr/EpisodicProgramLoadTask.java')
-rw-r--r--src/com/android/tv/dvr/EpisodicProgramLoadTask.java382
1 files changed, 0 insertions, 382 deletions
diff --git a/src/com/android/tv/dvr/EpisodicProgramLoadTask.java b/src/com/android/tv/dvr/EpisodicProgramLoadTask.java
deleted file mode 100644
index 15ca2700..00000000
--- a/src/com/android/tv/dvr/EpisodicProgramLoadTask.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.dvr;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.database.Cursor;
-import android.media.tv.TvContract;
-import android.media.tv.TvContract.Programs;
-import android.net.Uri;
-import android.os.Build;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.annotation.WorkerThread;
-import android.text.TextUtils;
-
-import com.android.tv.TvApplication;
-import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Program;
-import com.android.tv.util.AsyncDbTask.AsyncProgramQueryTask;
-import com.android.tv.util.AsyncDbTask.CursorFilter;
-import com.android.tv.util.PermissionUtils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * A wrapper of AsyncProgramQueryTask to load the episodic programs for the series recordings.
- */
-@TargetApi(Build.VERSION_CODES.N)
-abstract public class EpisodicProgramLoadTask {
- private static final String TAG = "EpisodicProgramLoadTask";
-
- private static final int PROGRAM_ID_INDEX = Program.getColumnIndex(Programs._ID);
- private static final int START_TIME_INDEX =
- Program.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS);
- private static final int RECORDING_PROHIBITED_INDEX =
- Program.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED);
-
- private static final String PARAM_START_TIME = "start_time";
- private static final String PARAM_END_TIME = "end_time";
-
- private static final String PROGRAM_PREDICATE =
- Programs.COLUMN_START_TIME_UTC_MILLIS + ">? AND "
- + Programs.COLUMN_RECORDING_PROHIBITED + "=0";
- private static final String PROGRAM_PREDICATE_WITH_CURRENT_PROGRAM =
- Programs.COLUMN_END_TIME_UTC_MILLIS + ">? AND "
- + Programs.COLUMN_RECORDING_PROHIBITED + "=0";
- private static final String CHANNEL_ID_PREDICATE = Programs.COLUMN_CHANNEL_ID + "=?";
- private static final String PROGRAM_TITLE_PREDICATE = Programs.COLUMN_TITLE + "=?";
-
- private final Context mContext;
- private final DvrDataManager mDataManager;
- private boolean mQueryAllChannels;
- private boolean mLoadCurrentProgram;
- private boolean mLoadScheduledEpisode;
- private boolean mLoadDisallowedProgram;
- // If true, match programs with OPTION_CHANNEL_ALL.
- private boolean mIgnoreChannelOption;
- private final ArrayList<SeriesRecording> mSeriesRecordings = new ArrayList<>();
- private AsyncProgramQueryTask mProgramQueryTask;
-
- /**
- *
- * Constructor used to load programs for one series recording with the given channel option.
- */
- public EpisodicProgramLoadTask(Context context, SeriesRecording seriesRecording) {
- this(context, Collections.singletonList(seriesRecording));
- }
-
- /**
- * Constructor used to load programs for multiple series recordings. The channel option is
- * {@link SeriesRecording#OPTION_CHANNEL_ALL}.
- */
- public EpisodicProgramLoadTask(Context context, Collection<SeriesRecording> seriesRecordings) {
- mContext = context.getApplicationContext();
- mDataManager = TvApplication.getSingletons(context).getDvrDataManager();
- mSeriesRecordings.addAll(seriesRecordings);
- }
-
- /**
- * Returns the series recordings.
- */
- public List<SeriesRecording> getSeriesRecordings() {
- return mSeriesRecordings;
- }
-
- /**
- * Returns the program query task. It is {@code null} until it is executed.
- */
- @Nullable
- public AsyncProgramQueryTask getTask() {
- return mProgramQueryTask;
- }
-
- /**
- * Enables loading current programs. The default value is {@code false}.
- */
- public EpisodicProgramLoadTask setLoadCurrentProgram(boolean loadCurrentProgram) {
- SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
- "Can't change setting after execution.");
- mLoadCurrentProgram = loadCurrentProgram;
- return this;
- }
-
- /**
- * Enables already schedules episodes. The default value is {@code false}.
- */
- public EpisodicProgramLoadTask setLoadScheduledEpisode(boolean loadScheduledEpisode) {
- SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
- "Can't change setting after execution.");
- mLoadScheduledEpisode = loadScheduledEpisode;
- return this;
- }
-
- /**
- * Enables loading disallowed programs whose schedules were removed manually by the user.
- * The default value is {@code false}.
- */
- public EpisodicProgramLoadTask setLoadDisallowedProgram(boolean loadDisallowedProgram) {
- SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
- "Can't change setting after execution.");
- mLoadDisallowedProgram = loadDisallowedProgram;
- return this;
- }
-
- /**
- * Gives the option whether to ignore the channel option when matching programs.
- * If {@code ignoreChannelOption} is {@code true}, the program will be matched with
- * {@link SeriesRecording#OPTION_CHANNEL_ALL} option.
- */
- public EpisodicProgramLoadTask setIgnoreChannelOption(boolean ignoreChannelOption) {
- SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
- "Can't change setting after execution.");
- mIgnoreChannelOption = ignoreChannelOption;
- return this;
- }
-
- /**
- * Executes the task.
- *
- * @see com.android.tv.util.AsyncDbTask#executeOnDbThread
- */
- public void execute() {
- if (SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
- "Can't execute task: the task is already running.")) {
- mQueryAllChannels = mSeriesRecordings.size() > 1
- || mSeriesRecordings.get(0).getChannelOption()
- == SeriesRecording.OPTION_CHANNEL_ALL
- || mIgnoreChannelOption;
- mProgramQueryTask = createTask();
- mProgramQueryTask.executeOnDbThread();
- }
- }
-
- /**
- * Cancels the task.
- *
- * @see android.os.AsyncTask#cancel
- */
- public void cancel(boolean mayInterruptIfRunning) {
- if (mProgramQueryTask != null) {
- mProgramQueryTask.cancel(mayInterruptIfRunning);
- }
- }
-
- /**
- * Runs on the UI thread after the program loading finishes successfully.
- */
- protected void onPostExecute(List<Program> programs) {
- }
-
- /**
- * Runs on the UI thread after the program loading was canceled.
- */
- protected void onCancelled(List<Program> programs) {
- }
-
- private AsyncProgramQueryTask createTask() {
- SqlParams sqlParams = createSqlParams();
- return new AsyncProgramQueryTask(mContext.getContentResolver(), sqlParams.uri,
- sqlParams.selection, sqlParams.selectionArgs, null, sqlParams.filter) {
- @Override
- protected void onPostExecute(List<Program> programs) {
- EpisodicProgramLoadTask.this.onPostExecute(programs);
- }
-
- @Override
- protected void onCancelled(List<Program> programs) {
- EpisodicProgramLoadTask.this.onCancelled(programs);
- }
- };
- }
-
- private SqlParams createSqlParams() {
- SqlParams sqlParams = new SqlParams();
- if (PermissionUtils.hasAccessAllEpg(mContext)) {
- sqlParams.uri = Programs.CONTENT_URI;
- // Base
- StringBuilder selection = new StringBuilder(mLoadCurrentProgram
- ? PROGRAM_PREDICATE_WITH_CURRENT_PROGRAM : PROGRAM_PREDICATE);
- List<String> args = new ArrayList<>();
- args.add(Long.toString(System.currentTimeMillis()));
- // Channel option
- if (!mQueryAllChannels) {
- selection.append(" AND ").append(CHANNEL_ID_PREDICATE);
- args.add(Long.toString(mSeriesRecordings.get(0).getChannelId()));
- }
- // Title
- if (mSeriesRecordings.size() == 1) {
- selection.append(" AND ").append(PROGRAM_TITLE_PREDICATE);
- args.add(mSeriesRecordings.get(0).getTitle());
- }
- sqlParams.selection = selection.toString();
- sqlParams.selectionArgs = args.toArray(new String[args.size()]);
- sqlParams.filter = new SeriesRecordingCursorFilter(mSeriesRecordings);
- } else {
- // The query includes the current program. Will be filtered if needed.
- if (mQueryAllChannels) {
- sqlParams.uri = Programs.CONTENT_URI.buildUpon()
- .appendQueryParameter(PARAM_START_TIME,
- String.valueOf(System.currentTimeMillis()))
- .appendQueryParameter(PARAM_END_TIME, String.valueOf(Long.MAX_VALUE))
- .build();
- } else {
- sqlParams.uri = TvContract.buildProgramsUriForChannel(
- mSeriesRecordings.get(0).getChannelId(),
- System.currentTimeMillis(), Long.MAX_VALUE);
- }
- sqlParams.selection = null;
- sqlParams.selectionArgs = null;
- sqlParams.filter = new SeriesRecordingCursorFilterForNonSystem(mSeriesRecordings);
- }
- return sqlParams;
- }
-
- @VisibleForTesting
- static boolean isEpisodeScheduled(Collection<ScheduledEpisode> scheduledEpisodes,
- ScheduledEpisode episode) {
- // The episode whose season number or episode number is null will always be scheduled.
- return scheduledEpisodes.contains(episode) && !TextUtils.isEmpty(episode.seasonNumber)
- && !TextUtils.isEmpty(episode.episodeNumber);
- }
-
- /**
- * Filter the programs which match the series recording. The episodes which the schedules are
- * already created for are filtered out too.
- */
- private class SeriesRecordingCursorFilter implements CursorFilter {
- private final Set<Long> mDisallowedProgramIds = new HashSet<>();
- private final Set<ScheduledEpisode> mScheduledEpisodes = new HashSet<>();
-
- SeriesRecordingCursorFilter(List<SeriesRecording> seriesRecordings) {
- if (!mLoadDisallowedProgram) {
- mDisallowedProgramIds.addAll(mDataManager.getDisallowedProgramIds());
- }
- if (!mLoadScheduledEpisode) {
- Set<Long> seriesRecordingIds = new HashSet<>();
- for (SeriesRecording r : seriesRecordings) {
- seriesRecordingIds.add(r.getId());
- }
- for (ScheduledRecording r : mDataManager.getAllScheduledRecordings()) {
- if (seriesRecordingIds.contains(r.getSeriesRecordingId())
- && r.getState() != ScheduledRecording.STATE_RECORDING_FAILED
- && r.getState() != ScheduledRecording.STATE_RECORDING_CLIPPED) {
- mScheduledEpisodes.add(new ScheduledEpisode(r));
- }
- }
- }
- }
-
- @Override
- @WorkerThread
- public boolean filter(Cursor c) {
- if (!mLoadDisallowedProgram
- && mDisallowedProgramIds.contains(c.getLong(PROGRAM_ID_INDEX))) {
- return false;
- }
- Program program = Program.fromCursor(c);
- for (SeriesRecording seriesRecording : mSeriesRecordings) {
- boolean programMatches;
- if (mIgnoreChannelOption) {
- programMatches = seriesRecording.matchProgram(program,
- SeriesRecording.OPTION_CHANNEL_ALL);
- } else {
- programMatches = seriesRecording.matchProgram(program);
- }
- if (programMatches) {
- return mLoadScheduledEpisode
- || !isEpisodeScheduled(mScheduledEpisodes, new ScheduledEpisode(
- seriesRecording.getId(), program.getSeasonNumber(),
- program.getEpisodeNumber()));
- }
- }
- return false;
- }
- }
-
- private class SeriesRecordingCursorFilterForNonSystem extends SeriesRecordingCursorFilter {
- SeriesRecordingCursorFilterForNonSystem(List<SeriesRecording> seriesRecordings) {
- super(seriesRecordings);
- }
-
- @Override
- public boolean filter(Cursor c) {
- return (mLoadCurrentProgram || c.getLong(START_TIME_INDEX) > System.currentTimeMillis())
- && c.getInt(RECORDING_PROHIBITED_INDEX) != 0 && super.filter(c);
- }
- }
-
- private static class SqlParams {
- public Uri uri;
- public String selection;
- public String[] selectionArgs;
- public CursorFilter filter;
- }
-
- /**
- * A plain java object which includes the season/episode number for the series recording.
- */
- public static class ScheduledEpisode {
- public final long seriesRecordingId;
- public final String seasonNumber;
- public final String episodeNumber;
-
- /**
- * Create a new Builder with the values set from an existing {@link ScheduledRecording}.
- */
- ScheduledEpisode(ScheduledRecording r) {
- this(r.getSeriesRecordingId(), r.getSeasonNumber(), r.getEpisodeNumber());
- }
-
- public ScheduledEpisode(long seriesRecordingId, String seasonNumber, String episodeNumber) {
- this.seriesRecordingId = seriesRecordingId;
- this.seasonNumber = seasonNumber;
- this.episodeNumber = episodeNumber;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (!(o instanceof ScheduledEpisode)) return false;
- ScheduledEpisode that = (ScheduledEpisode) o;
- return seriesRecordingId == that.seriesRecordingId
- && Objects.equals(seasonNumber, that.seasonNumber)
- && Objects.equals(episodeNumber, that.episodeNumber);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(seriesRecordingId, seasonNumber, episodeNumber);
- }
-
- @Override
- public String toString() {
- return "ScheduledEpisode{" +
- "seriesRecordingId=" + seriesRecordingId +
- ", seasonNumber='" + seasonNumber +
- ", episodeNumber=" + episodeNumber +
- '}';
- }
- }
-}