/* * Copyright (C) 2015 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.testing.data; import android.content.Context; import android.database.Cursor; import android.media.tv.TvContentRating; import android.media.tv.TvContract; import com.android.tv.testing.R; import com.android.tv.testing.utils.Utils; import java.util.Arrays; import java.util.Objects; import java.util.concurrent.TimeUnit; public final class ProgramInfo { /** If this is specify for title, it will be generated by adding index. */ public static final String GEN_TITLE = ""; /** * If this is specify for episode title, it will be generated by adding index. Also, season and * episode numbers would be generated, too. see: {@link #build} for detail. */ public static final String GEN_EPISODE = ""; private static final int SEASON_MAX = 10; private static final int EPISODE_MAX = 12; /** * If this is specify for poster art, it will be selected one of {@link #POSTER_ARTS_RES} in * order. */ public static final String GEN_POSTER = "GEN"; private static final int[] POSTER_ARTS_RES = { 0, R.drawable.blue, R.drawable.red_large, R.drawable.green, R.drawable.red, R.drawable.green_large, R.drawable.blue_small }; /** * If this is specified for duration, it will be selected one of {@link #DURATIONS_MS} in order. */ public static final int GEN_DURATION = -1; private static final long[] DURATIONS_MS = { TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(45), TimeUnit.MINUTES.toMillis(90), TimeUnit.MINUTES.toMillis(60), TimeUnit.MINUTES.toMillis(30), TimeUnit.MINUTES.toMillis(45), TimeUnit.MINUTES.toMillis(60), TimeUnit.MINUTES.toMillis(90), TimeUnit.HOURS.toMillis(5) }; private static long durationsSumMs; static { durationsSumMs = 0; for (long duration : DURATIONS_MS) { durationsSumMs += duration; } } /** If this is specified for genre, it will be selected one of {@link #GENRES} in order. */ public static final String GEN_GENRE = "GEN"; private static final String[] GENRES = { "", TvContract.Programs.Genres.SPORTS, TvContract.Programs.Genres.NEWS, TvContract.Programs.Genres.SHOPPING, TvContract.Programs.Genres.DRAMA, TvContract.Programs.Genres.ENTERTAINMENT }; public final String title; public final String episode; public final int seasonNumber; public final int episodeNumber; public final String posterArtUri; public final String description; public final long durationMs; public final String genre; public final TvContentRating[] contentRatings; public final String resourceUri; public static ProgramInfo fromCursor(Cursor c) { // TODO: Fill other fields. Builder builder = new Builder(); int index = c.getColumnIndex(TvContract.Programs.COLUMN_TITLE); if (index >= 0) { builder.setTitle(c.getString(index)); } index = c.getColumnIndex(TvContract.Programs.COLUMN_SHORT_DESCRIPTION); if (index >= 0) { builder.setDescription(c.getString(index)); } index = c.getColumnIndex(TvContract.Programs.COLUMN_EPISODE_TITLE); if (index >= 0) { builder.setEpisode(c.getString(index)); } return builder.build(); } public ProgramInfo( String title, String episode, int seasonNumber, int episodeNumber, String posterArtUri, String description, long durationMs, TvContentRating[] contentRatings, String genre, String resourceUri) { this.title = title; this.episode = episode; this.seasonNumber = seasonNumber; this.episodeNumber = episodeNumber; this.posterArtUri = posterArtUri; this.description = description; this.durationMs = durationMs; this.contentRatings = contentRatings; this.genre = genre; this.resourceUri = resourceUri; } /** * Create a instance of {@link ProgramInfo} whose content will be generated as much as possible. */ public static ProgramInfo create() { return new Builder().build(); } /** * Get index of the program whose start time equals or less than {@code timeMs} and end time * more than {@code timeMs}. * * @param timeMs target time in millis to find a program. * @param channelId used to add complexity to the index between two consequence channels. */ public int getIndex(long timeMs, long channelId) { if (durationMs != GEN_DURATION) { return Math.max((int) (timeMs / durationMs), 0); } long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))]; int index = (int) ((timeMs - startTimeMs) / durationsSumMs) * DURATIONS_MS.length; startTimeMs += (index / DURATIONS_MS.length) * durationsSumMs; while (startTimeMs + DURATIONS_MS[index % DURATIONS_MS.length] < timeMs) { startTimeMs += DURATIONS_MS[index % DURATIONS_MS.length]; index++; } return index; } /** * Returns the start time for the program with the position. * * @param index index returned by {@link #getIndex} */ public long getStartTimeMs(int index, long channelId) { if (durationMs != GEN_DURATION) { return index * durationMs; } long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))] + (index / DURATIONS_MS.length) * durationsSumMs; for (int i = 0; i < index % DURATIONS_MS.length; i++) { startTimeMs += DURATIONS_MS[i]; } return startTimeMs; } /** * Return complete {@link ProgramInfo} with the generated value. See: {@link #GEN_TITLE}, {@link * #GEN_EPISODE}, {@link #GEN_POSTER}, {@link #GEN_DURATION}, {@link #GEN_GENRE}. * * @param index index returned by {@link #getIndex} */ public ProgramInfo build(Context context, int index) { if (!GEN_TITLE.equals(title) && episode == null && !GEN_POSTER.equals(posterArtUri) && durationMs != GEN_DURATION && !GEN_GENRE.equals(genre)) { return this; } return new ProgramInfo( GEN_TITLE.equals(title) ? "Title(" + index + ")" : title, GEN_EPISODE.equals(episode) ? "Episode(" + index + ")" : episode, episode != null ? (index % SEASON_MAX + 1) : seasonNumber, episode != null ? (index % EPISODE_MAX + 1) : episodeNumber, GEN_POSTER.equals(posterArtUri) ? Utils.getUriStringForResource( context, POSTER_ARTS_RES[index % POSTER_ARTS_RES.length]) : posterArtUri, description, durationMs == GEN_DURATION ? DURATIONS_MS[index % DURATIONS_MS.length] : durationMs, contentRatings, GEN_GENRE.equals(genre) ? GENRES[index % GENRES.length] : genre, resourceUri); } @Override public String toString() { return "ProgramInfo{title=" + title + ", episode=" + episode + ", durationMs=" + durationMs + "}"; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } ProgramInfo that = (ProgramInfo) o; return Objects.equals(seasonNumber, that.seasonNumber) && Objects.equals(episodeNumber, that.episodeNumber) && Objects.equals(durationMs, that.durationMs) && Objects.equals(title, that.title) && Objects.equals(episode, that.episode) && Objects.equals(posterArtUri, that.posterArtUri) && Objects.equals(description, that.description) && Objects.equals(genre, that.genre) && Arrays.equals(contentRatings, that.contentRatings) && Objects.equals(resourceUri, that.resourceUri); } @Override public int hashCode() { return Objects.hash(title, episode, seasonNumber, episodeNumber); } public static class Builder { private String mTitle = GEN_TITLE; private String mEpisode = GEN_EPISODE; private int mSeasonNumber; private int mEpisodeNumber; private String mPosterArtUri = GEN_POSTER; private String mDescription; private long mDurationMs = GEN_DURATION; private TvContentRating[] mContentRatings; private String mGenre = GEN_GENRE; private String mResourceUri; public Builder setTitle(String title) { mTitle = title; return this; } public Builder setEpisode(String episode) { mEpisode = episode; return this; } public Builder setSeasonNumber(int seasonNumber) { mSeasonNumber = seasonNumber; return this; } public Builder setEpisodeNumber(int episodeNumber) { mEpisodeNumber = episodeNumber; return this; } public Builder setPosterArtUri(String posterArtUri) { mPosterArtUri = posterArtUri; return this; } public Builder setDescription(String description) { mDescription = description; return this; } public Builder setDurationMs(long durationMs) { mDurationMs = durationMs; return this; } public Builder setContentRatings(TvContentRating[] contentRatings) { mContentRatings = contentRatings; return this; } public Builder setGenre(String genre) { mGenre = genre; return this; } public Builder setResourceUri(String resourceUri) { mResourceUri = resourceUri; return this; } public ProgramInfo build() { return new ProgramInfo( mTitle, mEpisode, mSeasonNumber, mEpisodeNumber, mPosterArtUri, mDescription, mDurationMs, mContentRatings, mGenre, mResourceUri); } } }