Utils.java revision f8367f0d7dc6abc4876b52e04e2530c06464698e
1/* 2 * Copyright (C) 2014 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 17package com.android.tv.util; 18 19import android.content.ComponentName; 20import android.content.ContentUris; 21import android.content.Context; 22import android.content.Intent; 23import android.content.SharedPreferences; 24import android.content.pm.ActivityInfo; 25import android.content.pm.PackageManager; 26import android.content.pm.ResolveInfo; 27import android.database.Cursor; 28import android.media.tv.TvContract; 29import android.media.tv.TvInputInfo; 30import android.net.Uri; 31import android.preference.PreferenceManager; 32import android.text.TextUtils; 33import android.util.Base64; 34 35import com.android.tv.data.Channel; 36import com.android.tv.data.Program; 37import com.android.tv.data.StreamInfo; 38 39import java.util.List; 40 41/** 42 * A class that includes convenience methods for accessing TvProvider database. 43 */ 44public class Utils { 45 public static final String SERVICE_INTERFACE = "android.media.tv.TvInputService"; 46 public static final String EXTRA_SERVICE_NAME = "serviceName"; 47 public static final String EXTRA_KEYCODE = "keycode"; 48 49 public static final String CHANNEL_SORT_ORDER_BY_INPUT_NAME = 50 TvContract.Channels.COLUMN_PACKAGE_NAME + ", " 51 + TvContract.Channels.COLUMN_SERVICE_NAME; 52 53 public static final String CHANNEL_SORT_ORDER_BY_DISPLAY_NUMBER = 54 "CAST(" + TvContract.Channels.COLUMN_DISPLAY_NUMBER + " AS INTEGER), " 55 + "CAST(SUBSTR(LTRIM(" + TvContract.Channels.COLUMN_DISPLAY_NUMBER 56 + ",'0123456789'),2) AS INTEGER)"; 57 58 // preferences stored in the default preference. 59 private static final String PREF_KEY_LAST_SELECTED_TV_INPUT = "last_selected_tv_input"; 60 61 private static final String PREFIX_PREF_NAME = "com.android.tv."; 62 // preferences stored in the preference of a specific tv input. 63 private static final String PREF_KEY_LAST_WATCHED_CHANNEL_ID = "last_watched_channel_id"; 64 65 private static int VIDEO_SD_WIDTH = 704; 66 private static int VIDEO_SD_HEIGHT = 480; 67 private static int VIDEO_HD_WIDTH = 1280; 68 private static int VIDEO_HD_HEIGHT = 720; 69 private static int VIDEO_FULL_HD_WIDTH = 1920; 70 private static int VIDEO_FULL_HD_HEIGHT = 1080; 71 private static int VIDEO_ULTRA_HD_WIDTH = 2048; 72 private static int VIDEO_ULTRA_HD_HEIGHT = 1536; 73 74 // TODO: Remove this and add inputId into TvProvider. 75 public static String getInputIdForComponentName(ComponentName name) { 76 return name.flattenToShortString(); 77 } 78 79 public static Uri getChannelUri(long channelId) { 80 return ContentUris.withAppendedId(TvContract.Channels.CONTENT_URI, channelId); 81 } 82 83 public static String getInputIdForChannel(Context context, long channelId) { 84 if (channelId == Channel.INVALID_ID) { 85 return null; 86 } 87 Uri channelUri = ContentUris.withAppendedId(TvContract.Channels.CONTENT_URI, channelId); 88 return getInputIdForChannel(context, channelUri); 89 } 90 91 public static String getInputIdForChannel(Context context, Uri channelUri) { 92 String[] projection = { TvContract.Channels.COLUMN_PACKAGE_NAME, 93 TvContract.Channels.COLUMN_SERVICE_NAME }; 94 if (channelUri == null) { 95 return null; 96 } 97 Cursor cursor = context.getContentResolver().query( 98 channelUri, projection, null, null, null); 99 if (cursor == null) { 100 return null; 101 } 102 if (cursor.getCount() < 1) { 103 cursor.close(); 104 return null; 105 } 106 cursor.moveToNext(); 107 ComponentName componentName = new ComponentName(cursor.getString(0), cursor.getString(1)); 108 cursor.close(); 109 return getInputIdForComponentName(componentName); 110 } 111 112 public static void setLastWatchedChannelId(Context context, String inputId, long channelId) { 113 if (TextUtils.isEmpty(inputId)) { 114 throw new IllegalArgumentException("inputId cannot be empty"); 115 } 116 context.getSharedPreferences(getPreferenceName(inputId), Context.MODE_PRIVATE).edit() 117 .putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, channelId).apply(); 118 PreferenceManager.getDefaultSharedPreferences(context).edit() 119 .putString(PREF_KEY_LAST_SELECTED_TV_INPUT, inputId).apply(); 120 } 121 122 public static long getLastWatchedChannelId(Context context) { 123 String inputId = getLastSelectedInputId(context); 124 if (inputId == null) { 125 return Channel.INVALID_ID; 126 } 127 return getLastWatchedChannelId(context, inputId); 128 } 129 130 public static long getLastWatchedChannelId(Context context, String inputId) { 131 if (TextUtils.isEmpty(inputId)) { 132 throw new IllegalArgumentException("inputId cannot be empty"); 133 } 134 return context.getSharedPreferences(getPreferenceName(inputId), 135 Context.MODE_PRIVATE).getLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, Channel.INVALID_ID); 136 } 137 138 public static String getLastSelectedInputId(Context context) { 139 return PreferenceManager.getDefaultSharedPreferences(context) 140 .getString(PREF_KEY_LAST_SELECTED_TV_INPUT, null); 141 } 142 143 public static Program getCurrentProgram(Context context, Uri channelUri) { 144 if (channelUri == null) { 145 return null; 146 } 147 long time = System.currentTimeMillis(); 148 Uri uri = TvContract.buildProgramsUriForChannel(channelUri, time, time); 149 String[] projection = { 150 TvContract.Programs.COLUMN_TITLE, 151 TvContract.Programs.COLUMN_SHORT_DESCRIPTION, 152 TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS, 153 TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS }; 154 Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null); 155 String title = null; 156 String description = null; 157 long startTime = -1; 158 long endTime = -1; 159 if (cursor.moveToNext()) { 160 title = cursor.getString(0); 161 description = cursor.getString(1); 162 startTime = cursor.getLong(2); 163 endTime = cursor.getLong(3); 164 } 165 cursor.close(); 166 167 // TODO: Consider providing the entire data if needed. 168 return new Program.Builder() 169 .setTitle(title) 170 .setDescription(description) 171 .setStartTimeUtcMillis(startTime) 172 .setEndTimeUtcMillis(endTime).build(); 173 } 174 175 public static boolean hasChannel(Context context, TvInputInfo name) { 176 return hasChannel(context, name, true); 177 } 178 179 public static boolean hasChannel(Context context, TvInputInfo name, boolean browsableOnly) { 180 Uri uri = TvContract.buildChannelsUriForInput(name.getComponent(), browsableOnly); 181 String[] projection = { TvContract.Channels._ID }; 182 Cursor cursor = null; 183 try { 184 cursor = context.getContentResolver().query(uri, projection, null, null, null); 185 return cursor != null && cursor.getCount() > 0; 186 } finally { 187 if (cursor != null) { 188 cursor.close(); 189 } 190 } 191 } 192 193 public static SharedPreferences getSharedPreferencesOfDisplayNameForInput(Context context) { 194 return context.getSharedPreferences(TvSettings.PREFS_FILE, Context.MODE_PRIVATE); 195 } 196 197 public static String getDisplayNameForInput(Context context, TvInputInfo info) { 198 SharedPreferences preferences = getSharedPreferencesOfDisplayNameForInput(context); 199 PackageManager pm = context.getPackageManager(); 200 return preferences.getString(TvSettings.PREF_DISPLAY_INPUT_NAME + info.getId(), 201 info.loadLabel(pm).toString()); 202 } 203 204 public static boolean hasActivity(Context context, TvInputInfo input, String action) { 205 return getActivityInfo(context, input, action) != null; 206 } 207 208 public static int getVideoDefinitionLevelFromSize(int width, int height) { 209 if (width >= VIDEO_ULTRA_HD_WIDTH && height >= VIDEO_ULTRA_HD_HEIGHT) { 210 return StreamInfo.VIDEO_DEFINITION_LEVEL_ULTRA_HD; 211 } else if (width >= VIDEO_FULL_HD_WIDTH && height >= VIDEO_FULL_HD_HEIGHT) { 212 return StreamInfo.VIDEO_DEFINITION_LEVEL_FULL_HD; 213 } else if (width >= VIDEO_HD_WIDTH && height >= VIDEO_HD_HEIGHT) { 214 return StreamInfo.VIDEO_DEFINITION_LEVEL_HD; 215 } else if (width >= VIDEO_SD_WIDTH && height >= VIDEO_SD_HEIGHT) { 216 return StreamInfo.VIDEO_DEFINITION_LEVEL_SD; 217 } 218 return StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN; 219 } 220 221 public static String getVideoDefinitionLevelString(int videoFormat) { 222 switch (videoFormat) { 223 case StreamInfo.VIDEO_DEFINITION_LEVEL_ULTRA_HD: 224 return "UltraHD"; 225 case StreamInfo.VIDEO_DEFINITION_LEVEL_FULL_HD: 226 return "FullHD"; 227 case StreamInfo.VIDEO_DEFINITION_LEVEL_HD: 228 return "HD"; 229 case StreamInfo.VIDEO_DEFINITION_LEVEL_SD: 230 return "SD"; 231 } 232 return ""; 233 } 234 235 public static String getAudioChannelString(int channelCount) { 236 switch (channelCount) { 237 case 1: 238 return "MONO"; 239 case 2: 240 return "STEREO"; 241 case 6: 242 return "5.1"; 243 case 8: 244 return "7.1"; 245 } 246 return ""; 247 } 248 249 private static ActivityInfo getActivityInfo(Context context, TvInputInfo input, String action) { 250 if (input == null) { 251 return null; 252 } 253 254 List<ResolveInfo> infos = context.getPackageManager().queryIntentActivities( 255 new Intent(action), PackageManager.GET_ACTIVITIES); 256 if (infos == null) { 257 return null; 258 } 259 260 for (ResolveInfo info : infos) { 261 if (info.activityInfo.packageName.equals(input.getPackageName())) { 262 return info.activityInfo; 263 } 264 } 265 return null; 266 } 267 268 private static String getPreferenceName(String inputId) { 269 return PREFIX_PREF_NAME + Base64.encodeToString(inputId.getBytes(), Base64.URL_SAFE); 270 } 271} 272