Home | History | Annotate | Download | only in testing
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.tv.testing;
     18 
     19 import android.content.Context;
     20 import android.database.Cursor;
     21 import android.media.tv.TvContentRating;
     22 import android.media.tv.TvContract;
     23 
     24 import java.util.Objects;
     25 import java.util.concurrent.TimeUnit;
     26 
     27 public final class ProgramInfo {
     28     /**
     29      * If this is specify for title, it will be generated by adding index.
     30      */
     31     public static final String GEN_TITLE = "";
     32 
     33     /**
     34      * If this is specify for episode title, it will be generated by adding index.
     35      * Also, season and episode numbers would be generated, too.
     36      * see: {@link #build} for detail.
     37      */
     38     public static final String GEN_EPISODE = "";
     39     private static final int SEASON_MAX = 10;
     40     private static final int EPISODE_MAX = 12;
     41 
     42     /**
     43      * If this is specify for poster art,
     44      * it will be selected one of {@link #POSTER_ARTS_RES} in order.
     45      */
     46     public static final String GEN_POSTER = "GEN";
     47     private static final int[] POSTER_ARTS_RES = {
     48             0,
     49             R.drawable.blue,
     50             R.drawable.red_large,
     51             R.drawable.green,
     52             R.drawable.red,
     53             R.drawable.green_large,
     54             R.drawable.blue_small};
     55 
     56     /**
     57      * If this is specified for duration,
     58      * it will be selected one of {@link #DURATIONS_MS} in order.
     59      */
     60     public static final int GEN_DURATION = -1;
     61     private static final long[] DURATIONS_MS = {
     62             TimeUnit.MINUTES.toMillis(15),
     63             TimeUnit.MINUTES.toMillis(45),
     64             TimeUnit.MINUTES.toMillis(90),
     65             TimeUnit.MINUTES.toMillis(60),
     66             TimeUnit.MINUTES.toMillis(30),
     67             TimeUnit.MINUTES.toMillis(45),
     68             TimeUnit.MINUTES.toMillis(60),
     69             TimeUnit.MINUTES.toMillis(90),
     70             TimeUnit.HOURS.toMillis(5)};
     71     private static long DURATIONS_SUM_MS;
     72     static {
     73         DURATIONS_SUM_MS = 0;
     74         for (long duration : DURATIONS_MS) {
     75             DURATIONS_SUM_MS += duration;
     76         }
     77     }
     78 
     79     /**
     80      * If this is specified for genre,
     81      * it will be selected one of {@link #GENRES} in order.
     82      */
     83     public static final String GEN_GENRE = "GEN";
     84     private static final String[] GENRES = {
     85             "",
     86             TvContract.Programs.Genres.SPORTS,
     87             TvContract.Programs.Genres.NEWS,
     88             TvContract.Programs.Genres.SHOPPING,
     89             TvContract.Programs.Genres.DRAMA,
     90             TvContract.Programs.Genres.ENTERTAINMENT};
     91 
     92     public final String title;
     93     public final String episode;
     94     public final int seasonNumber;
     95     public final int episodeNumber;
     96     public final String posterArtUri;
     97     public final String description;
     98     public final long durationMs;
     99     public final String genre;
    100     public final TvContentRating[] contentRatings;
    101     public final String resourceUri;
    102 
    103     public static ProgramInfo fromCursor(Cursor c) {
    104         // TODO: Fill other fields.
    105         Builder builder = new Builder();
    106         int index = c.getColumnIndex(TvContract.Programs.COLUMN_TITLE);
    107         if (index >= 0) {
    108             builder.setTitle(c.getString(index));
    109         }
    110         index = c.getColumnIndex(TvContract.Programs.COLUMN_SHORT_DESCRIPTION);
    111         if (index >= 0) {
    112             builder.setDescription(c.getString(index));
    113         }
    114         index = c.getColumnIndex(TvContract.Programs.COLUMN_EPISODE_TITLE);
    115         if (index >= 0) {
    116             builder.setEpisode(c.getString(index));
    117         }
    118         return builder.build();
    119     }
    120 
    121     public ProgramInfo(String title, String episode, int seasonNumber, int episodeNumber,
    122             String posterArtUri, String description, long durationMs,
    123             TvContentRating[] contentRatings, String genre, String resourceUri) {
    124         this.title = title;
    125         this.episode = episode;
    126         this.seasonNumber = seasonNumber;
    127         this.episodeNumber = episodeNumber;
    128         this.posterArtUri = posterArtUri;
    129         this.description = description;
    130         this.durationMs = durationMs;
    131         this.contentRatings = contentRatings;
    132         this.genre = genre;
    133         this.resourceUri = resourceUri;
    134     }
    135 
    136     /**
    137      * Create a instance of {@link ProgramInfo} whose content will be generated as much as possible.
    138      */
    139     public static ProgramInfo create() {
    140         return new Builder().build();
    141     }
    142 
    143     /**
    144      * Get index of the program whose start time equals or less than {@code timeMs} and
    145      * end time more than {@code timeMs}.
    146      * @param timeMs target time in millis to find a program.
    147      * @param channelId used to add complexity to the index between two consequence channels.
    148      */
    149     public int getIndex(long timeMs, long channelId) {
    150         if (durationMs != GEN_DURATION) {
    151             return Math.max((int) (timeMs / durationMs), 0);
    152         }
    153         long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))];
    154         int index = (int) ((timeMs - startTimeMs) / DURATIONS_SUM_MS) * DURATIONS_MS.length;
    155         startTimeMs += (index / DURATIONS_MS.length) * DURATIONS_SUM_MS;
    156         while (startTimeMs + DURATIONS_MS[index % DURATIONS_MS.length] < timeMs) {
    157             startTimeMs += DURATIONS_MS[index % DURATIONS_MS.length];
    158             index++;
    159         }
    160         return index;
    161     }
    162 
    163     /**
    164      * Returns the start time for the program with the position.
    165      * @param index index returned by {@link #getIndex}
    166      */
    167     public long getStartTimeMs(int index, long channelId) {
    168         if (durationMs != GEN_DURATION) {
    169             return index * durationMs;
    170         }
    171         long startTimeMs = channelId * DURATIONS_MS[((int) (channelId % DURATIONS_MS.length))]
    172                 + (index / DURATIONS_MS.length) * DURATIONS_SUM_MS;
    173         for (int i = 0; i < index % DURATIONS_MS.length; i++) {
    174             startTimeMs += DURATIONS_MS[i];
    175         }
    176         return startTimeMs;
    177     }
    178 
    179     /**
    180      * Return complete {@link ProgramInfo} with the generated value.
    181      * See: {@link #GEN_TITLE}, {@link #GEN_EPISODE}, {@link #GEN_POSTER}, {@link #GEN_DURATION},
    182      * {@link #GEN_GENRE}.
    183      * @param index index returned by {@link #getIndex}
    184      */
    185     public ProgramInfo build(Context context, int index) {
    186         if (!GEN_TITLE.equals(title)
    187                 && episode == null
    188                 && !GEN_POSTER.equals(posterArtUri)
    189                 && durationMs != GEN_DURATION
    190                 && !GEN_GENRE.equals(genre)) {
    191             return this;
    192         }
    193         return new ProgramInfo(
    194                 GEN_TITLE.equals(title) ? "Title(" + index + ")" : title,
    195                 GEN_EPISODE.equals(episode) ? "Episode(" + index + ")" : episode,
    196                 episode != null ? (index % SEASON_MAX + 1) : seasonNumber,
    197                 episode != null ? (index % EPISODE_MAX + 1) : episodeNumber,
    198                 GEN_POSTER.equals(posterArtUri)
    199                         ? Utils.getUriStringForResource(context,
    200                                 POSTER_ARTS_RES[index % POSTER_ARTS_RES.length])
    201                         : posterArtUri,
    202                 description,
    203                 durationMs == GEN_DURATION ? DURATIONS_MS[index % DURATIONS_MS.length] : durationMs,
    204                 contentRatings,
    205                 GEN_GENRE.equals(genre) ? GENRES[index % GENRES.length] : genre,
    206                 resourceUri);
    207     }
    208 
    209     @Override
    210     public String toString() {
    211         return "ProgramInfo{title=" + title
    212                 + ", episode=" + episode
    213                 + ", durationMs=" + durationMs + "}";
    214     }
    215 
    216     @Override
    217     public boolean equals(Object o) {
    218         if (this == o) {
    219             return true;
    220         }
    221         if (o == null || getClass() != o.getClass()) {
    222             return false;
    223         }
    224         ProgramInfo that = (ProgramInfo) o;
    225         return Objects.equals(seasonNumber, that.seasonNumber) &&
    226                 Objects.equals(episodeNumber, that.episodeNumber) &&
    227                 Objects.equals(durationMs, that.durationMs) &&
    228                 Objects.equals(title, that.title) &&
    229                 Objects.equals(episode, that.episode) &&
    230                 Objects.equals(posterArtUri, that.posterArtUri) &&
    231                 Objects.equals(description, that.description) &&
    232                 Objects.equals(genre, that.genre) &&
    233                 Objects.equals(contentRatings, that.contentRatings) &&
    234                 Objects.equals(resourceUri, that.resourceUri);
    235     }
    236 
    237     @Override
    238     public int hashCode() {
    239         return Objects.hash(title, episode, seasonNumber, episodeNumber);
    240     }
    241 
    242     public static class Builder {
    243         private String mTitle = GEN_TITLE;
    244         private String mEpisode = GEN_EPISODE;
    245         private int mSeasonNumber;
    246         private int mEpisodeNumber;
    247         private String mPosterArtUri = GEN_POSTER;
    248         private String mDescription;
    249         private long mDurationMs = GEN_DURATION;
    250         private TvContentRating[] mContentRatings;
    251         private String mGenre = GEN_GENRE;
    252         private String mResourceUri;
    253 
    254         public Builder setTitle(String title) {
    255             mTitle = title;
    256             return this;
    257         }
    258 
    259         public Builder setEpisode(String episode) {
    260             mEpisode = episode;
    261             return this;
    262         }
    263 
    264         public Builder setSeasonNumber(int seasonNumber) {
    265             mSeasonNumber = seasonNumber;
    266             return this;
    267         }
    268 
    269         public Builder setEpisodeNumber(int episodeNumber) {
    270             mEpisodeNumber = episodeNumber;
    271             return this;
    272         }
    273 
    274         public Builder setPosterArtUri(String posterArtUri) {
    275             mPosterArtUri = posterArtUri;
    276             return this;
    277         }
    278 
    279         public Builder setDescription(String description) {
    280             mDescription = description;
    281             return this;
    282         }
    283 
    284         public Builder setDurationMs(long durationMs) {
    285             mDurationMs = durationMs;
    286             return this;
    287         }
    288 
    289         public Builder setContentRatings(TvContentRating[] contentRatings) {
    290             mContentRatings = contentRatings;
    291             return this;
    292         }
    293 
    294         public Builder setGenre(String genre) {
    295             mGenre = genre;
    296             return this;
    297         }
    298 
    299         public Builder setResourceUri(String resourceUri) {
    300             mResourceUri = resourceUri;
    301             return this;
    302         }
    303 
    304         public ProgramInfo build() {
    305             return new ProgramInfo(mTitle, mEpisode, mSeasonNumber, mEpisodeNumber, mPosterArtUri,
    306                     mDescription, mDurationMs, mContentRatings, mGenre, mResourceUri);
    307         }
    308     }
    309 }
    310