1 /* 2 * Copyright (C) 2017 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.fakes; 18 19 import android.annotation.SuppressLint; 20 import android.content.ContentProvider; 21 import android.content.ContentProviderOperation; 22 import android.content.ContentProviderResult; 23 import android.content.ContentUris; 24 import android.content.ContentValues; 25 import android.content.Context; 26 import android.content.OperationApplicationException; 27 import android.content.SharedPreferences; 28 import android.content.UriMatcher; 29 import android.content.pm.PackageManager; 30 import android.database.Cursor; 31 import android.database.DatabaseUtils; 32 import android.database.SQLException; 33 import android.database.sqlite.SQLiteDatabase; 34 import android.database.sqlite.SQLiteOpenHelper; 35 import android.database.sqlite.SQLiteQueryBuilder; 36 import android.graphics.Bitmap; 37 import android.graphics.BitmapFactory; 38 import android.media.tv.TvContract; 39 import android.net.Uri; 40 import android.os.AsyncTask; 41 import android.os.Bundle; 42 import android.os.ParcelFileDescriptor; 43 import android.os.ParcelFileDescriptor.AutoCloseInputStream; 44 import android.preference.PreferenceManager; 45 import android.provider.BaseColumns; 46 import android.support.annotation.VisibleForTesting; 47 import android.text.TextUtils; 48 import android.util.Log; 49 import androidx.tvprovider.media.tv.TvContractCompat; 50 import androidx.tvprovider.media.tv.TvContractCompat.BaseTvColumns; 51 import androidx.tvprovider.media.tv.TvContractCompat.Channels; 52 import androidx.tvprovider.media.tv.TvContractCompat.PreviewPrograms; 53 import androidx.tvprovider.media.tv.TvContractCompat.Programs; 54 import androidx.tvprovider.media.tv.TvContractCompat.Programs.Genres; 55 import androidx.tvprovider.media.tv.TvContractCompat.RecordedPrograms; 56 import androidx.tvprovider.media.tv.TvContractCompat.WatchNextPrograms; 57 import com.android.tv.common.util.sql.SqlParams; 58 import java.io.ByteArrayOutputStream; 59 import java.io.FileNotFoundException; 60 import java.io.IOException; 61 import java.util.ArrayList; 62 import java.util.HashMap; 63 import java.util.HashSet; 64 import java.util.Iterator; 65 import java.util.Map; 66 import java.util.Set; 67 import java.util.concurrent.ConcurrentHashMap; 68 69 /** 70 * Fake TV content provider suitable for unit tests. The contract between this provider and 71 * applications is defined in {@link TvContractCompat}. 72 */ 73 // TODO(b/62143348): remove when error prone check fixed 74 @SuppressWarnings({"AndroidApiChecker", "TryWithResources"}) 75 public class FakeTvProvider extends ContentProvider { 76 // TODO either make this a shadow or move it to the support library 77 78 private static final boolean DEBUG = false; 79 private static final String TAG = "TvProvider"; 80 81 static final int DATABASE_VERSION = 34; 82 static final String SHARED_PREF_BLOCKED_PACKAGES_KEY = "blocked_packages"; 83 static final String CHANNELS_TABLE = "channels"; 84 static final String PROGRAMS_TABLE = "programs"; 85 static final String RECORDED_PROGRAMS_TABLE = "recorded_programs"; 86 static final String PREVIEW_PROGRAMS_TABLE = "preview_programs"; 87 static final String WATCH_NEXT_PROGRAMS_TABLE = "watch_next_programs"; 88 static final String WATCHED_PROGRAMS_TABLE = "watched_programs"; 89 static final String PROGRAMS_TABLE_PACKAGE_NAME_INDEX = "programs_package_name_index"; 90 static final String PROGRAMS_TABLE_CHANNEL_ID_INDEX = "programs_channel_id_index"; 91 static final String PROGRAMS_TABLE_START_TIME_INDEX = "programs_start_time_index"; 92 static final String PROGRAMS_TABLE_END_TIME_INDEX = "programs_end_time_index"; 93 static final String WATCHED_PROGRAMS_TABLE_CHANNEL_ID_INDEX = 94 "watched_programs_channel_id_index"; 95 // The internal column in the watched programs table to indicate whether the current log entry 96 // is consolidated or not. Unconsolidated entries may have columns with missing data. 97 static final String WATCHED_PROGRAMS_COLUMN_CONSOLIDATED = "consolidated"; 98 static final String CHANNELS_COLUMN_LOGO = "logo"; 99 private static final String DATABASE_NAME = "tv.db"; 100 private static final String DELETED_CHANNELS_TABLE = "deleted_channels"; // Deprecated 101 private static final String DEFAULT_PROGRAMS_SORT_ORDER = 102 Programs.COLUMN_START_TIME_UTC_MILLIS + " ASC"; 103 private static final String DEFAULT_WATCHED_PROGRAMS_SORT_ORDER = 104 WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS + " DESC"; 105 private static final String CHANNELS_TABLE_INNER_JOIN_PROGRAMS_TABLE = 106 CHANNELS_TABLE 107 + " INNER JOIN " 108 + PROGRAMS_TABLE 109 + " ON (" 110 + CHANNELS_TABLE 111 + "." 112 + Channels._ID 113 + "=" 114 + PROGRAMS_TABLE 115 + "." 116 + Programs.COLUMN_CHANNEL_ID 117 + ")"; 118 119 // Operation names for createSqlParams(). 120 private static final String OP_QUERY = "query"; 121 private static final String OP_UPDATE = "update"; 122 private static final String OP_DELETE = "delete"; 123 124 private static final UriMatcher sUriMatcher; 125 private static final int MATCH_CHANNEL = 1; 126 private static final int MATCH_CHANNEL_ID = 2; 127 private static final int MATCH_CHANNEL_ID_LOGO = 3; 128 private static final int MATCH_PASSTHROUGH_ID = 4; 129 private static final int MATCH_PROGRAM = 5; 130 private static final int MATCH_PROGRAM_ID = 6; 131 private static final int MATCH_WATCHED_PROGRAM = 7; 132 private static final int MATCH_WATCHED_PROGRAM_ID = 8; 133 private static final int MATCH_RECORDED_PROGRAM = 9; 134 private static final int MATCH_RECORDED_PROGRAM_ID = 10; 135 private static final int MATCH_PREVIEW_PROGRAM = 11; 136 private static final int MATCH_PREVIEW_PROGRAM_ID = 12; 137 private static final int MATCH_WATCH_NEXT_PROGRAM = 13; 138 private static final int MATCH_WATCH_NEXT_PROGRAM_ID = 14; 139 140 private static final int MAX_LOGO_IMAGE_SIZE = 256; 141 142 private static final String EMPTY_STRING = ""; 143 144 private static final Map<String, String> sChannelProjectionMap; 145 private static final Map<String, String> sProgramProjectionMap; 146 private static final Map<String, String> sWatchedProgramProjectionMap; 147 private static final Map<String, String> sRecordedProgramProjectionMap; 148 private static final Map<String, String> sPreviewProgramProjectionMap; 149 private static final Map<String, String> sWatchNextProgramProjectionMap; 150 151 // TvContract hidden 152 private static final String PARAM_PACKAGE = "package"; 153 private static final String PARAM_PREVIEW = "preview"; 154 155 private static boolean sInitialized; 156 157 static { 158 sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel", MATCH_CHANNEL)159 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel", MATCH_CHANNEL); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#", MATCH_CHANNEL_ID)160 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#", MATCH_CHANNEL_ID); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#/logo", MATCH_CHANNEL_ID_LOGO)161 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "channel/#/logo", MATCH_CHANNEL_ID_LOGO); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "passthrough/*", MATCH_PASSTHROUGH_ID)162 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "passthrough/*", MATCH_PASSTHROUGH_ID); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program", MATCH_PROGRAM)163 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program", MATCH_PROGRAM); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program/#", MATCH_PROGRAM_ID)164 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "program/#", MATCH_PROGRAM_ID); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "watched_program", MATCH_WATCHED_PROGRAM)165 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "watched_program", MATCH_WATCHED_PROGRAM); sUriMatcher.addURI( TvContractCompat.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID)166 sUriMatcher.addURI( 167 TvContractCompat.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "recorded_program", MATCH_RECORDED_PROGRAM)168 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "recorded_program", MATCH_RECORDED_PROGRAM); sUriMatcher.addURI( TvContractCompat.AUTHORITY, "recorded_program/#", MATCH_RECORDED_PROGRAM_ID)169 sUriMatcher.addURI( 170 TvContractCompat.AUTHORITY, "recorded_program/#", MATCH_RECORDED_PROGRAM_ID); sUriMatcher.addURI(TvContractCompat.AUTHORITY, "preview_program", MATCH_PREVIEW_PROGRAM)171 sUriMatcher.addURI(TvContractCompat.AUTHORITY, "preview_program", MATCH_PREVIEW_PROGRAM); sUriMatcher.addURI( TvContractCompat.AUTHORITY, "preview_program/#", MATCH_PREVIEW_PROGRAM_ID)172 sUriMatcher.addURI( 173 TvContractCompat.AUTHORITY, "preview_program/#", MATCH_PREVIEW_PROGRAM_ID); sUriMatcher.addURI( TvContractCompat.AUTHORITY, "watch_next_program", MATCH_WATCH_NEXT_PROGRAM)174 sUriMatcher.addURI( 175 TvContractCompat.AUTHORITY, "watch_next_program", MATCH_WATCH_NEXT_PROGRAM); sUriMatcher.addURI( TvContractCompat.AUTHORITY, "watch_next_program/#", MATCH_WATCH_NEXT_PROGRAM_ID)176 sUriMatcher.addURI( 177 TvContractCompat.AUTHORITY, "watch_next_program/#", MATCH_WATCH_NEXT_PROGRAM_ID); 178 179 sChannelProjectionMap = new HashMap<>(); sChannelProjectionMap.put(Channels._ID, CHANNELS_TABLE + "." + Channels._ID)180 sChannelProjectionMap.put(Channels._ID, CHANNELS_TABLE + "." + Channels._ID); sChannelProjectionMap.put( Channels.COLUMN_PACKAGE_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_PACKAGE_NAME)181 sChannelProjectionMap.put( 182 Channels.COLUMN_PACKAGE_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_PACKAGE_NAME); sChannelProjectionMap.put( Channels.COLUMN_INPUT_ID, CHANNELS_TABLE + "." + Channels.COLUMN_INPUT_ID)183 sChannelProjectionMap.put( 184 Channels.COLUMN_INPUT_ID, CHANNELS_TABLE + "." + Channels.COLUMN_INPUT_ID); sChannelProjectionMap.put( Channels.COLUMN_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_TYPE)185 sChannelProjectionMap.put( 186 Channels.COLUMN_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_TYPE); sChannelProjectionMap.put( Channels.COLUMN_SERVICE_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_TYPE)187 sChannelProjectionMap.put( 188 Channels.COLUMN_SERVICE_TYPE, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_TYPE); sChannelProjectionMap.put( Channels.COLUMN_ORIGINAL_NETWORK_ID, CHANNELS_TABLE + "." + Channels.COLUMN_ORIGINAL_NETWORK_ID)189 sChannelProjectionMap.put( 190 Channels.COLUMN_ORIGINAL_NETWORK_ID, 191 CHANNELS_TABLE + "." + Channels.COLUMN_ORIGINAL_NETWORK_ID); sChannelProjectionMap.put( Channels.COLUMN_TRANSPORT_STREAM_ID, CHANNELS_TABLE + "." + Channels.COLUMN_TRANSPORT_STREAM_ID)192 sChannelProjectionMap.put( 193 Channels.COLUMN_TRANSPORT_STREAM_ID, 194 CHANNELS_TABLE + "." + Channels.COLUMN_TRANSPORT_STREAM_ID); sChannelProjectionMap.put( Channels.COLUMN_SERVICE_ID, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_ID)195 sChannelProjectionMap.put( 196 Channels.COLUMN_SERVICE_ID, CHANNELS_TABLE + "." + Channels.COLUMN_SERVICE_ID); sChannelProjectionMap.put( Channels.COLUMN_DISPLAY_NUMBER, CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NUMBER)197 sChannelProjectionMap.put( 198 Channels.COLUMN_DISPLAY_NUMBER, 199 CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NUMBER); sChannelProjectionMap.put( Channels.COLUMN_DISPLAY_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NAME)200 sChannelProjectionMap.put( 201 Channels.COLUMN_DISPLAY_NAME, CHANNELS_TABLE + "." + Channels.COLUMN_DISPLAY_NAME); sChannelProjectionMap.put( Channels.COLUMN_NETWORK_AFFILIATION, CHANNELS_TABLE + "." + Channels.COLUMN_NETWORK_AFFILIATION)202 sChannelProjectionMap.put( 203 Channels.COLUMN_NETWORK_AFFILIATION, 204 CHANNELS_TABLE + "." + Channels.COLUMN_NETWORK_AFFILIATION); sChannelProjectionMap.put( Channels.COLUMN_DESCRIPTION, CHANNELS_TABLE + "." + Channels.COLUMN_DESCRIPTION)205 sChannelProjectionMap.put( 206 Channels.COLUMN_DESCRIPTION, CHANNELS_TABLE + "." + Channels.COLUMN_DESCRIPTION); sChannelProjectionMap.put( Channels.COLUMN_VIDEO_FORMAT, CHANNELS_TABLE + "." + Channels.COLUMN_VIDEO_FORMAT)207 sChannelProjectionMap.put( 208 Channels.COLUMN_VIDEO_FORMAT, CHANNELS_TABLE + "." + Channels.COLUMN_VIDEO_FORMAT); sChannelProjectionMap.put( Channels.COLUMN_BROWSABLE, CHANNELS_TABLE + "." + Channels.COLUMN_BROWSABLE)209 sChannelProjectionMap.put( 210 Channels.COLUMN_BROWSABLE, CHANNELS_TABLE + "." + Channels.COLUMN_BROWSABLE); sChannelProjectionMap.put( Channels.COLUMN_SEARCHABLE, CHANNELS_TABLE + "." + Channels.COLUMN_SEARCHABLE)211 sChannelProjectionMap.put( 212 Channels.COLUMN_SEARCHABLE, CHANNELS_TABLE + "." + Channels.COLUMN_SEARCHABLE); sChannelProjectionMap.put( Channels.COLUMN_LOCKED, CHANNELS_TABLE + "." + Channels.COLUMN_LOCKED)213 sChannelProjectionMap.put( 214 Channels.COLUMN_LOCKED, CHANNELS_TABLE + "." + Channels.COLUMN_LOCKED); sChannelProjectionMap.put( Channels.COLUMN_APP_LINK_ICON_URI, CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_ICON_URI)215 sChannelProjectionMap.put( 216 Channels.COLUMN_APP_LINK_ICON_URI, 217 CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_ICON_URI); sChannelProjectionMap.put( Channels.COLUMN_APP_LINK_POSTER_ART_URI, CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_POSTER_ART_URI)218 sChannelProjectionMap.put( 219 Channels.COLUMN_APP_LINK_POSTER_ART_URI, 220 CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_POSTER_ART_URI); sChannelProjectionMap.put( Channels.COLUMN_APP_LINK_TEXT, CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_TEXT)221 sChannelProjectionMap.put( 222 Channels.COLUMN_APP_LINK_TEXT, 223 CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_TEXT); sChannelProjectionMap.put( Channels.COLUMN_APP_LINK_COLOR, CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_COLOR)224 sChannelProjectionMap.put( 225 Channels.COLUMN_APP_LINK_COLOR, 226 CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_COLOR); sChannelProjectionMap.put( Channels.COLUMN_APP_LINK_INTENT_URI, CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_INTENT_URI)227 sChannelProjectionMap.put( 228 Channels.COLUMN_APP_LINK_INTENT_URI, 229 CHANNELS_TABLE + "." + Channels.COLUMN_APP_LINK_INTENT_URI); sChannelProjectionMap.put( Channels.COLUMN_INTERNAL_PROVIDER_DATA, CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_DATA)230 sChannelProjectionMap.put( 231 Channels.COLUMN_INTERNAL_PROVIDER_DATA, 232 CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_DATA); sChannelProjectionMap.put( Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1)233 sChannelProjectionMap.put( 234 Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, 235 CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1); sChannelProjectionMap.put( Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2)236 sChannelProjectionMap.put( 237 Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, 238 CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2); sChannelProjectionMap.put( Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3)239 sChannelProjectionMap.put( 240 Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, 241 CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3); sChannelProjectionMap.put( Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4)242 sChannelProjectionMap.put( 243 Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, 244 CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4); sChannelProjectionMap.put( Channels.COLUMN_VERSION_NUMBER, CHANNELS_TABLE + "." + Channels.COLUMN_VERSION_NUMBER)245 sChannelProjectionMap.put( 246 Channels.COLUMN_VERSION_NUMBER, 247 CHANNELS_TABLE + "." + Channels.COLUMN_VERSION_NUMBER); sChannelProjectionMap.put( Channels.COLUMN_TRANSIENT, CHANNELS_TABLE + "." + Channels.COLUMN_TRANSIENT)248 sChannelProjectionMap.put( 249 Channels.COLUMN_TRANSIENT, CHANNELS_TABLE + "." + Channels.COLUMN_TRANSIENT); sChannelProjectionMap.put( Channels.COLUMN_INTERNAL_PROVIDER_ID, CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_ID)250 sChannelProjectionMap.put( 251 Channels.COLUMN_INTERNAL_PROVIDER_ID, 252 CHANNELS_TABLE + "." + Channels.COLUMN_INTERNAL_PROVIDER_ID); 253 254 sProgramProjectionMap = new HashMap<>(); sProgramProjectionMap.put(Programs._ID, Programs._ID)255 sProgramProjectionMap.put(Programs._ID, Programs._ID); sProgramProjectionMap.put(Programs.COLUMN_PACKAGE_NAME, Programs.COLUMN_PACKAGE_NAME)256 sProgramProjectionMap.put(Programs.COLUMN_PACKAGE_NAME, Programs.COLUMN_PACKAGE_NAME); sProgramProjectionMap.put(Programs.COLUMN_CHANNEL_ID, Programs.COLUMN_CHANNEL_ID)257 sProgramProjectionMap.put(Programs.COLUMN_CHANNEL_ID, Programs.COLUMN_CHANNEL_ID); sProgramProjectionMap.put(Programs.COLUMN_TITLE, Programs.COLUMN_TITLE)258 sProgramProjectionMap.put(Programs.COLUMN_TITLE, Programs.COLUMN_TITLE); 259 // COLUMN_SEASON_NUMBER is deprecated. Return COLUMN_SEASON_DISPLAY_NUMBER instead. sProgramProjectionMap.put( Programs.COLUMN_SEASON_NUMBER, Programs.COLUMN_SEASON_DISPLAY_NUMBER + " AS " + Programs.COLUMN_SEASON_NUMBER)260 sProgramProjectionMap.put( 261 Programs.COLUMN_SEASON_NUMBER, 262 Programs.COLUMN_SEASON_DISPLAY_NUMBER + " AS " + Programs.COLUMN_SEASON_NUMBER); sProgramProjectionMap.put( Programs.COLUMN_SEASON_DISPLAY_NUMBER, Programs.COLUMN_SEASON_DISPLAY_NUMBER)263 sProgramProjectionMap.put( 264 Programs.COLUMN_SEASON_DISPLAY_NUMBER, Programs.COLUMN_SEASON_DISPLAY_NUMBER); sProgramProjectionMap.put(Programs.COLUMN_SEASON_TITLE, Programs.COLUMN_SEASON_TITLE)265 sProgramProjectionMap.put(Programs.COLUMN_SEASON_TITLE, Programs.COLUMN_SEASON_TITLE); 266 // COLUMN_EPISODE_NUMBER is deprecated. Return COLUMN_EPISODE_DISPLAY_NUMBER instead. sProgramProjectionMap.put( Programs.COLUMN_EPISODE_NUMBER, Programs.COLUMN_EPISODE_DISPLAY_NUMBER + " AS " + Programs.COLUMN_EPISODE_NUMBER)267 sProgramProjectionMap.put( 268 Programs.COLUMN_EPISODE_NUMBER, 269 Programs.COLUMN_EPISODE_DISPLAY_NUMBER + " AS " + Programs.COLUMN_EPISODE_NUMBER); sProgramProjectionMap.put( Programs.COLUMN_EPISODE_DISPLAY_NUMBER, Programs.COLUMN_EPISODE_DISPLAY_NUMBER)270 sProgramProjectionMap.put( 271 Programs.COLUMN_EPISODE_DISPLAY_NUMBER, Programs.COLUMN_EPISODE_DISPLAY_NUMBER); sProgramProjectionMap.put(Programs.COLUMN_EPISODE_TITLE, Programs.COLUMN_EPISODE_TITLE)272 sProgramProjectionMap.put(Programs.COLUMN_EPISODE_TITLE, Programs.COLUMN_EPISODE_TITLE); sProgramProjectionMap.put( Programs.COLUMN_START_TIME_UTC_MILLIS, Programs.COLUMN_START_TIME_UTC_MILLIS)273 sProgramProjectionMap.put( 274 Programs.COLUMN_START_TIME_UTC_MILLIS, Programs.COLUMN_START_TIME_UTC_MILLIS); sProgramProjectionMap.put( Programs.COLUMN_END_TIME_UTC_MILLIS, Programs.COLUMN_END_TIME_UTC_MILLIS)275 sProgramProjectionMap.put( 276 Programs.COLUMN_END_TIME_UTC_MILLIS, Programs.COLUMN_END_TIME_UTC_MILLIS); sProgramProjectionMap.put(Programs.COLUMN_BROADCAST_GENRE, Programs.COLUMN_BROADCAST_GENRE)277 sProgramProjectionMap.put(Programs.COLUMN_BROADCAST_GENRE, Programs.COLUMN_BROADCAST_GENRE); sProgramProjectionMap.put(Programs.COLUMN_CANONICAL_GENRE, Programs.COLUMN_CANONICAL_GENRE)278 sProgramProjectionMap.put(Programs.COLUMN_CANONICAL_GENRE, Programs.COLUMN_CANONICAL_GENRE); sProgramProjectionMap.put( Programs.COLUMN_SHORT_DESCRIPTION, Programs.COLUMN_SHORT_DESCRIPTION)279 sProgramProjectionMap.put( 280 Programs.COLUMN_SHORT_DESCRIPTION, Programs.COLUMN_SHORT_DESCRIPTION); sProgramProjectionMap.put( Programs.COLUMN_LONG_DESCRIPTION, Programs.COLUMN_LONG_DESCRIPTION)281 sProgramProjectionMap.put( 282 Programs.COLUMN_LONG_DESCRIPTION, Programs.COLUMN_LONG_DESCRIPTION); sProgramProjectionMap.put(Programs.COLUMN_VIDEO_WIDTH, Programs.COLUMN_VIDEO_WIDTH)283 sProgramProjectionMap.put(Programs.COLUMN_VIDEO_WIDTH, Programs.COLUMN_VIDEO_WIDTH); sProgramProjectionMap.put(Programs.COLUMN_VIDEO_HEIGHT, Programs.COLUMN_VIDEO_HEIGHT)284 sProgramProjectionMap.put(Programs.COLUMN_VIDEO_HEIGHT, Programs.COLUMN_VIDEO_HEIGHT); sProgramProjectionMap.put(Programs.COLUMN_AUDIO_LANGUAGE, Programs.COLUMN_AUDIO_LANGUAGE)285 sProgramProjectionMap.put(Programs.COLUMN_AUDIO_LANGUAGE, Programs.COLUMN_AUDIO_LANGUAGE); sProgramProjectionMap.put(Programs.COLUMN_CONTENT_RATING, Programs.COLUMN_CONTENT_RATING)286 sProgramProjectionMap.put(Programs.COLUMN_CONTENT_RATING, Programs.COLUMN_CONTENT_RATING); sProgramProjectionMap.put(Programs.COLUMN_POSTER_ART_URI, Programs.COLUMN_POSTER_ART_URI)287 sProgramProjectionMap.put(Programs.COLUMN_POSTER_ART_URI, Programs.COLUMN_POSTER_ART_URI); sProgramProjectionMap.put(Programs.COLUMN_THUMBNAIL_URI, Programs.COLUMN_THUMBNAIL_URI)288 sProgramProjectionMap.put(Programs.COLUMN_THUMBNAIL_URI, Programs.COLUMN_THUMBNAIL_URI); sProgramProjectionMap.put(Programs.COLUMN_SEARCHABLE, Programs.COLUMN_SEARCHABLE)289 sProgramProjectionMap.put(Programs.COLUMN_SEARCHABLE, Programs.COLUMN_SEARCHABLE); sProgramProjectionMap.put( Programs.COLUMN_RECORDING_PROHIBITED, Programs.COLUMN_RECORDING_PROHIBITED)290 sProgramProjectionMap.put( 291 Programs.COLUMN_RECORDING_PROHIBITED, Programs.COLUMN_RECORDING_PROHIBITED); sProgramProjectionMap.put( Programs.COLUMN_INTERNAL_PROVIDER_DATA, Programs.COLUMN_INTERNAL_PROVIDER_DATA)292 sProgramProjectionMap.put( 293 Programs.COLUMN_INTERNAL_PROVIDER_DATA, Programs.COLUMN_INTERNAL_PROVIDER_DATA); sProgramProjectionMap.put( Programs.COLUMN_INTERNAL_PROVIDER_FLAG1, Programs.COLUMN_INTERNAL_PROVIDER_FLAG1)294 sProgramProjectionMap.put( 295 Programs.COLUMN_INTERNAL_PROVIDER_FLAG1, Programs.COLUMN_INTERNAL_PROVIDER_FLAG1); sProgramProjectionMap.put( Programs.COLUMN_INTERNAL_PROVIDER_FLAG2, Programs.COLUMN_INTERNAL_PROVIDER_FLAG2)296 sProgramProjectionMap.put( 297 Programs.COLUMN_INTERNAL_PROVIDER_FLAG2, Programs.COLUMN_INTERNAL_PROVIDER_FLAG2); sProgramProjectionMap.put( Programs.COLUMN_INTERNAL_PROVIDER_FLAG3, Programs.COLUMN_INTERNAL_PROVIDER_FLAG3)298 sProgramProjectionMap.put( 299 Programs.COLUMN_INTERNAL_PROVIDER_FLAG3, Programs.COLUMN_INTERNAL_PROVIDER_FLAG3); sProgramProjectionMap.put( Programs.COLUMN_INTERNAL_PROVIDER_FLAG4, Programs.COLUMN_INTERNAL_PROVIDER_FLAG4)300 sProgramProjectionMap.put( 301 Programs.COLUMN_INTERNAL_PROVIDER_FLAG4, Programs.COLUMN_INTERNAL_PROVIDER_FLAG4); sProgramProjectionMap.put(Programs.COLUMN_VERSION_NUMBER, Programs.COLUMN_VERSION_NUMBER)302 sProgramProjectionMap.put(Programs.COLUMN_VERSION_NUMBER, Programs.COLUMN_VERSION_NUMBER); sProgramProjectionMap.put( Programs.COLUMN_REVIEW_RATING_STYLE, Programs.COLUMN_REVIEW_RATING_STYLE)303 sProgramProjectionMap.put( 304 Programs.COLUMN_REVIEW_RATING_STYLE, Programs.COLUMN_REVIEW_RATING_STYLE); sProgramProjectionMap.put(Programs.COLUMN_REVIEW_RATING, Programs.COLUMN_REVIEW_RATING)305 sProgramProjectionMap.put(Programs.COLUMN_REVIEW_RATING, Programs.COLUMN_REVIEW_RATING); 306 307 sWatchedProgramProjectionMap = new HashMap<>(); sWatchedProgramProjectionMap.put(WatchedPrograms._ID, WatchedPrograms._ID)308 sWatchedProgramProjectionMap.put(WatchedPrograms._ID, WatchedPrograms._ID); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS)309 sWatchedProgramProjectionMap.put( 310 WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS, 311 WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS)312 sWatchedProgramProjectionMap.put( 313 WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS, 314 WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_CHANNEL_ID, WatchedPrograms.COLUMN_CHANNEL_ID)315 sWatchedProgramProjectionMap.put( 316 WatchedPrograms.COLUMN_CHANNEL_ID, WatchedPrograms.COLUMN_CHANNEL_ID); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_TITLE, WatchedPrograms.COLUMN_TITLE)317 sWatchedProgramProjectionMap.put( 318 WatchedPrograms.COLUMN_TITLE, WatchedPrograms.COLUMN_TITLE); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS)319 sWatchedProgramProjectionMap.put( 320 WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS, 321 WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS)322 sWatchedProgramProjectionMap.put( 323 WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS, 324 WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_DESCRIPTION, WatchedPrograms.COLUMN_DESCRIPTION)325 sWatchedProgramProjectionMap.put( 326 WatchedPrograms.COLUMN_DESCRIPTION, WatchedPrograms.COLUMN_DESCRIPTION); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS, WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS)327 sWatchedProgramProjectionMap.put( 328 WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS, 329 WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS); sWatchedProgramProjectionMap.put( WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN, WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN)330 sWatchedProgramProjectionMap.put( 331 WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN, 332 WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN); sWatchedProgramProjectionMap.put( WATCHED_PROGRAMS_COLUMN_CONSOLIDATED, WATCHED_PROGRAMS_COLUMN_CONSOLIDATED)333 sWatchedProgramProjectionMap.put( 334 WATCHED_PROGRAMS_COLUMN_CONSOLIDATED, WATCHED_PROGRAMS_COLUMN_CONSOLIDATED); 335 336 sRecordedProgramProjectionMap = new HashMap<>(); sRecordedProgramProjectionMap.put(RecordedPrograms._ID, RecordedPrograms._ID)337 sRecordedProgramProjectionMap.put(RecordedPrograms._ID, RecordedPrograms._ID); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_PACKAGE_NAME, RecordedPrograms.COLUMN_PACKAGE_NAME)338 sRecordedProgramProjectionMap.put( 339 RecordedPrograms.COLUMN_PACKAGE_NAME, RecordedPrograms.COLUMN_PACKAGE_NAME); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_INPUT_ID, RecordedPrograms.COLUMN_INPUT_ID)340 sRecordedProgramProjectionMap.put( 341 RecordedPrograms.COLUMN_INPUT_ID, RecordedPrograms.COLUMN_INPUT_ID); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_CHANNEL_ID, RecordedPrograms.COLUMN_CHANNEL_ID)342 sRecordedProgramProjectionMap.put( 343 RecordedPrograms.COLUMN_CHANNEL_ID, RecordedPrograms.COLUMN_CHANNEL_ID); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_TITLE, RecordedPrograms.COLUMN_TITLE)344 sRecordedProgramProjectionMap.put( 345 RecordedPrograms.COLUMN_TITLE, RecordedPrograms.COLUMN_TITLE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER)346 sRecordedProgramProjectionMap.put( 347 RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER, 348 RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_SEASON_TITLE, RecordedPrograms.COLUMN_SEASON_TITLE)349 sRecordedProgramProjectionMap.put( 350 RecordedPrograms.COLUMN_SEASON_TITLE, RecordedPrograms.COLUMN_SEASON_TITLE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER)351 sRecordedProgramProjectionMap.put( 352 RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, 353 RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_EPISODE_TITLE, RecordedPrograms.COLUMN_EPISODE_TITLE)354 sRecordedProgramProjectionMap.put( 355 RecordedPrograms.COLUMN_EPISODE_TITLE, RecordedPrograms.COLUMN_EPISODE_TITLE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS)356 sRecordedProgramProjectionMap.put( 357 RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, 358 RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS)359 sRecordedProgramProjectionMap.put( 360 RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, 361 RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_BROADCAST_GENRE, RecordedPrograms.COLUMN_BROADCAST_GENRE)362 sRecordedProgramProjectionMap.put( 363 RecordedPrograms.COLUMN_BROADCAST_GENRE, RecordedPrograms.COLUMN_BROADCAST_GENRE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_CANONICAL_GENRE, RecordedPrograms.COLUMN_CANONICAL_GENRE)364 sRecordedProgramProjectionMap.put( 365 RecordedPrograms.COLUMN_CANONICAL_GENRE, RecordedPrograms.COLUMN_CANONICAL_GENRE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_SHORT_DESCRIPTION, RecordedPrograms.COLUMN_SHORT_DESCRIPTION)366 sRecordedProgramProjectionMap.put( 367 RecordedPrograms.COLUMN_SHORT_DESCRIPTION, 368 RecordedPrograms.COLUMN_SHORT_DESCRIPTION); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_LONG_DESCRIPTION, RecordedPrograms.COLUMN_LONG_DESCRIPTION)369 sRecordedProgramProjectionMap.put( 370 RecordedPrograms.COLUMN_LONG_DESCRIPTION, RecordedPrograms.COLUMN_LONG_DESCRIPTION); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_VIDEO_WIDTH, RecordedPrograms.COLUMN_VIDEO_WIDTH)371 sRecordedProgramProjectionMap.put( 372 RecordedPrograms.COLUMN_VIDEO_WIDTH, RecordedPrograms.COLUMN_VIDEO_WIDTH); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_VIDEO_HEIGHT, RecordedPrograms.COLUMN_VIDEO_HEIGHT)373 sRecordedProgramProjectionMap.put( 374 RecordedPrograms.COLUMN_VIDEO_HEIGHT, RecordedPrograms.COLUMN_VIDEO_HEIGHT); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_AUDIO_LANGUAGE, RecordedPrograms.COLUMN_AUDIO_LANGUAGE)375 sRecordedProgramProjectionMap.put( 376 RecordedPrograms.COLUMN_AUDIO_LANGUAGE, RecordedPrograms.COLUMN_AUDIO_LANGUAGE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_CONTENT_RATING, RecordedPrograms.COLUMN_CONTENT_RATING)377 sRecordedProgramProjectionMap.put( 378 RecordedPrograms.COLUMN_CONTENT_RATING, RecordedPrograms.COLUMN_CONTENT_RATING); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_POSTER_ART_URI, RecordedPrograms.COLUMN_POSTER_ART_URI)379 sRecordedProgramProjectionMap.put( 380 RecordedPrograms.COLUMN_POSTER_ART_URI, RecordedPrograms.COLUMN_POSTER_ART_URI); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_THUMBNAIL_URI, RecordedPrograms.COLUMN_THUMBNAIL_URI)381 sRecordedProgramProjectionMap.put( 382 RecordedPrograms.COLUMN_THUMBNAIL_URI, RecordedPrograms.COLUMN_THUMBNAIL_URI); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_SEARCHABLE, RecordedPrograms.COLUMN_SEARCHABLE)383 sRecordedProgramProjectionMap.put( 384 RecordedPrograms.COLUMN_SEARCHABLE, RecordedPrograms.COLUMN_SEARCHABLE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_RECORDING_DATA_URI, RecordedPrograms.COLUMN_RECORDING_DATA_URI)385 sRecordedProgramProjectionMap.put( 386 RecordedPrograms.COLUMN_RECORDING_DATA_URI, 387 RecordedPrograms.COLUMN_RECORDING_DATA_URI); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, RecordedPrograms.COLUMN_RECORDING_DATA_BYTES)388 sRecordedProgramProjectionMap.put( 389 RecordedPrograms.COLUMN_RECORDING_DATA_BYTES, 390 RecordedPrograms.COLUMN_RECORDING_DATA_BYTES); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS)391 sRecordedProgramProjectionMap.put( 392 RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS, 393 RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS)394 sRecordedProgramProjectionMap.put( 395 RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS, 396 RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA)397 sRecordedProgramProjectionMap.put( 398 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA, 399 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1)400 sRecordedProgramProjectionMap.put( 401 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, 402 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2)403 sRecordedProgramProjectionMap.put( 404 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 405 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3)406 sRecordedProgramProjectionMap.put( 407 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 408 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4)409 sRecordedProgramProjectionMap.put( 410 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 411 RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_VERSION_NUMBER, RecordedPrograms.COLUMN_VERSION_NUMBER)412 sRecordedProgramProjectionMap.put( 413 RecordedPrograms.COLUMN_VERSION_NUMBER, RecordedPrograms.COLUMN_VERSION_NUMBER); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_REVIEW_RATING_STYLE, RecordedPrograms.COLUMN_REVIEW_RATING_STYLE)414 sRecordedProgramProjectionMap.put( 415 RecordedPrograms.COLUMN_REVIEW_RATING_STYLE, 416 RecordedPrograms.COLUMN_REVIEW_RATING_STYLE); sRecordedProgramProjectionMap.put( RecordedPrograms.COLUMN_REVIEW_RATING, RecordedPrograms.COLUMN_REVIEW_RATING)417 sRecordedProgramProjectionMap.put( 418 RecordedPrograms.COLUMN_REVIEW_RATING, RecordedPrograms.COLUMN_REVIEW_RATING); 419 420 sPreviewProgramProjectionMap = new HashMap<>(); sPreviewProgramProjectionMap.put(PreviewPrograms._ID, PreviewPrograms._ID)421 sPreviewProgramProjectionMap.put(PreviewPrograms._ID, PreviewPrograms._ID); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_PACKAGE_NAME, PreviewPrograms.COLUMN_PACKAGE_NAME)422 sPreviewProgramProjectionMap.put( 423 PreviewPrograms.COLUMN_PACKAGE_NAME, PreviewPrograms.COLUMN_PACKAGE_NAME); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_CHANNEL_ID, PreviewPrograms.COLUMN_CHANNEL_ID)424 sPreviewProgramProjectionMap.put( 425 PreviewPrograms.COLUMN_CHANNEL_ID, PreviewPrograms.COLUMN_CHANNEL_ID); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_TITLE, PreviewPrograms.COLUMN_TITLE)426 sPreviewProgramProjectionMap.put( 427 PreviewPrograms.COLUMN_TITLE, PreviewPrograms.COLUMN_TITLE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER, PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER)428 sPreviewProgramProjectionMap.put( 429 PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER, 430 PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_SEASON_TITLE, PreviewPrograms.COLUMN_SEASON_TITLE)431 sPreviewProgramProjectionMap.put( 432 PreviewPrograms.COLUMN_SEASON_TITLE, PreviewPrograms.COLUMN_SEASON_TITLE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER)433 sPreviewProgramProjectionMap.put( 434 PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, 435 PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_EPISODE_TITLE, PreviewPrograms.COLUMN_EPISODE_TITLE)436 sPreviewProgramProjectionMap.put( 437 PreviewPrograms.COLUMN_EPISODE_TITLE, PreviewPrograms.COLUMN_EPISODE_TITLE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_CANONICAL_GENRE, PreviewPrograms.COLUMN_CANONICAL_GENRE)438 sPreviewProgramProjectionMap.put( 439 PreviewPrograms.COLUMN_CANONICAL_GENRE, PreviewPrograms.COLUMN_CANONICAL_GENRE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_SHORT_DESCRIPTION, PreviewPrograms.COLUMN_SHORT_DESCRIPTION)440 sPreviewProgramProjectionMap.put( 441 PreviewPrograms.COLUMN_SHORT_DESCRIPTION, PreviewPrograms.COLUMN_SHORT_DESCRIPTION); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_LONG_DESCRIPTION, PreviewPrograms.COLUMN_LONG_DESCRIPTION)442 sPreviewProgramProjectionMap.put( 443 PreviewPrograms.COLUMN_LONG_DESCRIPTION, PreviewPrograms.COLUMN_LONG_DESCRIPTION); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_VIDEO_WIDTH, PreviewPrograms.COLUMN_VIDEO_WIDTH)444 sPreviewProgramProjectionMap.put( 445 PreviewPrograms.COLUMN_VIDEO_WIDTH, PreviewPrograms.COLUMN_VIDEO_WIDTH); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_VIDEO_HEIGHT, PreviewPrograms.COLUMN_VIDEO_HEIGHT)446 sPreviewProgramProjectionMap.put( 447 PreviewPrograms.COLUMN_VIDEO_HEIGHT, PreviewPrograms.COLUMN_VIDEO_HEIGHT); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_AUDIO_LANGUAGE, PreviewPrograms.COLUMN_AUDIO_LANGUAGE)448 sPreviewProgramProjectionMap.put( 449 PreviewPrograms.COLUMN_AUDIO_LANGUAGE, PreviewPrograms.COLUMN_AUDIO_LANGUAGE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_CONTENT_RATING, PreviewPrograms.COLUMN_CONTENT_RATING)450 sPreviewProgramProjectionMap.put( 451 PreviewPrograms.COLUMN_CONTENT_RATING, PreviewPrograms.COLUMN_CONTENT_RATING); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_POSTER_ART_URI, PreviewPrograms.COLUMN_POSTER_ART_URI)452 sPreviewProgramProjectionMap.put( 453 PreviewPrograms.COLUMN_POSTER_ART_URI, PreviewPrograms.COLUMN_POSTER_ART_URI); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_THUMBNAIL_URI, PreviewPrograms.COLUMN_THUMBNAIL_URI)454 sPreviewProgramProjectionMap.put( 455 PreviewPrograms.COLUMN_THUMBNAIL_URI, PreviewPrograms.COLUMN_THUMBNAIL_URI); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_SEARCHABLE, PreviewPrograms.COLUMN_SEARCHABLE)456 sPreviewProgramProjectionMap.put( 457 PreviewPrograms.COLUMN_SEARCHABLE, PreviewPrograms.COLUMN_SEARCHABLE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA, PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA)458 sPreviewProgramProjectionMap.put( 459 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA, 460 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1)461 sPreviewProgramProjectionMap.put( 462 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, 463 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2)464 sPreviewProgramProjectionMap.put( 465 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 466 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3)467 sPreviewProgramProjectionMap.put( 468 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 469 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4)470 sPreviewProgramProjectionMap.put( 471 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 472 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_VERSION_NUMBER, PreviewPrograms.COLUMN_VERSION_NUMBER)473 sPreviewProgramProjectionMap.put( 474 PreviewPrograms.COLUMN_VERSION_NUMBER, PreviewPrograms.COLUMN_VERSION_NUMBER); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID, PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID)475 sPreviewProgramProjectionMap.put( 476 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID, 477 PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI, PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI)478 sPreviewProgramProjectionMap.put( 479 PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI, PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS)480 sPreviewProgramProjectionMap.put( 481 PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, 482 PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_DURATION_MILLIS, PreviewPrograms.COLUMN_DURATION_MILLIS)483 sPreviewProgramProjectionMap.put( 484 PreviewPrograms.COLUMN_DURATION_MILLIS, PreviewPrograms.COLUMN_DURATION_MILLIS); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTENT_URI, PreviewPrograms.COLUMN_INTENT_URI)485 sPreviewProgramProjectionMap.put( 486 PreviewPrograms.COLUMN_INTENT_URI, PreviewPrograms.COLUMN_INTENT_URI); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_WEIGHT, PreviewPrograms.COLUMN_WEIGHT)487 sPreviewProgramProjectionMap.put( 488 PreviewPrograms.COLUMN_WEIGHT, PreviewPrograms.COLUMN_WEIGHT); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_TRANSIENT, PreviewPrograms.COLUMN_TRANSIENT)489 sPreviewProgramProjectionMap.put( 490 PreviewPrograms.COLUMN_TRANSIENT, PreviewPrograms.COLUMN_TRANSIENT); sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_TYPE, PreviewPrograms.COLUMN_TYPE)491 sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_TYPE, PreviewPrograms.COLUMN_TYPE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO)492 sPreviewProgramProjectionMap.put( 493 PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, 494 PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO)495 sPreviewProgramProjectionMap.put( 496 PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, 497 PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_LOGO_URI, PreviewPrograms.COLUMN_LOGO_URI)498 sPreviewProgramProjectionMap.put( 499 PreviewPrograms.COLUMN_LOGO_URI, PreviewPrograms.COLUMN_LOGO_URI); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_AVAILABILITY, PreviewPrograms.COLUMN_AVAILABILITY)500 sPreviewProgramProjectionMap.put( 501 PreviewPrograms.COLUMN_AVAILABILITY, PreviewPrograms.COLUMN_AVAILABILITY); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_STARTING_PRICE, PreviewPrograms.COLUMN_STARTING_PRICE)502 sPreviewProgramProjectionMap.put( 503 PreviewPrograms.COLUMN_STARTING_PRICE, PreviewPrograms.COLUMN_STARTING_PRICE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_OFFER_PRICE, PreviewPrograms.COLUMN_OFFER_PRICE)504 sPreviewProgramProjectionMap.put( 505 PreviewPrograms.COLUMN_OFFER_PRICE, PreviewPrograms.COLUMN_OFFER_PRICE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_RELEASE_DATE, PreviewPrograms.COLUMN_RELEASE_DATE)506 sPreviewProgramProjectionMap.put( 507 PreviewPrograms.COLUMN_RELEASE_DATE, PreviewPrograms.COLUMN_RELEASE_DATE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_ITEM_COUNT, PreviewPrograms.COLUMN_ITEM_COUNT)508 sPreviewProgramProjectionMap.put( 509 PreviewPrograms.COLUMN_ITEM_COUNT, PreviewPrograms.COLUMN_ITEM_COUNT); sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_LIVE, PreviewPrograms.COLUMN_LIVE)510 sPreviewProgramProjectionMap.put(PreviewPrograms.COLUMN_LIVE, PreviewPrograms.COLUMN_LIVE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERACTION_TYPE, PreviewPrograms.COLUMN_INTERACTION_TYPE)511 sPreviewProgramProjectionMap.put( 512 PreviewPrograms.COLUMN_INTERACTION_TYPE, PreviewPrograms.COLUMN_INTERACTION_TYPE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_INTERACTION_COUNT, PreviewPrograms.COLUMN_INTERACTION_COUNT)513 sPreviewProgramProjectionMap.put( 514 PreviewPrograms.COLUMN_INTERACTION_COUNT, PreviewPrograms.COLUMN_INTERACTION_COUNT); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_AUTHOR, PreviewPrograms.COLUMN_AUTHOR)515 sPreviewProgramProjectionMap.put( 516 PreviewPrograms.COLUMN_AUTHOR, PreviewPrograms.COLUMN_AUTHOR); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_REVIEW_RATING_STYLE, PreviewPrograms.COLUMN_REVIEW_RATING_STYLE)517 sPreviewProgramProjectionMap.put( 518 PreviewPrograms.COLUMN_REVIEW_RATING_STYLE, 519 PreviewPrograms.COLUMN_REVIEW_RATING_STYLE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_REVIEW_RATING, PreviewPrograms.COLUMN_REVIEW_RATING)520 sPreviewProgramProjectionMap.put( 521 PreviewPrograms.COLUMN_REVIEW_RATING, PreviewPrograms.COLUMN_REVIEW_RATING); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_BROWSABLE, PreviewPrograms.COLUMN_BROWSABLE)522 sPreviewProgramProjectionMap.put( 523 PreviewPrograms.COLUMN_BROWSABLE, PreviewPrograms.COLUMN_BROWSABLE); sPreviewProgramProjectionMap.put( PreviewPrograms.COLUMN_CONTENT_ID, PreviewPrograms.COLUMN_CONTENT_ID)524 sPreviewProgramProjectionMap.put( 525 PreviewPrograms.COLUMN_CONTENT_ID, PreviewPrograms.COLUMN_CONTENT_ID); 526 527 sWatchNextProgramProjectionMap = new HashMap<>(); sWatchNextProgramProjectionMap.put(WatchNextPrograms._ID, WatchNextPrograms._ID)528 sWatchNextProgramProjectionMap.put(WatchNextPrograms._ID, WatchNextPrograms._ID); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_PACKAGE_NAME, WatchNextPrograms.COLUMN_PACKAGE_NAME)529 sWatchNextProgramProjectionMap.put( 530 WatchNextPrograms.COLUMN_PACKAGE_NAME, WatchNextPrograms.COLUMN_PACKAGE_NAME); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_TITLE, WatchNextPrograms.COLUMN_TITLE)531 sWatchNextProgramProjectionMap.put( 532 WatchNextPrograms.COLUMN_TITLE, WatchNextPrograms.COLUMN_TITLE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER, WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER)533 sWatchNextProgramProjectionMap.put( 534 WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER, 535 WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_SEASON_TITLE, WatchNextPrograms.COLUMN_SEASON_TITLE)536 sWatchNextProgramProjectionMap.put( 537 WatchNextPrograms.COLUMN_SEASON_TITLE, WatchNextPrograms.COLUMN_SEASON_TITLE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER)538 sWatchNextProgramProjectionMap.put( 539 WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER, 540 WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_EPISODE_TITLE, WatchNextPrograms.COLUMN_EPISODE_TITLE)541 sWatchNextProgramProjectionMap.put( 542 WatchNextPrograms.COLUMN_EPISODE_TITLE, WatchNextPrograms.COLUMN_EPISODE_TITLE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_CANONICAL_GENRE, WatchNextPrograms.COLUMN_CANONICAL_GENRE)543 sWatchNextProgramProjectionMap.put( 544 WatchNextPrograms.COLUMN_CANONICAL_GENRE, WatchNextPrograms.COLUMN_CANONICAL_GENRE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_SHORT_DESCRIPTION, WatchNextPrograms.COLUMN_SHORT_DESCRIPTION)545 sWatchNextProgramProjectionMap.put( 546 WatchNextPrograms.COLUMN_SHORT_DESCRIPTION, 547 WatchNextPrograms.COLUMN_SHORT_DESCRIPTION); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_LONG_DESCRIPTION, WatchNextPrograms.COLUMN_LONG_DESCRIPTION)548 sWatchNextProgramProjectionMap.put( 549 WatchNextPrograms.COLUMN_LONG_DESCRIPTION, 550 WatchNextPrograms.COLUMN_LONG_DESCRIPTION); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_VIDEO_WIDTH, WatchNextPrograms.COLUMN_VIDEO_WIDTH)551 sWatchNextProgramProjectionMap.put( 552 WatchNextPrograms.COLUMN_VIDEO_WIDTH, WatchNextPrograms.COLUMN_VIDEO_WIDTH); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_VIDEO_HEIGHT, WatchNextPrograms.COLUMN_VIDEO_HEIGHT)553 sWatchNextProgramProjectionMap.put( 554 WatchNextPrograms.COLUMN_VIDEO_HEIGHT, WatchNextPrograms.COLUMN_VIDEO_HEIGHT); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_AUDIO_LANGUAGE, WatchNextPrograms.COLUMN_AUDIO_LANGUAGE)555 sWatchNextProgramProjectionMap.put( 556 WatchNextPrograms.COLUMN_AUDIO_LANGUAGE, WatchNextPrograms.COLUMN_AUDIO_LANGUAGE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_CONTENT_RATING, WatchNextPrograms.COLUMN_CONTENT_RATING)557 sWatchNextProgramProjectionMap.put( 558 WatchNextPrograms.COLUMN_CONTENT_RATING, WatchNextPrograms.COLUMN_CONTENT_RATING); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_POSTER_ART_URI, WatchNextPrograms.COLUMN_POSTER_ART_URI)559 sWatchNextProgramProjectionMap.put( 560 WatchNextPrograms.COLUMN_POSTER_ART_URI, WatchNextPrograms.COLUMN_POSTER_ART_URI); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_THUMBNAIL_URI, WatchNextPrograms.COLUMN_THUMBNAIL_URI)561 sWatchNextProgramProjectionMap.put( 562 WatchNextPrograms.COLUMN_THUMBNAIL_URI, WatchNextPrograms.COLUMN_THUMBNAIL_URI); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_SEARCHABLE, WatchNextPrograms.COLUMN_SEARCHABLE)563 sWatchNextProgramProjectionMap.put( 564 WatchNextPrograms.COLUMN_SEARCHABLE, WatchNextPrograms.COLUMN_SEARCHABLE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA, WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA)565 sWatchNextProgramProjectionMap.put( 566 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA, 567 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1)568 sWatchNextProgramProjectionMap.put( 569 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1, 570 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2)571 sWatchNextProgramProjectionMap.put( 572 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 573 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3)574 sWatchNextProgramProjectionMap.put( 575 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 576 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4)577 sWatchNextProgramProjectionMap.put( 578 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 579 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_VERSION_NUMBER, WatchNextPrograms.COLUMN_VERSION_NUMBER)580 sWatchNextProgramProjectionMap.put( 581 WatchNextPrograms.COLUMN_VERSION_NUMBER, WatchNextPrograms.COLUMN_VERSION_NUMBER); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID, WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID)582 sWatchNextProgramProjectionMap.put( 583 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID, 584 WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI, WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI)585 sWatchNextProgramProjectionMap.put( 586 WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI, 587 WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS)588 sWatchNextProgramProjectionMap.put( 589 WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS, 590 WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_DURATION_MILLIS, WatchNextPrograms.COLUMN_DURATION_MILLIS)591 sWatchNextProgramProjectionMap.put( 592 WatchNextPrograms.COLUMN_DURATION_MILLIS, WatchNextPrograms.COLUMN_DURATION_MILLIS); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTENT_URI, WatchNextPrograms.COLUMN_INTENT_URI)593 sWatchNextProgramProjectionMap.put( 594 WatchNextPrograms.COLUMN_INTENT_URI, WatchNextPrograms.COLUMN_INTENT_URI); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_TRANSIENT, WatchNextPrograms.COLUMN_TRANSIENT)595 sWatchNextProgramProjectionMap.put( 596 WatchNextPrograms.COLUMN_TRANSIENT, WatchNextPrograms.COLUMN_TRANSIENT); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_TYPE, WatchNextPrograms.COLUMN_TYPE)597 sWatchNextProgramProjectionMap.put( 598 WatchNextPrograms.COLUMN_TYPE, WatchNextPrograms.COLUMN_TYPE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE, WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE)599 sWatchNextProgramProjectionMap.put( 600 WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE, WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO)601 sWatchNextProgramProjectionMap.put( 602 WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO, 603 WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO)604 sWatchNextProgramProjectionMap.put( 605 WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO, 606 WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_LOGO_URI, WatchNextPrograms.COLUMN_LOGO_URI)607 sWatchNextProgramProjectionMap.put( 608 WatchNextPrograms.COLUMN_LOGO_URI, WatchNextPrograms.COLUMN_LOGO_URI); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_AVAILABILITY, WatchNextPrograms.COLUMN_AVAILABILITY)609 sWatchNextProgramProjectionMap.put( 610 WatchNextPrograms.COLUMN_AVAILABILITY, WatchNextPrograms.COLUMN_AVAILABILITY); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_STARTING_PRICE, WatchNextPrograms.COLUMN_STARTING_PRICE)611 sWatchNextProgramProjectionMap.put( 612 WatchNextPrograms.COLUMN_STARTING_PRICE, WatchNextPrograms.COLUMN_STARTING_PRICE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_OFFER_PRICE, WatchNextPrograms.COLUMN_OFFER_PRICE)613 sWatchNextProgramProjectionMap.put( 614 WatchNextPrograms.COLUMN_OFFER_PRICE, WatchNextPrograms.COLUMN_OFFER_PRICE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_RELEASE_DATE, WatchNextPrograms.COLUMN_RELEASE_DATE)615 sWatchNextProgramProjectionMap.put( 616 WatchNextPrograms.COLUMN_RELEASE_DATE, WatchNextPrograms.COLUMN_RELEASE_DATE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_ITEM_COUNT, WatchNextPrograms.COLUMN_ITEM_COUNT)617 sWatchNextProgramProjectionMap.put( 618 WatchNextPrograms.COLUMN_ITEM_COUNT, WatchNextPrograms.COLUMN_ITEM_COUNT); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_LIVE, WatchNextPrograms.COLUMN_LIVE)619 sWatchNextProgramProjectionMap.put( 620 WatchNextPrograms.COLUMN_LIVE, WatchNextPrograms.COLUMN_LIVE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERACTION_TYPE, WatchNextPrograms.COLUMN_INTERACTION_TYPE)621 sWatchNextProgramProjectionMap.put( 622 WatchNextPrograms.COLUMN_INTERACTION_TYPE, 623 WatchNextPrograms.COLUMN_INTERACTION_TYPE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_INTERACTION_COUNT, WatchNextPrograms.COLUMN_INTERACTION_COUNT)624 sWatchNextProgramProjectionMap.put( 625 WatchNextPrograms.COLUMN_INTERACTION_COUNT, 626 WatchNextPrograms.COLUMN_INTERACTION_COUNT); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_AUTHOR, WatchNextPrograms.COLUMN_AUTHOR)627 sWatchNextProgramProjectionMap.put( 628 WatchNextPrograms.COLUMN_AUTHOR, WatchNextPrograms.COLUMN_AUTHOR); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE, WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE)629 sWatchNextProgramProjectionMap.put( 630 WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE, 631 WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_REVIEW_RATING, WatchNextPrograms.COLUMN_REVIEW_RATING)632 sWatchNextProgramProjectionMap.put( 633 WatchNextPrograms.COLUMN_REVIEW_RATING, WatchNextPrograms.COLUMN_REVIEW_RATING); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_BROWSABLE, WatchNextPrograms.COLUMN_BROWSABLE)634 sWatchNextProgramProjectionMap.put( 635 WatchNextPrograms.COLUMN_BROWSABLE, WatchNextPrograms.COLUMN_BROWSABLE); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_CONTENT_ID, WatchNextPrograms.COLUMN_CONTENT_ID)636 sWatchNextProgramProjectionMap.put( 637 WatchNextPrograms.COLUMN_CONTENT_ID, WatchNextPrograms.COLUMN_CONTENT_ID); sWatchNextProgramProjectionMap.put( WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS, WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS)638 sWatchNextProgramProjectionMap.put( 639 WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS, 640 WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS); 641 } 642 643 // Mapping from broadcast genre to canonical genre. 644 private static Map<String, String> sGenreMap; 645 646 private static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS"; 647 648 private static final String PERMISSION_ACCESS_ALL_EPG_DATA = 649 "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA"; 650 651 private static final String PERMISSION_ACCESS_WATCHED_PROGRAMS = 652 "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS"; 653 654 private static final String CREATE_RECORDED_PROGRAMS_TABLE_SQL = 655 "CREATE TABLE " 656 + RECORDED_PROGRAMS_TABLE 657 + " (" 658 + RecordedPrograms._ID 659 + " INTEGER PRIMARY KEY AUTOINCREMENT," 660 + RecordedPrograms.COLUMN_PACKAGE_NAME 661 + " TEXT NOT NULL," 662 + RecordedPrograms.COLUMN_INPUT_ID 663 + " TEXT NOT NULL," 664 + RecordedPrograms.COLUMN_CHANNEL_ID 665 + " INTEGER," 666 + RecordedPrograms.COLUMN_TITLE 667 + " TEXT," 668 + RecordedPrograms.COLUMN_SEASON_DISPLAY_NUMBER 669 + " TEXT," 670 + RecordedPrograms.COLUMN_SEASON_TITLE 671 + " TEXT," 672 + RecordedPrograms.COLUMN_EPISODE_DISPLAY_NUMBER 673 + " TEXT," 674 + RecordedPrograms.COLUMN_EPISODE_TITLE 675 + " TEXT," 676 + RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS 677 + " INTEGER," 678 + RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS 679 + " INTEGER," 680 + RecordedPrograms.COLUMN_BROADCAST_GENRE 681 + " TEXT," 682 + RecordedPrograms.COLUMN_CANONICAL_GENRE 683 + " TEXT," 684 + RecordedPrograms.COLUMN_SHORT_DESCRIPTION 685 + " TEXT," 686 + RecordedPrograms.COLUMN_LONG_DESCRIPTION 687 + " TEXT," 688 + RecordedPrograms.COLUMN_VIDEO_WIDTH 689 + " INTEGER," 690 + RecordedPrograms.COLUMN_VIDEO_HEIGHT 691 + " INTEGER," 692 + RecordedPrograms.COLUMN_AUDIO_LANGUAGE 693 + " TEXT," 694 + RecordedPrograms.COLUMN_CONTENT_RATING 695 + " TEXT," 696 + RecordedPrograms.COLUMN_POSTER_ART_URI 697 + " TEXT," 698 + RecordedPrograms.COLUMN_THUMBNAIL_URI 699 + " TEXT," 700 + RecordedPrograms.COLUMN_SEARCHABLE 701 + " INTEGER NOT NULL DEFAULT 1," 702 + RecordedPrograms.COLUMN_RECORDING_DATA_URI 703 + " TEXT," 704 + RecordedPrograms.COLUMN_RECORDING_DATA_BYTES 705 + " INTEGER," 706 + RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS 707 + " INTEGER," 708 + RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS 709 + " INTEGER," 710 + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA 711 + " BLOB," 712 + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1 713 + " INTEGER," 714 + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2 715 + " INTEGER," 716 + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3 717 + " INTEGER," 718 + RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4 719 + " INTEGER," 720 + RecordedPrograms.COLUMN_VERSION_NUMBER 721 + " INTEGER," 722 + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE 723 + " INTEGER," 724 + RecordedPrograms.COLUMN_REVIEW_RATING 725 + " TEXT," 726 + "FOREIGN KEY(" 727 + RecordedPrograms.COLUMN_CHANNEL_ID 728 + ") " 729 + "REFERENCES " 730 + CHANNELS_TABLE 731 + "(" 732 + Channels._ID 733 + ") " 734 + "ON UPDATE CASCADE ON DELETE SET NULL);"; 735 736 private static final String CREATE_PREVIEW_PROGRAMS_TABLE_SQL = 737 "CREATE TABLE " 738 + PREVIEW_PROGRAMS_TABLE 739 + " (" 740 + PreviewPrograms._ID 741 + " INTEGER PRIMARY KEY AUTOINCREMENT," 742 + PreviewPrograms.COLUMN_PACKAGE_NAME 743 + " TEXT NOT NULL," 744 + PreviewPrograms.COLUMN_CHANNEL_ID 745 + " INTEGER," 746 + PreviewPrograms.COLUMN_TITLE 747 + " TEXT," 748 + PreviewPrograms.COLUMN_SEASON_DISPLAY_NUMBER 749 + " TEXT," 750 + PreviewPrograms.COLUMN_SEASON_TITLE 751 + " TEXT," 752 + PreviewPrograms.COLUMN_EPISODE_DISPLAY_NUMBER 753 + " TEXT," 754 + PreviewPrograms.COLUMN_EPISODE_TITLE 755 + " TEXT," 756 + PreviewPrograms.COLUMN_CANONICAL_GENRE 757 + " TEXT," 758 + PreviewPrograms.COLUMN_SHORT_DESCRIPTION 759 + " TEXT," 760 + PreviewPrograms.COLUMN_LONG_DESCRIPTION 761 + " TEXT," 762 + PreviewPrograms.COLUMN_VIDEO_WIDTH 763 + " INTEGER," 764 + PreviewPrograms.COLUMN_VIDEO_HEIGHT 765 + " INTEGER," 766 + PreviewPrograms.COLUMN_AUDIO_LANGUAGE 767 + " TEXT," 768 + PreviewPrograms.COLUMN_CONTENT_RATING 769 + " TEXT," 770 + PreviewPrograms.COLUMN_POSTER_ART_URI 771 + " TEXT," 772 + PreviewPrograms.COLUMN_THUMBNAIL_URI 773 + " TEXT," 774 + PreviewPrograms.COLUMN_SEARCHABLE 775 + " INTEGER NOT NULL DEFAULT 1," 776 + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_DATA 777 + " BLOB," 778 + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1 779 + " INTEGER," 780 + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2 781 + " INTEGER," 782 + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3 783 + " INTEGER," 784 + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4 785 + " INTEGER," 786 + PreviewPrograms.COLUMN_VERSION_NUMBER 787 + " INTEGER," 788 + PreviewPrograms.COLUMN_INTERNAL_PROVIDER_ID 789 + " TEXT," 790 + PreviewPrograms.COLUMN_PREVIEW_VIDEO_URI 791 + " TEXT," 792 + PreviewPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS 793 + " INTEGER," 794 + PreviewPrograms.COLUMN_DURATION_MILLIS 795 + " INTEGER," 796 + PreviewPrograms.COLUMN_INTENT_URI 797 + " TEXT," 798 + PreviewPrograms.COLUMN_WEIGHT 799 + " INTEGER," 800 + PreviewPrograms.COLUMN_TRANSIENT 801 + " INTEGER NOT NULL DEFAULT 0," 802 + PreviewPrograms.COLUMN_TYPE 803 + " INTEGER NOT NULL," 804 + PreviewPrograms.COLUMN_POSTER_ART_ASPECT_RATIO 805 + " INTEGER," 806 + PreviewPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO 807 + " INTEGER," 808 + PreviewPrograms.COLUMN_LOGO_URI 809 + " TEXT," 810 + PreviewPrograms.COLUMN_AVAILABILITY 811 + " INTERGER," 812 + PreviewPrograms.COLUMN_STARTING_PRICE 813 + " TEXT," 814 + PreviewPrograms.COLUMN_OFFER_PRICE 815 + " TEXT," 816 + PreviewPrograms.COLUMN_RELEASE_DATE 817 + " TEXT," 818 + PreviewPrograms.COLUMN_ITEM_COUNT 819 + " INTEGER," 820 + PreviewPrograms.COLUMN_LIVE 821 + " INTEGER NOT NULL DEFAULT 0," 822 + PreviewPrograms.COLUMN_INTERACTION_TYPE 823 + " INTEGER," 824 + PreviewPrograms.COLUMN_INTERACTION_COUNT 825 + " INTEGER," 826 + PreviewPrograms.COLUMN_AUTHOR 827 + " TEXT," 828 + PreviewPrograms.COLUMN_REVIEW_RATING_STYLE 829 + " INTEGER," 830 + PreviewPrograms.COLUMN_REVIEW_RATING 831 + " TEXT," 832 + PreviewPrograms.COLUMN_BROWSABLE 833 + " INTEGER NOT NULL DEFAULT 1," 834 + PreviewPrograms.COLUMN_CONTENT_ID 835 + " TEXT," 836 + "FOREIGN KEY(" 837 + PreviewPrograms.COLUMN_CHANNEL_ID 838 + "," 839 + PreviewPrograms.COLUMN_PACKAGE_NAME 840 + ") REFERENCES " 841 + CHANNELS_TABLE 842 + "(" 843 + Channels._ID 844 + "," 845 + Channels.COLUMN_PACKAGE_NAME 846 + ") ON UPDATE CASCADE ON DELETE CASCADE" 847 + ");"; 848 private static final String CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL = 849 "CREATE INDEX preview_programs_package_name_index ON " 850 + PREVIEW_PROGRAMS_TABLE 851 + "(" 852 + PreviewPrograms.COLUMN_PACKAGE_NAME 853 + ");"; 854 private static final String CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL = 855 "CREATE INDEX preview_programs_id_index ON " 856 + PREVIEW_PROGRAMS_TABLE 857 + "(" 858 + PreviewPrograms.COLUMN_CHANNEL_ID 859 + ");"; 860 private static final String CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL = 861 "CREATE TABLE " 862 + WATCH_NEXT_PROGRAMS_TABLE 863 + " (" 864 + WatchNextPrograms._ID 865 + " INTEGER PRIMARY KEY AUTOINCREMENT," 866 + WatchNextPrograms.COLUMN_PACKAGE_NAME 867 + " TEXT NOT NULL," 868 + WatchNextPrograms.COLUMN_TITLE 869 + " TEXT," 870 + WatchNextPrograms.COLUMN_SEASON_DISPLAY_NUMBER 871 + " TEXT," 872 + WatchNextPrograms.COLUMN_SEASON_TITLE 873 + " TEXT," 874 + WatchNextPrograms.COLUMN_EPISODE_DISPLAY_NUMBER 875 + " TEXT," 876 + WatchNextPrograms.COLUMN_EPISODE_TITLE 877 + " TEXT," 878 + WatchNextPrograms.COLUMN_CANONICAL_GENRE 879 + " TEXT," 880 + WatchNextPrograms.COLUMN_SHORT_DESCRIPTION 881 + " TEXT," 882 + WatchNextPrograms.COLUMN_LONG_DESCRIPTION 883 + " TEXT," 884 + WatchNextPrograms.COLUMN_VIDEO_WIDTH 885 + " INTEGER," 886 + WatchNextPrograms.COLUMN_VIDEO_HEIGHT 887 + " INTEGER," 888 + WatchNextPrograms.COLUMN_AUDIO_LANGUAGE 889 + " TEXT," 890 + WatchNextPrograms.COLUMN_CONTENT_RATING 891 + " TEXT," 892 + WatchNextPrograms.COLUMN_POSTER_ART_URI 893 + " TEXT," 894 + WatchNextPrograms.COLUMN_THUMBNAIL_URI 895 + " TEXT," 896 + WatchNextPrograms.COLUMN_SEARCHABLE 897 + " INTEGER NOT NULL DEFAULT 1," 898 + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_DATA 899 + " BLOB," 900 + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1 901 + " INTEGER," 902 + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2 903 + " INTEGER," 904 + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3 905 + " INTEGER," 906 + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4 907 + " INTEGER," 908 + WatchNextPrograms.COLUMN_VERSION_NUMBER 909 + " INTEGER," 910 + WatchNextPrograms.COLUMN_INTERNAL_PROVIDER_ID 911 + " TEXT," 912 + WatchNextPrograms.COLUMN_PREVIEW_VIDEO_URI 913 + " TEXT," 914 + WatchNextPrograms.COLUMN_LAST_PLAYBACK_POSITION_MILLIS 915 + " INTEGER," 916 + WatchNextPrograms.COLUMN_DURATION_MILLIS 917 + " INTEGER," 918 + WatchNextPrograms.COLUMN_INTENT_URI 919 + " TEXT," 920 + WatchNextPrograms.COLUMN_TRANSIENT 921 + " INTEGER NOT NULL DEFAULT 0," 922 + WatchNextPrograms.COLUMN_TYPE 923 + " INTEGER NOT NULL," 924 + WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE 925 + " INTEGER," 926 + WatchNextPrograms.COLUMN_POSTER_ART_ASPECT_RATIO 927 + " INTEGER," 928 + WatchNextPrograms.COLUMN_THUMBNAIL_ASPECT_RATIO 929 + " INTEGER," 930 + WatchNextPrograms.COLUMN_LOGO_URI 931 + " TEXT," 932 + WatchNextPrograms.COLUMN_AVAILABILITY 933 + " INTEGER," 934 + WatchNextPrograms.COLUMN_STARTING_PRICE 935 + " TEXT," 936 + WatchNextPrograms.COLUMN_OFFER_PRICE 937 + " TEXT," 938 + WatchNextPrograms.COLUMN_RELEASE_DATE 939 + " TEXT," 940 + WatchNextPrograms.COLUMN_ITEM_COUNT 941 + " INTEGER," 942 + WatchNextPrograms.COLUMN_LIVE 943 + " INTEGER NOT NULL DEFAULT 0," 944 + WatchNextPrograms.COLUMN_INTERACTION_TYPE 945 + " INTEGER," 946 + WatchNextPrograms.COLUMN_INTERACTION_COUNT 947 + " INTEGER," 948 + WatchNextPrograms.COLUMN_AUTHOR 949 + " TEXT," 950 + WatchNextPrograms.COLUMN_REVIEW_RATING_STYLE 951 + " INTEGER," 952 + WatchNextPrograms.COLUMN_REVIEW_RATING 953 + " TEXT," 954 + WatchNextPrograms.COLUMN_BROWSABLE 955 + " INTEGER NOT NULL DEFAULT 1," 956 + WatchNextPrograms.COLUMN_CONTENT_ID 957 + " TEXT," 958 + WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS 959 + " INTEGER" 960 + ");"; 961 private static final String CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL = 962 "CREATE INDEX watch_next_programs_package_name_index ON " 963 + WATCH_NEXT_PROGRAMS_TABLE 964 + "(" 965 + WatchNextPrograms.COLUMN_PACKAGE_NAME 966 + ");"; 967 968 private String mCallingPackage = "com.android.tv"; 969 970 static class DatabaseHelper extends SQLiteOpenHelper { 971 private Context mContext; 972 createInstance(Context context)973 public static synchronized DatabaseHelper createInstance(Context context) { 974 return new DatabaseHelper(context); 975 } 976 DatabaseHelper(Context context)977 private DatabaseHelper(Context context) { 978 this(context, DATABASE_NAME, DATABASE_VERSION); 979 } 980 981 @VisibleForTesting DatabaseHelper(Context context, String databaseName, int databaseVersion)982 DatabaseHelper(Context context, String databaseName, int databaseVersion) { 983 super(context, databaseName, null, databaseVersion); 984 mContext = context; 985 } 986 987 @Override onConfigure(SQLiteDatabase db)988 public void onConfigure(SQLiteDatabase db) { 989 db.setForeignKeyConstraintsEnabled(true); 990 } 991 992 @Override onCreate(SQLiteDatabase db)993 public void onCreate(SQLiteDatabase db) { 994 if (DEBUG) { 995 Log.d(TAG, "Creating database"); 996 } 997 // Set up the database schema. 998 db.execSQL( 999 "CREATE TABLE " 1000 + CHANNELS_TABLE 1001 + " (" 1002 + Channels._ID 1003 + " INTEGER PRIMARY KEY AUTOINCREMENT," 1004 + Channels.COLUMN_PACKAGE_NAME 1005 + " TEXT NOT NULL," 1006 + Channels.COLUMN_INPUT_ID 1007 + " TEXT NOT NULL," 1008 + Channels.COLUMN_TYPE 1009 + " TEXT NOT NULL DEFAULT '" 1010 + Channels.TYPE_OTHER 1011 + "'," 1012 + Channels.COLUMN_SERVICE_TYPE 1013 + " TEXT NOT NULL DEFAULT '" 1014 + Channels.SERVICE_TYPE_AUDIO_VIDEO 1015 + "'," 1016 + Channels.COLUMN_ORIGINAL_NETWORK_ID 1017 + " INTEGER NOT NULL DEFAULT 0," 1018 + Channels.COLUMN_TRANSPORT_STREAM_ID 1019 + " INTEGER NOT NULL DEFAULT 0," 1020 + Channels.COLUMN_SERVICE_ID 1021 + " INTEGER NOT NULL DEFAULT 0," 1022 + Channels.COLUMN_DISPLAY_NUMBER 1023 + " TEXT," 1024 + Channels.COLUMN_DISPLAY_NAME 1025 + " TEXT," 1026 + Channels.COLUMN_NETWORK_AFFILIATION 1027 + " TEXT," 1028 + Channels.COLUMN_DESCRIPTION 1029 + " TEXT," 1030 + Channels.COLUMN_VIDEO_FORMAT 1031 + " TEXT," 1032 + Channels.COLUMN_BROWSABLE 1033 + " INTEGER NOT NULL DEFAULT 0," 1034 + Channels.COLUMN_SEARCHABLE 1035 + " INTEGER NOT NULL DEFAULT 1," 1036 + Channels.COLUMN_LOCKED 1037 + " INTEGER NOT NULL DEFAULT 0," 1038 + Channels.COLUMN_APP_LINK_ICON_URI 1039 + " TEXT," 1040 + Channels.COLUMN_APP_LINK_POSTER_ART_URI 1041 + " TEXT," 1042 + Channels.COLUMN_APP_LINK_TEXT 1043 + " TEXT," 1044 + Channels.COLUMN_APP_LINK_COLOR 1045 + " INTEGER," 1046 + Channels.COLUMN_APP_LINK_INTENT_URI 1047 + " TEXT," 1048 + Channels.COLUMN_INTERNAL_PROVIDER_DATA 1049 + " BLOB," 1050 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1 1051 + " INTEGER," 1052 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2 1053 + " INTEGER," 1054 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3 1055 + " INTEGER," 1056 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4 1057 + " INTEGER," 1058 + CHANNELS_COLUMN_LOGO 1059 + " BLOB," 1060 + Channels.COLUMN_VERSION_NUMBER 1061 + " INTEGER," 1062 + Channels.COLUMN_TRANSIENT 1063 + " INTEGER NOT NULL DEFAULT 0," 1064 + Channels.COLUMN_INTERNAL_PROVIDER_ID 1065 + " TEXT," 1066 // Needed for foreign keys in other tables. 1067 + "UNIQUE(" 1068 + Channels._ID 1069 + "," 1070 + Channels.COLUMN_PACKAGE_NAME 1071 + ")" 1072 + ");"); 1073 db.execSQL( 1074 "CREATE TABLE " 1075 + PROGRAMS_TABLE 1076 + " (" 1077 + Programs._ID 1078 + " INTEGER PRIMARY KEY AUTOINCREMENT," 1079 + Programs.COLUMN_PACKAGE_NAME 1080 + " TEXT NOT NULL," 1081 + Programs.COLUMN_CHANNEL_ID 1082 + " INTEGER," 1083 + Programs.COLUMN_TITLE 1084 + " TEXT," 1085 + Programs.COLUMN_SEASON_DISPLAY_NUMBER 1086 + " TEXT," 1087 + Programs.COLUMN_SEASON_TITLE 1088 + " TEXT," 1089 + Programs.COLUMN_EPISODE_DISPLAY_NUMBER 1090 + " TEXT," 1091 + Programs.COLUMN_EPISODE_TITLE 1092 + " TEXT," 1093 + Programs.COLUMN_START_TIME_UTC_MILLIS 1094 + " INTEGER," 1095 + Programs.COLUMN_END_TIME_UTC_MILLIS 1096 + " INTEGER," 1097 + Programs.COLUMN_BROADCAST_GENRE 1098 + " TEXT," 1099 + Programs.COLUMN_CANONICAL_GENRE 1100 + " TEXT," 1101 + Programs.COLUMN_SHORT_DESCRIPTION 1102 + " TEXT," 1103 + Programs.COLUMN_LONG_DESCRIPTION 1104 + " TEXT," 1105 + Programs.COLUMN_VIDEO_WIDTH 1106 + " INTEGER," 1107 + Programs.COLUMN_VIDEO_HEIGHT 1108 + " INTEGER," 1109 + Programs.COLUMN_AUDIO_LANGUAGE 1110 + " TEXT," 1111 + Programs.COLUMN_CONTENT_RATING 1112 + " TEXT," 1113 + Programs.COLUMN_POSTER_ART_URI 1114 + " TEXT," 1115 + Programs.COLUMN_THUMBNAIL_URI 1116 + " TEXT," 1117 + Programs.COLUMN_SEARCHABLE 1118 + " INTEGER NOT NULL DEFAULT 1," 1119 + Programs.COLUMN_RECORDING_PROHIBITED 1120 + " INTEGER NOT NULL DEFAULT 0," 1121 + Programs.COLUMN_INTERNAL_PROVIDER_DATA 1122 + " BLOB," 1123 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1 1124 + " INTEGER," 1125 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2 1126 + " INTEGER," 1127 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3 1128 + " INTEGER," 1129 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4 1130 + " INTEGER," 1131 + Programs.COLUMN_REVIEW_RATING_STYLE 1132 + " INTEGER," 1133 + Programs.COLUMN_REVIEW_RATING 1134 + " TEXT," 1135 + Programs.COLUMN_VERSION_NUMBER 1136 + " INTEGER," 1137 + "FOREIGN KEY(" 1138 + Programs.COLUMN_CHANNEL_ID 1139 + "," 1140 + Programs.COLUMN_PACKAGE_NAME 1141 + ") REFERENCES " 1142 + CHANNELS_TABLE 1143 + "(" 1144 + Channels._ID 1145 + "," 1146 + Channels.COLUMN_PACKAGE_NAME 1147 + ") ON UPDATE CASCADE ON DELETE CASCADE" 1148 + ");"); 1149 db.execSQL( 1150 "CREATE INDEX " 1151 + PROGRAMS_TABLE_PACKAGE_NAME_INDEX 1152 + " ON " 1153 + PROGRAMS_TABLE 1154 + "(" 1155 + Programs.COLUMN_PACKAGE_NAME 1156 + ");"); 1157 db.execSQL( 1158 "CREATE INDEX " 1159 + PROGRAMS_TABLE_CHANNEL_ID_INDEX 1160 + " ON " 1161 + PROGRAMS_TABLE 1162 + "(" 1163 + Programs.COLUMN_CHANNEL_ID 1164 + ");"); 1165 db.execSQL( 1166 "CREATE INDEX " 1167 + PROGRAMS_TABLE_START_TIME_INDEX 1168 + " ON " 1169 + PROGRAMS_TABLE 1170 + "(" 1171 + Programs.COLUMN_START_TIME_UTC_MILLIS 1172 + ");"); 1173 db.execSQL( 1174 "CREATE INDEX " 1175 + PROGRAMS_TABLE_END_TIME_INDEX 1176 + " ON " 1177 + PROGRAMS_TABLE 1178 + "(" 1179 + Programs.COLUMN_END_TIME_UTC_MILLIS 1180 + ");"); 1181 db.execSQL( 1182 "CREATE TABLE " 1183 + WATCHED_PROGRAMS_TABLE 1184 + " (" 1185 + WatchedPrograms._ID 1186 + " INTEGER PRIMARY KEY AUTOINCREMENT," 1187 + WatchedPrograms.COLUMN_PACKAGE_NAME 1188 + " TEXT NOT NULL," 1189 + WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS 1190 + " INTEGER NOT NULL DEFAULT 0," 1191 + WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS 1192 + " INTEGER NOT NULL DEFAULT 0," 1193 + WatchedPrograms.COLUMN_CHANNEL_ID 1194 + " INTEGER," 1195 + WatchedPrograms.COLUMN_TITLE 1196 + " TEXT," 1197 + WatchedPrograms.COLUMN_START_TIME_UTC_MILLIS 1198 + " INTEGER," 1199 + WatchedPrograms.COLUMN_END_TIME_UTC_MILLIS 1200 + " INTEGER," 1201 + WatchedPrograms.COLUMN_DESCRIPTION 1202 + " TEXT," 1203 + WatchedPrograms.COLUMN_INTERNAL_TUNE_PARAMS 1204 + " TEXT," 1205 + WatchedPrograms.COLUMN_INTERNAL_SESSION_TOKEN 1206 + " TEXT NOT NULL," 1207 + WATCHED_PROGRAMS_COLUMN_CONSOLIDATED 1208 + " INTEGER NOT NULL DEFAULT 0," 1209 + "FOREIGN KEY(" 1210 + WatchedPrograms.COLUMN_CHANNEL_ID 1211 + "," 1212 + WatchedPrograms.COLUMN_PACKAGE_NAME 1213 + ") REFERENCES " 1214 + CHANNELS_TABLE 1215 + "(" 1216 + Channels._ID 1217 + "," 1218 + Channels.COLUMN_PACKAGE_NAME 1219 + ") ON UPDATE CASCADE ON DELETE CASCADE" 1220 + ");"); 1221 db.execSQL( 1222 "CREATE INDEX " 1223 + WATCHED_PROGRAMS_TABLE_CHANNEL_ID_INDEX 1224 + " ON " 1225 + WATCHED_PROGRAMS_TABLE 1226 + "(" 1227 + WatchedPrograms.COLUMN_CHANNEL_ID 1228 + ");"); 1229 db.execSQL(CREATE_RECORDED_PROGRAMS_TABLE_SQL); 1230 db.execSQL(CREATE_PREVIEW_PROGRAMS_TABLE_SQL); 1231 db.execSQL(CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL); 1232 db.execSQL(CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL); 1233 db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL); 1234 db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL); 1235 } 1236 1237 @Override onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)1238 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 1239 if (oldVersion < 23) { 1240 Log.i( 1241 TAG, 1242 "Upgrading from version " 1243 + oldVersion 1244 + " to " 1245 + newVersion 1246 + ", data will be lost!"); 1247 db.execSQL("DROP TABLE IF EXISTS " + DELETED_CHANNELS_TABLE); 1248 db.execSQL("DROP TABLE IF EXISTS " + WATCHED_PROGRAMS_TABLE); 1249 db.execSQL("DROP TABLE IF EXISTS " + PROGRAMS_TABLE); 1250 db.execSQL("DROP TABLE IF EXISTS " + CHANNELS_TABLE); 1251 1252 onCreate(db); 1253 return; 1254 } 1255 1256 Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion + "."); 1257 if (oldVersion <= 23) { 1258 db.execSQL( 1259 "ALTER TABLE " 1260 + CHANNELS_TABLE 1261 + " ADD " 1262 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG1 1263 + " INTEGER;"); 1264 db.execSQL( 1265 "ALTER TABLE " 1266 + CHANNELS_TABLE 1267 + " ADD " 1268 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG2 1269 + " INTEGER;"); 1270 db.execSQL( 1271 "ALTER TABLE " 1272 + CHANNELS_TABLE 1273 + " ADD " 1274 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG3 1275 + " INTEGER;"); 1276 db.execSQL( 1277 "ALTER TABLE " 1278 + CHANNELS_TABLE 1279 + " ADD " 1280 + Channels.COLUMN_INTERNAL_PROVIDER_FLAG4 1281 + " INTEGER;"); 1282 } 1283 if (oldVersion <= 24) { 1284 db.execSQL( 1285 "ALTER TABLE " 1286 + PROGRAMS_TABLE 1287 + " ADD " 1288 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG1 1289 + " INTEGER;"); 1290 db.execSQL( 1291 "ALTER TABLE " 1292 + PROGRAMS_TABLE 1293 + " ADD " 1294 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG2 1295 + " INTEGER;"); 1296 db.execSQL( 1297 "ALTER TABLE " 1298 + PROGRAMS_TABLE 1299 + " ADD " 1300 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG3 1301 + " INTEGER;"); 1302 db.execSQL( 1303 "ALTER TABLE " 1304 + PROGRAMS_TABLE 1305 + " ADD " 1306 + Programs.COLUMN_INTERNAL_PROVIDER_FLAG4 1307 + " INTEGER;"); 1308 } 1309 if (oldVersion <= 25) { 1310 db.execSQL( 1311 "ALTER TABLE " 1312 + CHANNELS_TABLE 1313 + " ADD " 1314 + Channels.COLUMN_APP_LINK_ICON_URI 1315 + " TEXT;"); 1316 db.execSQL( 1317 "ALTER TABLE " 1318 + CHANNELS_TABLE 1319 + " ADD " 1320 + Channels.COLUMN_APP_LINK_POSTER_ART_URI 1321 + " TEXT;"); 1322 db.execSQL( 1323 "ALTER TABLE " 1324 + CHANNELS_TABLE 1325 + " ADD " 1326 + Channels.COLUMN_APP_LINK_TEXT 1327 + " TEXT;"); 1328 db.execSQL( 1329 "ALTER TABLE " 1330 + CHANNELS_TABLE 1331 + " ADD " 1332 + Channels.COLUMN_APP_LINK_COLOR 1333 + " INTEGER;"); 1334 db.execSQL( 1335 "ALTER TABLE " 1336 + CHANNELS_TABLE 1337 + " ADD " 1338 + Channels.COLUMN_APP_LINK_INTENT_URI 1339 + " TEXT;"); 1340 db.execSQL( 1341 "ALTER TABLE " 1342 + PROGRAMS_TABLE 1343 + " ADD " 1344 + Programs.COLUMN_SEARCHABLE 1345 + " INTEGER NOT NULL DEFAULT 1;"); 1346 } 1347 if (oldVersion <= 28) { 1348 db.execSQL( 1349 "ALTER TABLE " 1350 + PROGRAMS_TABLE 1351 + " ADD " 1352 + Programs.COLUMN_SEASON_TITLE 1353 + " TEXT;"); 1354 migrateIntegerColumnToTextColumn( 1355 db, 1356 PROGRAMS_TABLE, 1357 Programs.COLUMN_SEASON_NUMBER, 1358 Programs.COLUMN_SEASON_DISPLAY_NUMBER); 1359 migrateIntegerColumnToTextColumn( 1360 db, 1361 PROGRAMS_TABLE, 1362 Programs.COLUMN_EPISODE_NUMBER, 1363 Programs.COLUMN_EPISODE_DISPLAY_NUMBER); 1364 } 1365 if (oldVersion <= 29) { 1366 db.execSQL("DROP TABLE IF EXISTS " + RECORDED_PROGRAMS_TABLE); 1367 db.execSQL(CREATE_RECORDED_PROGRAMS_TABLE_SQL); 1368 } 1369 if (oldVersion <= 30) { 1370 db.execSQL( 1371 "ALTER TABLE " 1372 + PROGRAMS_TABLE 1373 + " ADD " 1374 + Programs.COLUMN_RECORDING_PROHIBITED 1375 + " INTEGER NOT NULL DEFAULT 0;"); 1376 } 1377 if (oldVersion <= 32) { 1378 db.execSQL( 1379 "ALTER TABLE " 1380 + CHANNELS_TABLE 1381 + " ADD " 1382 + Channels.COLUMN_TRANSIENT 1383 + " INTEGER NOT NULL DEFAULT 0;"); 1384 db.execSQL( 1385 "ALTER TABLE " 1386 + CHANNELS_TABLE 1387 + " ADD " 1388 + Channels.COLUMN_INTERNAL_PROVIDER_ID 1389 + " TEXT;"); 1390 db.execSQL( 1391 "ALTER TABLE " 1392 + PROGRAMS_TABLE 1393 + " ADD " 1394 + Programs.COLUMN_REVIEW_RATING_STYLE 1395 + " INTEGER;"); 1396 db.execSQL( 1397 "ALTER TABLE " 1398 + PROGRAMS_TABLE 1399 + " ADD " 1400 + Programs.COLUMN_REVIEW_RATING 1401 + " TEXT;"); 1402 if (oldVersion > 29) { 1403 db.execSQL( 1404 "ALTER TABLE " 1405 + RECORDED_PROGRAMS_TABLE 1406 + " ADD " 1407 + RecordedPrograms.COLUMN_REVIEW_RATING_STYLE 1408 + " INTEGER;"); 1409 db.execSQL( 1410 "ALTER TABLE " 1411 + RECORDED_PROGRAMS_TABLE 1412 + " ADD " 1413 + RecordedPrograms.COLUMN_REVIEW_RATING 1414 + " TEXT;"); 1415 } 1416 } 1417 if (oldVersion <= 33) { 1418 db.execSQL("DROP TABLE IF EXISTS " + PREVIEW_PROGRAMS_TABLE); 1419 db.execSQL("DROP TABLE IF EXISTS " + WATCH_NEXT_PROGRAMS_TABLE); 1420 db.execSQL(CREATE_PREVIEW_PROGRAMS_TABLE_SQL); 1421 db.execSQL(CREATE_PREVIEW_PROGRAMS_PACKAGE_NAME_INDEX_SQL); 1422 db.execSQL(CREATE_PREVIEW_PROGRAMS_CHANNEL_ID_INDEX_SQL); 1423 db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_TABLE_SQL); 1424 db.execSQL(CREATE_WATCH_NEXT_PROGRAMS_PACKAGE_NAME_INDEX_SQL); 1425 } 1426 Log.i(TAG, "Upgrading from version " + oldVersion + " to " + newVersion + " is done."); 1427 } 1428 1429 @Override onOpen(SQLiteDatabase db)1430 public void onOpen(SQLiteDatabase db) { 1431 // Call a static method on the TvProvider because changes to sInitialized must 1432 // be guarded by a lock on the class. 1433 initOnOpenIfNeeded(mContext, db); 1434 } 1435 migrateIntegerColumnToTextColumn( SQLiteDatabase db, String table, String integerColumn, String textColumn)1436 private static void migrateIntegerColumnToTextColumn( 1437 SQLiteDatabase db, String table, String integerColumn, String textColumn) { 1438 db.execSQL("ALTER TABLE " + table + " ADD " + textColumn + " TEXT;"); 1439 db.execSQL( 1440 "UPDATE " 1441 + table 1442 + " SET " 1443 + textColumn 1444 + " = CAST(" 1445 + integerColumn 1446 + " AS TEXT);"); 1447 } 1448 } 1449 1450 private DatabaseHelper mOpenHelper; 1451 private static SharedPreferences sBlockedPackagesSharedPreference; 1452 private static Map<String, Boolean> sBlockedPackages; 1453 1454 @Override onCreate()1455 public boolean onCreate() { 1456 if (DEBUG) { 1457 Log.d(TAG, "Creating TvProvider"); 1458 } 1459 mOpenHelper = DatabaseHelper.createInstance(getContext()); 1460 return true; 1461 } 1462 1463 @VisibleForTesting getCallingPackage_()1464 String getCallingPackage_() { 1465 return mCallingPackage; 1466 } 1467 setCallingPackage(String packageName)1468 public void setCallingPackage(String packageName) { 1469 mCallingPackage = packageName; 1470 } 1471 setOpenHelper(DatabaseHelper helper)1472 void setOpenHelper(DatabaseHelper helper) { 1473 mOpenHelper = helper; 1474 } 1475 1476 @Override getType(Uri uri)1477 public String getType(Uri uri) { 1478 switch (sUriMatcher.match(uri)) { 1479 case MATCH_CHANNEL: 1480 return Channels.CONTENT_TYPE; 1481 case MATCH_CHANNEL_ID: 1482 return Channels.CONTENT_ITEM_TYPE; 1483 case MATCH_CHANNEL_ID_LOGO: 1484 return "image/png"; 1485 case MATCH_PASSTHROUGH_ID: 1486 return Channels.CONTENT_ITEM_TYPE; 1487 case MATCH_PROGRAM: 1488 return Programs.CONTENT_TYPE; 1489 case MATCH_PROGRAM_ID: 1490 return Programs.CONTENT_ITEM_TYPE; 1491 case MATCH_WATCHED_PROGRAM: 1492 return WatchedPrograms.CONTENT_TYPE; 1493 case MATCH_WATCHED_PROGRAM_ID: 1494 return WatchedPrograms.CONTENT_ITEM_TYPE; 1495 case MATCH_RECORDED_PROGRAM: 1496 return RecordedPrograms.CONTENT_TYPE; 1497 case MATCH_RECORDED_PROGRAM_ID: 1498 return RecordedPrograms.CONTENT_ITEM_TYPE; 1499 case MATCH_PREVIEW_PROGRAM: 1500 return PreviewPrograms.CONTENT_TYPE; 1501 case MATCH_PREVIEW_PROGRAM_ID: 1502 return PreviewPrograms.CONTENT_ITEM_TYPE; 1503 case MATCH_WATCH_NEXT_PROGRAM: 1504 return WatchNextPrograms.CONTENT_TYPE; 1505 case MATCH_WATCH_NEXT_PROGRAM_ID: 1506 return WatchNextPrograms.CONTENT_ITEM_TYPE; 1507 default: 1508 throw new IllegalArgumentException("Unknown URI " + uri); 1509 } 1510 } 1511 1512 @Override call(String method, String arg, Bundle extras)1513 public Bundle call(String method, String arg, Bundle extras) { 1514 throw new UnsupportedOperationException(); 1515 } 1516 1517 @Override query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)1518 public Cursor query( 1519 Uri uri, 1520 String[] projection, 1521 String selection, 1522 String[] selectionArgs, 1523 String sortOrder) { 1524 ensureInitialized(); 1525 boolean needsToValidateSortOrder = !callerHasAccessAllEpgDataPermission(); 1526 SqlParams params = createSqlParams(OP_QUERY, uri, selection, selectionArgs); 1527 1528 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); 1529 queryBuilder.setStrict(needsToValidateSortOrder); 1530 queryBuilder.setTables(params.getTables()); 1531 String orderBy = null; 1532 Map<String, String> projectionMap; 1533 switch (params.getTables()) { 1534 case PROGRAMS_TABLE: 1535 projectionMap = sProgramProjectionMap; 1536 orderBy = DEFAULT_PROGRAMS_SORT_ORDER; 1537 break; 1538 case WATCHED_PROGRAMS_TABLE: 1539 projectionMap = sWatchedProgramProjectionMap; 1540 orderBy = DEFAULT_WATCHED_PROGRAMS_SORT_ORDER; 1541 break; 1542 case RECORDED_PROGRAMS_TABLE: 1543 projectionMap = sRecordedProgramProjectionMap; 1544 break; 1545 case PREVIEW_PROGRAMS_TABLE: 1546 projectionMap = sPreviewProgramProjectionMap; 1547 break; 1548 case WATCH_NEXT_PROGRAMS_TABLE: 1549 projectionMap = sWatchNextProgramProjectionMap; 1550 break; 1551 default: 1552 projectionMap = sChannelProjectionMap; 1553 break; 1554 } 1555 queryBuilder.setProjectionMap(createProjectionMapForQuery(projection, projectionMap)); 1556 if (needsToValidateSortOrder) { 1557 validateSortOrder(sortOrder, projectionMap.keySet()); 1558 } 1559 1560 // Use the default sort order only if no sort order is specified. 1561 if (!TextUtils.isEmpty(sortOrder)) { 1562 orderBy = sortOrder; 1563 } 1564 1565 // Get the database and run the query. 1566 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 1567 Cursor c = 1568 queryBuilder.query( 1569 db, 1570 projection, 1571 params.getSelection(), 1572 params.getSelectionArgs(), 1573 null, 1574 null, 1575 orderBy); 1576 1577 // Tell the cursor what URI to watch, so it knows when its source data changes. 1578 c.setNotificationUri(getContext().getContentResolver(), uri); 1579 return c; 1580 } 1581 1582 @Override insert(Uri uri, ContentValues values)1583 public Uri insert(Uri uri, ContentValues values) { 1584 ensureInitialized(); 1585 switch (sUriMatcher.match(uri)) { 1586 case MATCH_CHANNEL: 1587 // Preview channels are not necessarily associated with TV input service. 1588 // Therefore, we fill a fake ID to meet not null restriction for preview channels. 1589 if (values.get(Channels.COLUMN_INPUT_ID) == null 1590 && TvContractCompat.PARAM_CHANNEL.equals( 1591 values.get(Channels.COLUMN_TYPE))) { 1592 values.put(Channels.COLUMN_INPUT_ID, EMPTY_STRING); 1593 } 1594 filterContentValues(values, sChannelProjectionMap); 1595 return insertChannel(uri, values); 1596 case MATCH_PROGRAM: 1597 filterContentValues(values, sProgramProjectionMap); 1598 return insertProgram(uri, values); 1599 case MATCH_WATCHED_PROGRAM: 1600 return insertWatchedProgram(uri, values); 1601 case MATCH_RECORDED_PROGRAM: 1602 filterContentValues(values, sRecordedProgramProjectionMap); 1603 return insertRecordedProgram(uri, values); 1604 case MATCH_PREVIEW_PROGRAM: 1605 filterContentValues(values, sPreviewProgramProjectionMap); 1606 return insertPreviewProgram(uri, values); 1607 case MATCH_WATCH_NEXT_PROGRAM: 1608 filterContentValues(values, sWatchNextProgramProjectionMap); 1609 return insertWatchNextProgram(uri, values); 1610 case MATCH_CHANNEL_ID: 1611 case MATCH_CHANNEL_ID_LOGO: 1612 case MATCH_PASSTHROUGH_ID: 1613 case MATCH_PROGRAM_ID: 1614 case MATCH_WATCHED_PROGRAM_ID: 1615 case MATCH_RECORDED_PROGRAM_ID: 1616 case MATCH_PREVIEW_PROGRAM_ID: 1617 throw new UnsupportedOperationException("Cannot insert into that URI: " + uri); 1618 default: 1619 throw new IllegalArgumentException("Unknown URI " + uri); 1620 } 1621 } 1622 insertChannel(Uri uri, ContentValues values)1623 private Uri insertChannel(Uri uri, ContentValues values) { 1624 if (TextUtils.equals( 1625 values.getAsString(Channels.COLUMN_TYPE), TvContractCompat.Channels.TYPE_PREVIEW)) { 1626 blockIllegalAccessFromBlockedPackage(); 1627 } 1628 // Mark the owner package of this channel. 1629 values.put(Channels.COLUMN_PACKAGE_NAME, getCallingPackage_()); 1630 blockIllegalAccessToChannelsSystemColumns(values); 1631 1632 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1633 long rowId = db.insert(CHANNELS_TABLE, null, values); 1634 if (rowId > 0) { 1635 Uri channelUri = TvContractCompat.buildChannelUri(rowId); 1636 notifyChange(channelUri); 1637 return channelUri; 1638 } 1639 1640 throw new SQLException("Failed to insert row into " + uri); 1641 } 1642 insertProgram(Uri uri, ContentValues values)1643 private Uri insertProgram(Uri uri, ContentValues values) { 1644 if (!callerHasAccessAllEpgDataPermission() 1645 || !values.containsKey(Programs.COLUMN_PACKAGE_NAME)) { 1646 // Mark the owner package of this program. System app with a proper permission may 1647 // change the owner of the program. 1648 values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); 1649 } 1650 1651 checkAndConvertGenre(values); 1652 checkAndConvertDeprecatedColumns(values); 1653 1654 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1655 long rowId = db.insert(PROGRAMS_TABLE, null, values); 1656 if (rowId > 0) { 1657 Uri programUri = TvContractCompat.buildProgramUri(rowId); 1658 notifyChange(programUri); 1659 return programUri; 1660 } 1661 1662 throw new SQLException("Failed to insert row into " + uri); 1663 } 1664 insertWatchedProgram(Uri uri, ContentValues values)1665 private Uri insertWatchedProgram(Uri uri, ContentValues values) { 1666 if (DEBUG) { 1667 Log.d(TAG, "insertWatchedProgram(uri=" + uri + ", values={" + values + "})"); 1668 } 1669 Long watchStartTime = values.getAsLong(WatchedPrograms.COLUMN_WATCH_START_TIME_UTC_MILLIS); 1670 Long watchEndTime = values.getAsLong(WatchedPrograms.COLUMN_WATCH_END_TIME_UTC_MILLIS); 1671 // The system sends only two kinds of watch events: 1672 // 1. The user tunes to a new channel. (COLUMN_WATCH_START_TIME_UTC_MILLIS) 1673 // 2. The user stops watching. (COLUMN_WATCH_END_TIME_UTC_MILLIS) 1674 if (watchStartTime != null && watchEndTime == null) { 1675 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1676 long rowId = db.insert(WATCHED_PROGRAMS_TABLE, null, values); 1677 if (rowId > 0) { 1678 return ContentUris.withAppendedId(WatchedPrograms.CONTENT_URI, rowId); 1679 } 1680 Log.w(TAG, "Failed to insert row for " + values + ". Channel does not exist."); 1681 return null; 1682 } else if (watchStartTime == null && watchEndTime != null) { 1683 return null; 1684 } 1685 // All the other cases are invalid. 1686 throw new IllegalArgumentException( 1687 "Only one of COLUMN_WATCH_START_TIME_UTC_MILLIS and" 1688 + " COLUMN_WATCH_END_TIME_UTC_MILLIS should be specified"); 1689 } 1690 insertRecordedProgram(Uri uri, ContentValues values)1691 private Uri insertRecordedProgram(Uri uri, ContentValues values) { 1692 // Mark the owner package of this program. 1693 values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); 1694 1695 checkAndConvertGenre(values); 1696 1697 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1698 long rowId = db.insert(RECORDED_PROGRAMS_TABLE, null, values); 1699 if (rowId > 0) { 1700 Uri recordedProgramUri = TvContractCompat.buildRecordedProgramUri(rowId); 1701 notifyChange(recordedProgramUri); 1702 return recordedProgramUri; 1703 } 1704 1705 throw new SQLException("Failed to insert row into " + uri); 1706 } 1707 insertPreviewProgram(Uri uri, ContentValues values)1708 private Uri insertPreviewProgram(Uri uri, ContentValues values) { 1709 if (!values.containsKey(PreviewPrograms.COLUMN_TYPE)) { 1710 throw new IllegalArgumentException( 1711 "Missing the required column: " + PreviewPrograms.COLUMN_TYPE); 1712 } 1713 blockIllegalAccessFromBlockedPackage(); 1714 // Mark the owner package of this program. 1715 values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); 1716 blockIllegalAccessToPreviewProgramsSystemColumns(values); 1717 1718 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1719 long rowId = db.insert(PREVIEW_PROGRAMS_TABLE, null, values); 1720 if (rowId > 0) { 1721 Uri previewProgramUri = TvContractCompat.buildPreviewProgramUri(rowId); 1722 notifyChange(previewProgramUri); 1723 return previewProgramUri; 1724 } 1725 1726 throw new SQLException("Failed to insert row into " + uri); 1727 } 1728 insertWatchNextProgram(Uri uri, ContentValues values)1729 private Uri insertWatchNextProgram(Uri uri, ContentValues values) { 1730 if (!values.containsKey(WatchNextPrograms.COLUMN_TYPE)) { 1731 throw new IllegalArgumentException( 1732 "Missing the required column: " + WatchNextPrograms.COLUMN_TYPE); 1733 } 1734 blockIllegalAccessFromBlockedPackage(); 1735 if (!callerHasAccessAllEpgDataPermission() 1736 || !values.containsKey(Programs.COLUMN_PACKAGE_NAME)) { 1737 // Mark the owner package of this program. System app with a proper permission may 1738 // change the owner of the program. 1739 values.put(Programs.COLUMN_PACKAGE_NAME, getCallingPackage_()); 1740 } 1741 blockIllegalAccessToPreviewProgramsSystemColumns(values); 1742 1743 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1744 long rowId = db.insert(WATCH_NEXT_PROGRAMS_TABLE, null, values); 1745 if (rowId > 0) { 1746 Uri watchNextProgramUri = TvContractCompat.buildWatchNextProgramUri(rowId); 1747 notifyChange(watchNextProgramUri); 1748 return watchNextProgramUri; 1749 } 1750 1751 throw new SQLException("Failed to insert row into " + uri); 1752 } 1753 1754 @Override delete(Uri uri, String selection, String[] selectionArgs)1755 public int delete(Uri uri, String selection, String[] selectionArgs) { 1756 SqlParams params = createSqlParams(OP_DELETE, uri, selection, selectionArgs); 1757 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1758 int count; 1759 switch (sUriMatcher.match(uri)) { 1760 case MATCH_CHANNEL_ID_LOGO: 1761 ContentValues values = new ContentValues(); 1762 values.putNull(CHANNELS_COLUMN_LOGO); 1763 count = 1764 db.update( 1765 params.getTables(), 1766 values, 1767 params.getSelection(), 1768 params.getSelectionArgs()); 1769 break; 1770 case MATCH_CHANNEL: 1771 case MATCH_PROGRAM: 1772 case MATCH_WATCHED_PROGRAM: 1773 case MATCH_RECORDED_PROGRAM: 1774 case MATCH_PREVIEW_PROGRAM: 1775 case MATCH_WATCH_NEXT_PROGRAM: 1776 case MATCH_CHANNEL_ID: 1777 case MATCH_PASSTHROUGH_ID: 1778 case MATCH_PROGRAM_ID: 1779 case MATCH_WATCHED_PROGRAM_ID: 1780 case MATCH_RECORDED_PROGRAM_ID: 1781 case MATCH_PREVIEW_PROGRAM_ID: 1782 case MATCH_WATCH_NEXT_PROGRAM_ID: 1783 count = 1784 db.delete( 1785 params.getTables(), 1786 params.getSelection(), 1787 params.getSelectionArgs()); 1788 break; 1789 default: 1790 throw new IllegalArgumentException("Unknown URI " + uri); 1791 } 1792 if (count > 0) { 1793 notifyChange(uri); 1794 } 1795 return count; 1796 } 1797 1798 @Override update(Uri uri, ContentValues values, String selection, String[] selectionArgs)1799 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 1800 SqlParams params = createSqlParams(OP_UPDATE, uri, selection, selectionArgs); 1801 blockIllegalAccessToIdAndPackageName(uri, values); 1802 boolean containImmutableColumn = false; 1803 if (params.getTables().equals(CHANNELS_TABLE)) { 1804 filterContentValues(values, sChannelProjectionMap); 1805 containImmutableColumn = disallowModifyChannelType(values, params); 1806 if (containImmutableColumn && sUriMatcher.match(uri) != MATCH_CHANNEL_ID) { 1807 Log.i(TAG, "Updating failed. Attempt to change immutable column for channels."); 1808 return 0; 1809 } 1810 blockIllegalAccessToChannelsSystemColumns(values); 1811 } else if (params.getTables().equals(PROGRAMS_TABLE)) { 1812 filterContentValues(values, sProgramProjectionMap); 1813 checkAndConvertGenre(values); 1814 checkAndConvertDeprecatedColumns(values); 1815 } else if (params.getTables().equals(RECORDED_PROGRAMS_TABLE)) { 1816 filterContentValues(values, sRecordedProgramProjectionMap); 1817 checkAndConvertGenre(values); 1818 } else if (params.getTables().equals(PREVIEW_PROGRAMS_TABLE)) { 1819 filterContentValues(values, sPreviewProgramProjectionMap); 1820 containImmutableColumn = disallowModifyChannelId(values, params); 1821 if (containImmutableColumn && PreviewPrograms.CONTENT_URI.equals(uri)) { 1822 Log.i( 1823 TAG, 1824 "Updating failed. Attempt to change unmodifiable column for " 1825 + "preview programs."); 1826 return 0; 1827 } 1828 blockIllegalAccessToPreviewProgramsSystemColumns(values); 1829 } else if (params.getTables().equals(WATCH_NEXT_PROGRAMS_TABLE)) { 1830 filterContentValues(values, sWatchNextProgramProjectionMap); 1831 blockIllegalAccessToPreviewProgramsSystemColumns(values); 1832 } 1833 if (values.size() == 0) { 1834 // All values may be filtered out, no need to update 1835 return 0; 1836 } 1837 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 1838 int count = 1839 db.update( 1840 params.getTables(), 1841 values, 1842 params.getSelection(), 1843 params.getSelectionArgs()); 1844 if (count > 0) { 1845 notifyChange(uri); 1846 } else if (containImmutableColumn) { 1847 Log.i( 1848 TAG, 1849 "Updating failed. The item may not exist or attempt to change " 1850 + "immutable column."); 1851 } 1852 return count; 1853 } 1854 ensureInitialized()1855 private synchronized void ensureInitialized() { 1856 if (!sInitialized) { 1857 // Database is not accessed before and the projection maps and the blocked package list 1858 // are not updated yet. Gets database here to make it initialized. 1859 mOpenHelper.getReadableDatabase(); 1860 } 1861 } 1862 initOnOpenIfNeeded(Context context, SQLiteDatabase db)1863 private static synchronized void initOnOpenIfNeeded(Context context, SQLiteDatabase db) { 1864 if (!sInitialized) { 1865 updateProjectionMap(db, CHANNELS_TABLE, sChannelProjectionMap); 1866 updateProjectionMap(db, PROGRAMS_TABLE, sProgramProjectionMap); 1867 updateProjectionMap(db, WATCHED_PROGRAMS_TABLE, sWatchedProgramProjectionMap); 1868 updateProjectionMap(db, RECORDED_PROGRAMS_TABLE, sRecordedProgramProjectionMap); 1869 updateProjectionMap(db, PREVIEW_PROGRAMS_TABLE, sPreviewProgramProjectionMap); 1870 updateProjectionMap(db, WATCH_NEXT_PROGRAMS_TABLE, sWatchNextProgramProjectionMap); 1871 sBlockedPackagesSharedPreference = 1872 PreferenceManager.getDefaultSharedPreferences(context); 1873 sBlockedPackages = new ConcurrentHashMap<>(); 1874 for (String packageName : 1875 sBlockedPackagesSharedPreference.getStringSet( 1876 SHARED_PREF_BLOCKED_PACKAGES_KEY, new HashSet<>())) { 1877 sBlockedPackages.put(packageName, true); 1878 } 1879 sInitialized = true; 1880 } 1881 } 1882 updateProjectionMap( SQLiteDatabase db, String tableName, Map<String, String> projectionMap)1883 private static void updateProjectionMap( 1884 SQLiteDatabase db, String tableName, Map<String, String> projectionMap) { 1885 try (Cursor cursor = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 0", null)) { 1886 for (String columnName : cursor.getColumnNames()) { 1887 if (!projectionMap.containsKey(columnName)) { 1888 projectionMap.put(columnName, tableName + '.' + columnName); 1889 } 1890 } 1891 } 1892 } 1893 createProjectionMapForQuery( String[] projection, Map<String, String> projectionMap)1894 private Map<String, String> createProjectionMapForQuery( 1895 String[] projection, Map<String, String> projectionMap) { 1896 if (projection == null) { 1897 return projectionMap; 1898 } 1899 Map<String, String> columnProjectionMap = new HashMap<>(); 1900 for (String columnName : projection) { 1901 // Value NULL will be provided if the requested column does not exist in the database. 1902 columnProjectionMap.put( 1903 columnName, projectionMap.getOrDefault(columnName, "NULL as " + columnName)); 1904 } 1905 return columnProjectionMap; 1906 } 1907 filterContentValues(ContentValues values, Map<String, String> projectionMap)1908 private void filterContentValues(ContentValues values, Map<String, String> projectionMap) { 1909 Iterator<String> iter = values.keySet().iterator(); 1910 while (iter.hasNext()) { 1911 String columnName = iter.next(); 1912 if (!projectionMap.containsKey(columnName)) { 1913 iter.remove(); 1914 } 1915 } 1916 } 1917 createSqlParams( String operation, Uri uri, String selection, String[] selectionArgs)1918 private SqlParams createSqlParams( 1919 String operation, Uri uri, String selection, String[] selectionArgs) { 1920 int match = sUriMatcher.match(uri); 1921 SqlParams params = new SqlParams(null, selection, selectionArgs); 1922 1923 // Control access to EPG data (excluding watched programs) when the caller doesn't have all 1924 // access. 1925 String prefix = match == MATCH_CHANNEL ? CHANNELS_TABLE + "." : ""; 1926 if (!callerHasAccessAllEpgDataPermission() 1927 && match != MATCH_WATCHED_PROGRAM 1928 && match != MATCH_WATCHED_PROGRAM_ID) { 1929 if (!TextUtils.isEmpty(selection)) { 1930 throw new SecurityException("Selection not allowed for " + uri); 1931 } 1932 // Limit the operation only to the data that the calling package owns except for when 1933 // the caller tries to read TV listings and has the appropriate permission. 1934 if (operation.equals(OP_QUERY) && callerHasReadTvListingsPermission()) { 1935 params.setWhere( 1936 prefix 1937 + BaseTvColumns.COLUMN_PACKAGE_NAME 1938 + "=? OR " 1939 + Channels.COLUMN_SEARCHABLE 1940 + "=?", 1941 getCallingPackage_(), 1942 "1"); 1943 } else { 1944 params.setWhere( 1945 prefix + BaseTvColumns.COLUMN_PACKAGE_NAME + "=?", getCallingPackage_()); 1946 } 1947 } 1948 String packageName = uri.getQueryParameter(PARAM_PACKAGE); 1949 if (packageName != null) { 1950 params.appendWhere(prefix + BaseTvColumns.COLUMN_PACKAGE_NAME + "=?", packageName); 1951 } 1952 1953 switch (match) { 1954 case MATCH_CHANNEL: 1955 String genre = uri.getQueryParameter(TvContractCompat.PARAM_CANONICAL_GENRE); 1956 if (genre == null) { 1957 params.setTables(CHANNELS_TABLE); 1958 } else { 1959 if (!operation.equals(OP_QUERY)) { 1960 throw new SecurityException( 1961 capitalize(operation) + " not allowed for " + uri); 1962 } 1963 if (!Genres.isCanonical(genre)) { 1964 throw new IllegalArgumentException("Not a canonical genre : " + genre); 1965 } 1966 params.setTables(CHANNELS_TABLE_INNER_JOIN_PROGRAMS_TABLE); 1967 String curTime = String.valueOf(System.currentTimeMillis()); 1968 params.appendWhere( 1969 "LIKE(?, " 1970 + Programs.COLUMN_CANONICAL_GENRE 1971 + ") AND " 1972 + Programs.COLUMN_START_TIME_UTC_MILLIS 1973 + "<=? AND " 1974 + Programs.COLUMN_END_TIME_UTC_MILLIS 1975 + ">=?", 1976 "%" + genre + "%", 1977 curTime, 1978 curTime); 1979 } 1980 String inputId = uri.getQueryParameter(TvContractCompat.PARAM_INPUT); 1981 if (inputId != null) { 1982 params.appendWhere(Channels.COLUMN_INPUT_ID + "=?", inputId); 1983 } 1984 boolean browsableOnly = 1985 uri.getBooleanQueryParameter(TvContractCompat.PARAM_BROWSABLE_ONLY, false); 1986 if (browsableOnly) { 1987 params.appendWhere(Channels.COLUMN_BROWSABLE + "=1"); 1988 } 1989 String preview = uri.getQueryParameter(PARAM_PREVIEW); 1990 if (preview != null) { 1991 String previewSelection = 1992 Channels.COLUMN_TYPE 1993 + (preview.equals(String.valueOf(true)) ? "=?" : "!=?"); 1994 params.appendWhere(previewSelection, Channels.TYPE_PREVIEW); 1995 } 1996 break; 1997 case MATCH_CHANNEL_ID: 1998 params.setTables(CHANNELS_TABLE); 1999 params.appendWhere(Channels._ID + "=?", uri.getLastPathSegment()); 2000 break; 2001 case MATCH_PROGRAM: 2002 params.setTables(PROGRAMS_TABLE); 2003 String paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL); 2004 if (paramChannelId != null) { 2005 String channelId = String.valueOf(Long.parseLong(paramChannelId)); 2006 params.appendWhere(Programs.COLUMN_CHANNEL_ID + "=?", channelId); 2007 } 2008 String paramStartTime = uri.getQueryParameter(TvContractCompat.PARAM_START_TIME); 2009 String paramEndTime = uri.getQueryParameter(TvContractCompat.PARAM_END_TIME); 2010 if (paramStartTime != null && paramEndTime != null) { 2011 String startTime = String.valueOf(Long.parseLong(paramStartTime)); 2012 String endTime = String.valueOf(Long.parseLong(paramEndTime)); 2013 params.appendWhere( 2014 Programs.COLUMN_START_TIME_UTC_MILLIS 2015 + "<=? AND " 2016 + Programs.COLUMN_END_TIME_UTC_MILLIS 2017 + ">=? AND ?<=?", 2018 endTime, 2019 startTime, 2020 startTime, 2021 endTime); 2022 } 2023 break; 2024 case MATCH_PROGRAM_ID: 2025 params.setTables(PROGRAMS_TABLE); 2026 params.appendWhere(Programs._ID + "=?", uri.getLastPathSegment()); 2027 break; 2028 case MATCH_WATCHED_PROGRAM: 2029 if (!callerHasAccessWatchedProgramsPermission()) { 2030 throw new SecurityException("Access not allowed for " + uri); 2031 } 2032 params.setTables(WATCHED_PROGRAMS_TABLE); 2033 params.appendWhere(WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + "=?", "1"); 2034 break; 2035 case MATCH_WATCHED_PROGRAM_ID: 2036 if (!callerHasAccessWatchedProgramsPermission()) { 2037 throw new SecurityException("Access not allowed for " + uri); 2038 } 2039 params.setTables(WATCHED_PROGRAMS_TABLE); 2040 params.appendWhere(WatchedPrograms._ID + "=?", uri.getLastPathSegment()); 2041 params.appendWhere(WATCHED_PROGRAMS_COLUMN_CONSOLIDATED + "=?", "1"); 2042 break; 2043 case MATCH_RECORDED_PROGRAM_ID: 2044 params.appendWhere(RecordedPrograms._ID + "=?", uri.getLastPathSegment()); 2045 // fall-through 2046 case MATCH_RECORDED_PROGRAM: 2047 params.setTables(RECORDED_PROGRAMS_TABLE); 2048 paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL); 2049 if (paramChannelId != null) { 2050 String channelId = String.valueOf(Long.parseLong(paramChannelId)); 2051 params.appendWhere(Programs.COLUMN_CHANNEL_ID + "=?", channelId); 2052 } 2053 break; 2054 case MATCH_PREVIEW_PROGRAM_ID: 2055 params.appendWhere(PreviewPrograms._ID + "=?", uri.getLastPathSegment()); 2056 // fall-through 2057 case MATCH_PREVIEW_PROGRAM: 2058 params.setTables(PREVIEW_PROGRAMS_TABLE); 2059 paramChannelId = uri.getQueryParameter(TvContractCompat.PARAM_CHANNEL); 2060 if (paramChannelId != null) { 2061 String channelId = String.valueOf(Long.parseLong(paramChannelId)); 2062 params.appendWhere(PreviewPrograms.COLUMN_CHANNEL_ID + "=?", channelId); 2063 } 2064 break; 2065 case MATCH_WATCH_NEXT_PROGRAM_ID: 2066 params.appendWhere(WatchNextPrograms._ID + "=?", uri.getLastPathSegment()); 2067 // fall-through 2068 case MATCH_WATCH_NEXT_PROGRAM: 2069 params.setTables(WATCH_NEXT_PROGRAMS_TABLE); 2070 break; 2071 case MATCH_CHANNEL_ID_LOGO: 2072 if (operation.equals(OP_DELETE)) { 2073 params.setTables(CHANNELS_TABLE); 2074 params.appendWhere(Channels._ID + "=?", uri.getPathSegments().get(1)); 2075 break; 2076 } 2077 // fall-through 2078 case MATCH_PASSTHROUGH_ID: 2079 throw new UnsupportedOperationException(operation + " not permmitted on " + uri); 2080 default: 2081 throw new IllegalArgumentException("Unknown URI " + uri); 2082 } 2083 return params; 2084 } 2085 capitalize(String str)2086 private static String capitalize(String str) { 2087 return Character.toUpperCase(str.charAt(0)) + str.substring(1); 2088 } 2089 2090 @SuppressLint("DefaultLocale") checkAndConvertGenre(ContentValues values)2091 private void checkAndConvertGenre(ContentValues values) { 2092 String canonicalGenres = values.getAsString(Programs.COLUMN_CANONICAL_GENRE); 2093 2094 if (!TextUtils.isEmpty(canonicalGenres)) { 2095 // Check if the canonical genres are valid. If not, clear them. 2096 String[] genres = Genres.decode(canonicalGenres); 2097 for (String genre : genres) { 2098 if (!Genres.isCanonical(genre)) { 2099 values.putNull(Programs.COLUMN_CANONICAL_GENRE); 2100 canonicalGenres = null; 2101 break; 2102 } 2103 } 2104 } 2105 2106 if (TextUtils.isEmpty(canonicalGenres)) { 2107 // If the canonical genre is not set, try to map the broadcast genre to the canonical 2108 // genre. 2109 String broadcastGenres = values.getAsString(Programs.COLUMN_BROADCAST_GENRE); 2110 if (!TextUtils.isEmpty(broadcastGenres)) { 2111 Set<String> genreSet = new HashSet<>(); 2112 String[] genres = Genres.decode(broadcastGenres); 2113 for (String genre : genres) { 2114 String canonicalGenre = sGenreMap.get(genre.toUpperCase()); 2115 if (Genres.isCanonical(canonicalGenre)) { 2116 genreSet.add(canonicalGenre); 2117 } 2118 } 2119 if (genreSet.size() > 0) { 2120 values.put( 2121 Programs.COLUMN_CANONICAL_GENRE, 2122 Genres.encode(genreSet.toArray(new String[genreSet.size()]))); 2123 } 2124 } 2125 } 2126 } 2127 checkAndConvertDeprecatedColumns(ContentValues values)2128 private void checkAndConvertDeprecatedColumns(ContentValues values) { 2129 if (values.containsKey(Programs.COLUMN_SEASON_NUMBER)) { 2130 if (!values.containsKey(Programs.COLUMN_SEASON_DISPLAY_NUMBER)) { 2131 values.put( 2132 Programs.COLUMN_SEASON_DISPLAY_NUMBER, 2133 values.getAsInteger(Programs.COLUMN_SEASON_NUMBER)); 2134 } 2135 values.remove(Programs.COLUMN_SEASON_NUMBER); 2136 } 2137 if (values.containsKey(Programs.COLUMN_EPISODE_NUMBER)) { 2138 if (!values.containsKey(Programs.COLUMN_EPISODE_DISPLAY_NUMBER)) { 2139 values.put( 2140 Programs.COLUMN_EPISODE_DISPLAY_NUMBER, 2141 values.getAsInteger(Programs.COLUMN_EPISODE_NUMBER)); 2142 } 2143 values.remove(Programs.COLUMN_EPISODE_NUMBER); 2144 } 2145 } 2146 2147 // We might have more than one thread trying to make its way through applyBatch() so the 2148 // notification coalescing needs to be thread-local to work correctly. 2149 private final ThreadLocal<Set<Uri>> mTLBatchNotifications = new ThreadLocal<>(); 2150 getBatchNotificationsSet()2151 private Set<Uri> getBatchNotificationsSet() { 2152 return mTLBatchNotifications.get(); 2153 } 2154 setBatchNotificationsSet(Set<Uri> batchNotifications)2155 private void setBatchNotificationsSet(Set<Uri> batchNotifications) { 2156 mTLBatchNotifications.set(batchNotifications); 2157 } 2158 2159 @Override applyBatch(ArrayList<ContentProviderOperation> operations)2160 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2161 throws OperationApplicationException { 2162 setBatchNotificationsSet(new HashSet<Uri>()); 2163 Context context = getContext(); 2164 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 2165 db.beginTransaction(); 2166 try { 2167 ContentProviderResult[] results = super.applyBatch(operations); 2168 db.setTransactionSuccessful(); 2169 return results; 2170 } finally { 2171 db.endTransaction(); 2172 final Set<Uri> notifications = getBatchNotificationsSet(); 2173 setBatchNotificationsSet(null); 2174 for (final Uri uri : notifications) { 2175 context.getContentResolver().notifyChange(uri, null); 2176 } 2177 } 2178 } 2179 2180 @Override bulkInsert(Uri uri, ContentValues[] values)2181 public int bulkInsert(Uri uri, ContentValues[] values) { 2182 setBatchNotificationsSet(new HashSet<Uri>()); 2183 Context context = getContext(); 2184 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 2185 db.beginTransaction(); 2186 try { 2187 int result = super.bulkInsert(uri, values); 2188 db.setTransactionSuccessful(); 2189 return result; 2190 } finally { 2191 db.endTransaction(); 2192 final Set<Uri> notifications = getBatchNotificationsSet(); 2193 setBatchNotificationsSet(null); 2194 for (final Uri notificationUri : notifications) { 2195 context.getContentResolver().notifyChange(notificationUri, null); 2196 } 2197 } 2198 } 2199 notifyChange(Uri uri)2200 private void notifyChange(Uri uri) { 2201 final Set<Uri> batchNotifications = getBatchNotificationsSet(); 2202 if (batchNotifications != null) { 2203 batchNotifications.add(uri); 2204 } else { 2205 getContext().getContentResolver().notifyChange(uri, null); 2206 } 2207 } 2208 callerHasReadTvListingsPermission()2209 private boolean callerHasReadTvListingsPermission() { 2210 return getContext().checkCallingOrSelfPermission(PERMISSION_READ_TV_LISTINGS) 2211 == PackageManager.PERMISSION_GRANTED; 2212 } 2213 callerHasAccessAllEpgDataPermission()2214 private boolean callerHasAccessAllEpgDataPermission() { 2215 return getContext().checkCallingOrSelfPermission(PERMISSION_ACCESS_ALL_EPG_DATA) 2216 == PackageManager.PERMISSION_GRANTED; 2217 } 2218 callerHasAccessWatchedProgramsPermission()2219 private boolean callerHasAccessWatchedProgramsPermission() { 2220 return getContext().checkCallingOrSelfPermission(PERMISSION_ACCESS_WATCHED_PROGRAMS) 2221 == PackageManager.PERMISSION_GRANTED; 2222 } 2223 callerHasModifyParentalControlsPermission()2224 private boolean callerHasModifyParentalControlsPermission() { 2225 return getContext() 2226 .checkCallingOrSelfPermission( 2227 android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) 2228 == PackageManager.PERMISSION_GRANTED; 2229 } 2230 blockIllegalAccessToIdAndPackageName(Uri uri, ContentValues values)2231 private void blockIllegalAccessToIdAndPackageName(Uri uri, ContentValues values) { 2232 if (values.containsKey(BaseColumns._ID)) { 2233 int match = sUriMatcher.match(uri); 2234 switch (match) { 2235 case MATCH_CHANNEL_ID: 2236 case MATCH_PROGRAM_ID: 2237 case MATCH_PREVIEW_PROGRAM_ID: 2238 case MATCH_RECORDED_PROGRAM_ID: 2239 case MATCH_WATCH_NEXT_PROGRAM_ID: 2240 case MATCH_WATCHED_PROGRAM_ID: 2241 if (TextUtils.equals( 2242 values.getAsString(BaseColumns._ID), uri.getLastPathSegment())) { 2243 break; 2244 } 2245 // fall through 2246 default: 2247 throw new IllegalArgumentException("Not allowed to change ID."); 2248 } 2249 } 2250 if (values.containsKey(BaseTvColumns.COLUMN_PACKAGE_NAME) 2251 && !callerHasAccessAllEpgDataPermission() 2252 && !TextUtils.equals( 2253 values.getAsString(BaseTvColumns.COLUMN_PACKAGE_NAME), 2254 getCallingPackage_())) { 2255 throw new SecurityException("Not allowed to change package name."); 2256 } 2257 } 2258 blockIllegalAccessToChannelsSystemColumns(ContentValues values)2259 private void blockIllegalAccessToChannelsSystemColumns(ContentValues values) { 2260 if (values.containsKey(Channels.COLUMN_LOCKED) 2261 && !callerHasModifyParentalControlsPermission()) { 2262 throw new SecurityException("Not allowed to access Channels.COLUMN_LOCKED"); 2263 } 2264 Boolean hasAccessAllEpgDataPermission = null; 2265 if (values.containsKey(Channels.COLUMN_BROWSABLE)) { 2266 hasAccessAllEpgDataPermission = callerHasAccessAllEpgDataPermission(); 2267 if (!hasAccessAllEpgDataPermission) { 2268 throw new SecurityException("Not allowed to access Channels.COLUMN_BROWSABLE"); 2269 } 2270 } 2271 } 2272 blockIllegalAccessToPreviewProgramsSystemColumns(ContentValues values)2273 private void blockIllegalAccessToPreviewProgramsSystemColumns(ContentValues values) { 2274 if (values.containsKey(PreviewPrograms.COLUMN_BROWSABLE) 2275 && !callerHasAccessAllEpgDataPermission()) { 2276 throw new SecurityException("Not allowed to access Programs.COLUMN_BROWSABLE"); 2277 } 2278 } 2279 blockIllegalAccessFromBlockedPackage()2280 private void blockIllegalAccessFromBlockedPackage() { 2281 String callingPackageName = getCallingPackage_(); 2282 if (sBlockedPackages.containsKey(callingPackageName)) { 2283 throw new SecurityException( 2284 "Not allowed to access " 2285 + TvContractCompat.AUTHORITY 2286 + ", " 2287 + callingPackageName 2288 + " is blocked"); 2289 } 2290 } 2291 disallowModifyChannelType(ContentValues values, SqlParams params)2292 private boolean disallowModifyChannelType(ContentValues values, SqlParams params) { 2293 if (values.containsKey(Channels.COLUMN_TYPE)) { 2294 params.appendWhere( 2295 Channels.COLUMN_TYPE + "=?", values.getAsString(Channels.COLUMN_TYPE)); 2296 return true; 2297 } 2298 return false; 2299 } 2300 disallowModifyChannelId(ContentValues values, SqlParams params)2301 private boolean disallowModifyChannelId(ContentValues values, SqlParams params) { 2302 if (values.containsKey(PreviewPrograms.COLUMN_CHANNEL_ID)) { 2303 params.appendWhere( 2304 PreviewPrograms.COLUMN_CHANNEL_ID + "=?", 2305 values.getAsString(PreviewPrograms.COLUMN_CHANNEL_ID)); 2306 return true; 2307 } 2308 return false; 2309 } 2310 2311 @Override openFile(Uri uri, String mode)2312 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 2313 switch (sUriMatcher.match(uri)) { 2314 case MATCH_CHANNEL_ID_LOGO: 2315 return openLogoFile(uri, mode); 2316 default: 2317 throw new FileNotFoundException(uri.toString()); 2318 } 2319 } 2320 openLogoFile(Uri uri, String mode)2321 private ParcelFileDescriptor openLogoFile(Uri uri, String mode) throws FileNotFoundException { 2322 long channelId = Long.parseLong(uri.getPathSegments().get(1)); 2323 2324 SqlParams params = 2325 new SqlParams(CHANNELS_TABLE, Channels._ID + "=?", String.valueOf(channelId)); 2326 if (!callerHasAccessAllEpgDataPermission()) { 2327 if (callerHasReadTvListingsPermission()) { 2328 params.appendWhere( 2329 Channels.COLUMN_PACKAGE_NAME + "=? OR " + Channels.COLUMN_SEARCHABLE + "=?", 2330 getCallingPackage_(), 2331 "1"); 2332 } else { 2333 params.appendWhere(Channels.COLUMN_PACKAGE_NAME + "=?", getCallingPackage_()); 2334 } 2335 } 2336 2337 SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); 2338 queryBuilder.setTables(params.getTables()); 2339 2340 // We don't write the database here. 2341 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 2342 if (mode.equals("r")) { 2343 String sql = 2344 queryBuilder.buildQuery( 2345 new String[] {CHANNELS_COLUMN_LOGO}, 2346 params.getSelection(), 2347 null, 2348 null, 2349 null, 2350 null); 2351 ParcelFileDescriptor fd = 2352 DatabaseUtils.blobFileDescriptorForQuery(db, sql, params.getSelectionArgs()); 2353 if (fd == null) { 2354 throw new FileNotFoundException(uri.toString()); 2355 } 2356 return fd; 2357 } else { 2358 try (Cursor cursor = 2359 queryBuilder.query( 2360 db, 2361 new String[] {Channels._ID}, 2362 params.getSelection(), 2363 params.getSelectionArgs(), 2364 null, 2365 null, 2366 null)) { 2367 if (cursor.getCount() < 1) { 2368 // Fails early if corresponding channel does not exist. 2369 // PipeMonitor may still fail to update DB later. 2370 throw new FileNotFoundException(uri.toString()); 2371 } 2372 } 2373 2374 try { 2375 ParcelFileDescriptor[] pipeFds = ParcelFileDescriptor.createPipe(); 2376 PipeMonitor pipeMonitor = new PipeMonitor(pipeFds[0], channelId, params); 2377 pipeMonitor.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 2378 return pipeFds[1]; 2379 } catch (IOException ioe) { 2380 FileNotFoundException fne = new FileNotFoundException(uri.toString()); 2381 fne.initCause(ioe); 2382 throw fne; 2383 } 2384 } 2385 } 2386 2387 /** 2388 * Validates the sort order based on the given field set. 2389 * 2390 * @throws IllegalArgumentException if there is any unknown field. 2391 */ 2392 @SuppressLint("DefaultLocale") validateSortOrder(String sortOrder, Set<String> possibleFields)2393 private static void validateSortOrder(String sortOrder, Set<String> possibleFields) { 2394 if (TextUtils.isEmpty(sortOrder) || possibleFields.isEmpty()) { 2395 return; 2396 } 2397 String[] orders = sortOrder.split(","); 2398 for (String order : orders) { 2399 String field = 2400 order.replaceAll("\\s+", " ") 2401 .trim() 2402 .toLowerCase() 2403 .replace(" asc", "") 2404 .replace(" desc", ""); 2405 if (!possibleFields.contains(field)) { 2406 throw new IllegalArgumentException("Illegal field in sort order " + order); 2407 } 2408 } 2409 } 2410 2411 private class PipeMonitor extends AsyncTask<Void, Void, Void> { 2412 private final ParcelFileDescriptor mPfd; 2413 private final long mChannelId; 2414 private final SqlParams mParams; 2415 PipeMonitor(ParcelFileDescriptor pfd, long channelId, SqlParams params)2416 private PipeMonitor(ParcelFileDescriptor pfd, long channelId, SqlParams params) { 2417 mPfd = pfd; 2418 mChannelId = channelId; 2419 mParams = params; 2420 } 2421 2422 @Override doInBackground(Void... params)2423 protected Void doInBackground(Void... params) { 2424 int count = 0; 2425 try (AutoCloseInputStream is = new AutoCloseInputStream(mPfd); 2426 ByteArrayOutputStream baos = new ByteArrayOutputStream()) { 2427 Bitmap bitmap = BitmapFactory.decodeStream(is); 2428 if (bitmap == null) { 2429 Log.e(TAG, "Failed to decode logo image for channel ID " + mChannelId); 2430 return null; 2431 } 2432 2433 float scaleFactor = 2434 Math.min( 2435 1f, 2436 ((float) MAX_LOGO_IMAGE_SIZE) 2437 / Math.max(bitmap.getWidth(), bitmap.getHeight())); 2438 if (scaleFactor < 1f) { 2439 bitmap = 2440 Bitmap.createScaledBitmap( 2441 bitmap, 2442 (int) (bitmap.getWidth() * scaleFactor), 2443 (int) (bitmap.getHeight() * scaleFactor), 2444 false); 2445 } 2446 bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); 2447 byte[] bytes = baos.toByteArray(); 2448 2449 ContentValues values = new ContentValues(); 2450 values.put(CHANNELS_COLUMN_LOGO, bytes); 2451 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 2452 count = 2453 db.update( 2454 mParams.getTables(), 2455 values, 2456 mParams.getSelection(), 2457 mParams.getSelectionArgs()); 2458 if (count > 0) { 2459 Uri uri = TvContractCompat.buildChannelLogoUri(mChannelId); 2460 notifyChange(uri); 2461 } 2462 } catch (IOException e) { 2463 Log.e(TAG, "Failed to write logo for channel ID " + mChannelId, e); 2464 2465 } finally { 2466 if (count == 0) { 2467 try { 2468 mPfd.closeWithError("Failed to write logo for channel ID " + mChannelId); 2469 } catch (IOException ioe) { 2470 Log.e(TAG, "Failed to close pipe", ioe); 2471 } 2472 } 2473 } 2474 return null; 2475 } 2476 } 2477 2478 /** 2479 * Column definitions for the TV programs that the user watched. Applications do not have access 2480 * to this table. 2481 * 2482 * <p> 2483 * 2484 * <p>By default, the query results will be sorted by {@link 2485 * WatchedPrograms#COLUMN_WATCH_START_TIME_UTC_MILLIS} in descending order. 2486 * 2487 * @hide 2488 */ 2489 public static final class WatchedPrograms implements BaseTvColumns { 2490 2491 /** The content:// style URI for this table. */ 2492 public static final Uri CONTENT_URI = 2493 Uri.parse("content://" + TvContract.AUTHORITY + "/watched_program"); 2494 2495 /** The MIME type of a directory of watched programs. */ 2496 public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watched_program"; 2497 2498 /** The MIME type of a single item in this table. */ 2499 public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watched_program"; 2500 2501 /** 2502 * The UTC time that the user started watching this TV program, in milliseconds since the 2503 * epoch. 2504 * 2505 * <p> 2506 * 2507 * <p>Type: INTEGER (long) 2508 */ 2509 public static final String COLUMN_WATCH_START_TIME_UTC_MILLIS = 2510 "watch_start_time_utc_millis"; 2511 2512 /** 2513 * The UTC time that the user stopped watching this TV program, in milliseconds since the 2514 * epoch. 2515 * 2516 * <p> 2517 * 2518 * <p>Type: INTEGER (long) 2519 */ 2520 public static final String COLUMN_WATCH_END_TIME_UTC_MILLIS = "watch_end_time_utc_millis"; 2521 2522 /** 2523 * The ID of the TV channel that provides this TV program. 2524 * 2525 * <p> 2526 * 2527 * <p>This is a required field. 2528 * 2529 * <p> 2530 * 2531 * <p>Type: INTEGER (long) 2532 */ 2533 public static final String COLUMN_CHANNEL_ID = "channel_id"; 2534 2535 /** 2536 * The title of this TV program. 2537 * 2538 * <p> 2539 * 2540 * <p>Type: TEXT 2541 */ 2542 public static final String COLUMN_TITLE = "title"; 2543 2544 /** 2545 * The start time of this TV program, in milliseconds since the epoch. 2546 * 2547 * <p> 2548 * 2549 * <p>Type: INTEGER (long) 2550 */ 2551 public static final String COLUMN_START_TIME_UTC_MILLIS = "start_time_utc_millis"; 2552 2553 /** 2554 * The end time of this TV program, in milliseconds since the epoch. 2555 * 2556 * <p> 2557 * 2558 * <p>Type: INTEGER (long) 2559 */ 2560 public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis"; 2561 2562 /** 2563 * The description of this TV program. 2564 * 2565 * <p> 2566 * 2567 * <p>Type: TEXT 2568 */ 2569 public static final String COLUMN_DESCRIPTION = "description"; 2570 2571 /** 2572 * Extra parameters given to {@link TvInputService.Session#tune(Uri, android.os.Bundle) 2573 * TvInputService.Session.tune(Uri, android.os.Bundle)} when tuning to the channel that 2574 * provides this TV program. (Used internally.) 2575 * 2576 * <p> 2577 * 2578 * <p>This column contains an encoded string that represents comma-separated key-value pairs 2579 * of the tune parameters. (Ex. "[key1]=[value1], [key2]=[value2]"). '%' is used as an 2580 * escape character for '%', '=', and ','. 2581 * 2582 * <p> 2583 * 2584 * <p>Type: TEXT 2585 */ 2586 public static final String COLUMN_INTERNAL_TUNE_PARAMS = "tune_params"; 2587 2588 /** 2589 * The session token of this TV program. (Used internally.) 2590 * 2591 * <p> 2592 * 2593 * <p>This contains a String representation of {@link IBinder} for {@link 2594 * TvInputService.Session} that provides the current TV program. It is used internally to 2595 * distinguish watched programs entries from different TV input sessions. 2596 * 2597 * <p> 2598 * 2599 * <p>Type: TEXT 2600 */ 2601 public static final String COLUMN_INTERNAL_SESSION_TOKEN = "session_token"; 2602 WatchedPrograms()2603 private WatchedPrograms() {} 2604 } 2605 } 2606