Home | History | Annotate | Download | only in data
      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.data;
     18 
     19 import android.content.ContentUris;
     20 import android.content.ContentValues;
     21 import android.content.Context;
     22 import android.database.Cursor;
     23 import android.database.sqlite.SQLiteException;
     24 import android.media.tv.TvContract;
     25 import android.media.tv.TvContract.Programs;
     26 import android.net.Uri;
     27 import android.util.Log;
     28 import com.android.tv.common.TvContentRatingCache;
     29 import com.android.tv.common.util.Clock;
     30 import java.util.ArrayList;
     31 import java.util.Map;
     32 import java.util.concurrent.TimeUnit;
     33 
     34 /** Static utilities for using Programs in tests */
     35 public final class ProgramUtils {
     36     private static final String TAG = "ProgramUtils";
     37     private static final boolean DEBUG = false;
     38 
     39     /** Populate program data for a week */
     40     public static final long PROGRAM_INSERT_DURATION_MS = TimeUnit.DAYS.toMillis(7);
     41 
     42     private static final int MAX_DB_INSERT_COUNT_AT_ONCE = 500;
     43 
     44     /**
     45      * Populate programs by repeating given program information. This method will populate programs
     46      * without any gap nor overlapping starting from the current time.
     47      */
     48     public static void populatePrograms(
     49             Context context, Uri channelUri, ProgramInfo program, Clock clock) {
     50         populatePrograms(context, channelUri, program, clock, PROGRAM_INSERT_DURATION_MS);
     51     }
     52 
     53     public static void populatePrograms(
     54             Context context,
     55             Uri channelUri,
     56             ProgramInfo program,
     57             Clock clock,
     58             long programInsertDurationMs) {
     59         long currentTimeMs = clock.currentTimeMillis();
     60         long targetEndTimeMs = currentTimeMs + programInsertDurationMs;
     61         populatePrograms(context, channelUri, program, currentTimeMs, targetEndTimeMs);
     62     }
     63 
     64     public static void populatePrograms(
     65             Context context,
     66             Uri channelUri,
     67             ProgramInfo program,
     68             long currentTimeMs,
     69             long targetEndTimeMs) {
     70         ContentValues values = new ContentValues();
     71         long channelId = ContentUris.parseId(channelUri);
     72 
     73         values.put(Programs.COLUMN_CHANNEL_ID, channelId);
     74         values.put(Programs.COLUMN_SHORT_DESCRIPTION, program.description);
     75         values.put(
     76                 Programs.COLUMN_CONTENT_RATING,
     77                 TvContentRatingCache.contentRatingsToString(program.contentRatings));
     78 
     79         long timeMs = getLastProgramEndTimeMs(context, channelUri, currentTimeMs, targetEndTimeMs);
     80         if (timeMs <= 0) {
     81             timeMs = currentTimeMs;
     82         }
     83         int index = program.getIndex(timeMs, channelId);
     84         timeMs = program.getStartTimeMs(index, channelId);
     85 
     86         ArrayList<ContentValues> list = new ArrayList<>();
     87         while (timeMs < targetEndTimeMs) {
     88             ProgramInfo programAt = program.build(context, index++);
     89             values.put(Programs.COLUMN_TITLE, programAt.title);
     90             values.put(Programs.COLUMN_EPISODE_TITLE, programAt.episode);
     91             if (programAt.seasonNumber != 0) {
     92                 values.put(Programs.COLUMN_SEASON_NUMBER, programAt.seasonNumber);
     93             }
     94             if (programAt.episodeNumber != 0) {
     95                 values.put(Programs.COLUMN_EPISODE_NUMBER, programAt.episodeNumber);
     96             }
     97             values.put(Programs.COLUMN_POSTER_ART_URI, programAt.posterArtUri);
     98             values.put(Programs.COLUMN_START_TIME_UTC_MILLIS, timeMs);
     99             values.put(Programs.COLUMN_END_TIME_UTC_MILLIS, timeMs + programAt.durationMs);
    100             values.put(Programs.COLUMN_CANONICAL_GENRE, programAt.genre);
    101             values.put(Programs.COLUMN_POSTER_ART_URI, programAt.posterArtUri);
    102             list.add(new ContentValues(values));
    103             timeMs += programAt.durationMs;
    104 
    105             if (list.size() >= MAX_DB_INSERT_COUNT_AT_ONCE || timeMs >= targetEndTimeMs) {
    106                 try {
    107                     context.getContentResolver()
    108                             .bulkInsert(
    109                                     Programs.CONTENT_URI,
    110                                     list.toArray(new ContentValues[list.size()]));
    111                 } catch (SQLiteException e) {
    112                     Log.e(TAG, "Can't insert EPG.", e);
    113                     return;
    114                 }
    115                 if (DEBUG) Log.d(TAG, "Inserted " + list.size() + " programs for " + channelUri);
    116                 list.clear();
    117             }
    118         }
    119     }
    120 
    121     private static long getLastProgramEndTimeMs(
    122             Context context, Uri channelUri, long startTimeMs, long endTimeMs) {
    123         Uri uri = TvContract.buildProgramsUriForChannel(channelUri, startTimeMs, endTimeMs);
    124         String[] projection = {Programs.COLUMN_END_TIME_UTC_MILLIS};
    125         try (Cursor cursor =
    126                 context.getContentResolver().query(uri, projection, null, null, null)) {
    127             if (cursor != null && cursor.moveToLast()) {
    128                 return cursor.getLong(0);
    129             }
    130         }
    131         return 0;
    132     }
    133 
    134     private ProgramUtils() {}
    135 
    136     public static void updateProgramForAllChannelsOf(
    137             Context context, String inputId, Clock clock, long durationMs) {
    138         // Reload channels so we have the ids.
    139         Map<Long, ChannelInfo> channelIdToInfoMap =
    140                 ChannelUtils.queryChannelInfoMapForTvInput(context, inputId);
    141         for (Long channelId : channelIdToInfoMap.keySet()) {
    142             ProgramInfo programInfo = ProgramInfo.create();
    143             populatePrograms(
    144                     context, TvContract.buildChannelUri(channelId), programInfo, clock, durationMs);
    145         }
    146     }
    147 }
    148