1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.tv.tuner; 18 19 import android.content.ContentResolver; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.content.SharedPreferences; 23 import android.database.ContentObserver; 24 import android.database.Cursor; 25 import android.os.AsyncTask; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.support.annotation.MainThread; 29 30 import com.android.tv.common.SoftPreconditions; 31 import com.android.tv.tuner.TunerPreferenceProvider.Preferences; 32 import com.android.tv.tuner.util.TisConfiguration; 33 34 /** 35 * A helper class for the USB tuner preferences. 36 */ 37 public class TunerPreferences { 38 private static final String TAG = "TunerPreferences"; 39 40 private static final String PREFS_KEY_CHANNEL_DATA_VERSION = "channel_data_version"; 41 private static final String PREFS_KEY_SCANNED_CHANNEL_COUNT = "scanned_channel_count"; 42 private static final String PREFS_KEY_SCAN_DONE = "scan_done"; 43 private static final String PREFS_KEY_LAUNCH_SETUP = "launch_setup"; 44 private static final String PREFS_KEY_STORE_TS_STREAM = "store_ts_stream"; 45 46 private static final String SHARED_PREFS_NAME = "com.android.tv.tuner.preferences"; 47 48 public static final int CHANNEL_DATA_VERSION_NOT_SET = -1; 49 50 private static final Bundle sPreferenceValues = new Bundle(); 51 private static LoadPreferencesTask sLoadPreferencesTask; 52 private static ContentObserver sContentObserver; 53 54 private static boolean sInitialized; 55 56 /** 57 * Initializes the USB tuner preferences. 58 */ 59 @MainThread initialize(final Context context)60 public static void initialize(final Context context) { 61 if (sInitialized) { 62 return; 63 } 64 sInitialized = true; 65 if (useContentProvider(context)) { 66 loadPreferences(context); 67 sContentObserver = new ContentObserver(new Handler()) { 68 @Override 69 public void onChange(boolean selfChange) { 70 loadPreferences(context); 71 } 72 }; 73 context.getContentResolver().registerContentObserver( 74 TunerPreferenceProvider.Preferences.CONTENT_URI, true, sContentObserver); 75 } else { 76 new AsyncTask<Void, Void, Void>() { 77 @Override 78 protected Void doInBackground(Void... params) { 79 getSharedPreferences(context); 80 return null; 81 } 82 }.execute(); 83 } 84 } 85 86 /** 87 * Releases the resources. 88 */ 89 @MainThread release(Context context)90 public static void release(Context context) { 91 if (useContentProvider(context) && sContentObserver != null) { 92 context.getContentResolver().unregisterContentObserver(sContentObserver); 93 } 94 } 95 96 /** 97 * Loads the preferences from database. 98 * <p> 99 * This preferences is used across processes, so the preferences should be loaded again when the 100 * databases changes. 101 */ loadPreferences(Context context)102 public static synchronized void loadPreferences(Context context) { 103 if (sLoadPreferencesTask != null 104 && sLoadPreferencesTask.getStatus() != AsyncTask.Status.FINISHED) { 105 sLoadPreferencesTask.cancel(true); 106 } 107 sLoadPreferencesTask = new LoadPreferencesTask(context); 108 sLoadPreferencesTask.execute(); 109 } 110 useContentProvider(Context context)111 private static boolean useContentProvider(Context context) { 112 // If TIS is a part of LC, it should use ContentProvider to resolve multiple process access. 113 return TisConfiguration.isPackagedWithLiveChannels(context); 114 } 115 116 @MainThread getChannelDataVersion(Context context)117 public static int getChannelDataVersion(Context context) { 118 SoftPreconditions.checkState(sInitialized); 119 if (useContentProvider(context)) { 120 return sPreferenceValues.getInt(PREFS_KEY_CHANNEL_DATA_VERSION, 121 CHANNEL_DATA_VERSION_NOT_SET); 122 } else { 123 return getSharedPreferences(context) 124 .getInt(TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, 125 CHANNEL_DATA_VERSION_NOT_SET); 126 } 127 } 128 129 @MainThread setChannelDataVersion(Context context, int version)130 public static void setChannelDataVersion(Context context, int version) { 131 if (useContentProvider(context)) { 132 setPreference(context, PREFS_KEY_CHANNEL_DATA_VERSION, version); 133 } else { 134 getSharedPreferences(context).edit() 135 .putInt(TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, version) 136 .apply(); 137 } 138 } 139 140 @MainThread getScannedChannelCount(Context context)141 public static int getScannedChannelCount(Context context) { 142 SoftPreconditions.checkState(sInitialized); 143 if (useContentProvider(context)) { 144 return sPreferenceValues.getInt(PREFS_KEY_SCANNED_CHANNEL_COUNT); 145 } else { 146 return getSharedPreferences(context) 147 .getInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, 0); 148 } 149 } 150 151 @MainThread setScannedChannelCount(Context context, int channelCount)152 public static void setScannedChannelCount(Context context, int channelCount) { 153 if (useContentProvider(context)) { 154 setPreference(context, PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount); 155 } else { 156 getSharedPreferences(context).edit() 157 .putInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount) 158 .apply(); 159 } 160 } 161 162 @MainThread isScanDone(Context context)163 public static boolean isScanDone(Context context) { 164 SoftPreconditions.checkState(sInitialized); 165 if (useContentProvider(context)) { 166 return sPreferenceValues.getBoolean(PREFS_KEY_SCAN_DONE); 167 } else { 168 return getSharedPreferences(context) 169 .getBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, false); 170 } 171 } 172 173 @MainThread setScanDone(Context context)174 public static void setScanDone(Context context) { 175 if (useContentProvider(context)) { 176 setPreference(context, PREFS_KEY_SCAN_DONE, true); 177 } else { 178 getSharedPreferences(context).edit() 179 .putBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, true) 180 .apply(); 181 } 182 } 183 184 @MainThread shouldShowSetupActivity(Context context)185 public static boolean shouldShowSetupActivity(Context context) { 186 SoftPreconditions.checkState(sInitialized); 187 if (useContentProvider(context)) { 188 return sPreferenceValues.getBoolean(PREFS_KEY_LAUNCH_SETUP); 189 } else { 190 return getSharedPreferences(context) 191 .getBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, false); 192 } 193 } 194 195 @MainThread setShouldShowSetupActivity(Context context, boolean need)196 public static void setShouldShowSetupActivity(Context context, boolean need) { 197 if (useContentProvider(context)) { 198 setPreference(context, PREFS_KEY_LAUNCH_SETUP, need); 199 } else { 200 getSharedPreferences(context).edit() 201 .putBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, need) 202 .apply(); 203 } 204 } 205 206 @MainThread getStoreTsStream(Context context)207 public static boolean getStoreTsStream(Context context) { 208 SoftPreconditions.checkState(sInitialized); 209 if (useContentProvider(context)) { 210 return sPreferenceValues.getBoolean(PREFS_KEY_STORE_TS_STREAM, false); 211 } else { 212 return getSharedPreferences(context) 213 .getBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, false); 214 } 215 } 216 217 @MainThread setStoreTsStream(Context context, boolean shouldStore)218 public static void setStoreTsStream(Context context, boolean shouldStore) { 219 if (useContentProvider(context)) { 220 setPreference(context, PREFS_KEY_STORE_TS_STREAM, shouldStore); 221 } else { 222 getSharedPreferences(context).edit() 223 .putBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, shouldStore) 224 .apply(); 225 } 226 } 227 getSharedPreferences(Context context)228 private static SharedPreferences getSharedPreferences(Context context) { 229 return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE); 230 } 231 232 @MainThread setPreference(final Context context, final String key, final String value)233 private static void setPreference(final Context context, final String key, final String value) { 234 new AsyncTask<Void, Void, Void>() { 235 @Override 236 protected Void doInBackground(Void... params) { 237 ContentResolver resolver = context.getContentResolver(); 238 ContentValues values = new ContentValues(); 239 values.put(Preferences.COLUMN_KEY, key); 240 values.put(Preferences.COLUMN_VALUE, value); 241 try { 242 resolver.insert(Preferences.CONTENT_URI, values); 243 } catch (Exception e) { 244 SoftPreconditions.warn(TAG, "setPreference", "Error writing preference values", 245 e); 246 } 247 return null; 248 } 249 }.execute(); 250 } 251 252 @MainThread setPreference(Context context, String key, int value)253 private static void setPreference(Context context, String key, int value) { 254 sPreferenceValues.putInt(key, value); 255 setPreference(context, key, Integer.toString(value)); 256 } 257 258 @MainThread setPreference(Context context, String key, boolean value)259 private static void setPreference(Context context, String key, boolean value) { 260 sPreferenceValues.putBoolean(key, value); 261 setPreference(context, key, Boolean.toString(value)); 262 } 263 264 private static class LoadPreferencesTask extends AsyncTask<Void, Void, Bundle> { 265 private final Context mContext; LoadPreferencesTask(Context context)266 private LoadPreferencesTask(Context context) { 267 mContext = context; 268 } 269 270 @Override doInBackground(Void... params)271 protected Bundle doInBackground(Void... params) { 272 Bundle bundle = new Bundle(); 273 ContentResolver resolver = mContext.getContentResolver(); 274 String[] projection = new String[] { Preferences.COLUMN_KEY, Preferences.COLUMN_VALUE }; 275 try (Cursor cursor = resolver.query(Preferences.CONTENT_URI, projection, null, null, 276 null)) { 277 if (cursor != null) { 278 while (!isCancelled() && cursor.moveToNext()) { 279 String key = cursor.getString(0); 280 String value = cursor.getString(1); 281 switch (key) { 282 case PREFS_KEY_CHANNEL_DATA_VERSION: 283 case PREFS_KEY_SCANNED_CHANNEL_COUNT: 284 try { 285 bundle.putInt(key, Integer.parseInt(value)); 286 } catch (NumberFormatException e) { 287 // Does nothing. 288 } 289 break; 290 case PREFS_KEY_SCAN_DONE: 291 case PREFS_KEY_LAUNCH_SETUP: 292 case PREFS_KEY_STORE_TS_STREAM: 293 bundle.putBoolean(key, Boolean.parseBoolean(value)); 294 break; 295 } 296 } 297 } 298 } catch (Exception e) { 299 SoftPreconditions.warn(TAG, "getPreference", "Error querying preference values", e); 300 return null; 301 } 302 return bundle; 303 } 304 305 @Override onPostExecute(Bundle bundle)306 protected void onPostExecute(Bundle bundle) { 307 sPreferenceValues.putAll(bundle); 308 } 309 } 310 } 311