• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.GuardedBy;
29 import android.support.annotation.IntDef;
30 import android.support.annotation.MainThread;
31 
32 import com.android.tv.common.SoftPreconditions;
33 import com.android.tv.tuner.TunerPreferenceProvider.Preferences;
34 import com.android.tv.tuner.util.TisConfiguration;
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 
38 /**
39  * A helper class for the USB tuner preferences.
40  */
41 public class TunerPreferences {
42     private static final String TAG = "TunerPreferences";
43 
44     private static final String PREFS_KEY_CHANNEL_DATA_VERSION = "channel_data_version";
45     private static final String PREFS_KEY_SCANNED_CHANNEL_COUNT = "scanned_channel_count";
46     private static final String PREFS_KEY_LAST_POSTAL_CODE = "last_postal_code";
47     private static final String PREFS_KEY_SCAN_DONE = "scan_done";
48     private static final String PREFS_KEY_LAUNCH_SETUP = "launch_setup";
49     private static final String PREFS_KEY_STORE_TS_STREAM = "store_ts_stream";
50     private static final String PREFS_KEY_TRICKPLAY_SETTING = "trickplay_setting";
51     private static final String PREFS_KEY_TRICKPLAY_EXPIRED_MS = "trickplay_expired_ms";
52 
53     private static final String SHARED_PREFS_NAME = "com.android.tv.tuner.preferences";
54 
55     public static final int CHANNEL_DATA_VERSION_NOT_SET = -1;
56 
57     @IntDef({TRICKPLAY_SETTING_NOT_SET, TRICKPLAY_SETTING_DISABLED, TRICKPLAY_SETTING_ENABLED})
58     @Retention(RetentionPolicy.SOURCE)
59     public @interface TrickplaySetting {
60     }
61 
62     /**
63      * Trickplay setting is not changed by a user. Trickplay will be enabled in this case.
64      */
65     public static final int TRICKPLAY_SETTING_NOT_SET = -1;
66 
67     /**
68      * Trickplay setting is disabled.
69      */
70     public static final int TRICKPLAY_SETTING_DISABLED = 0;
71 
72     /**
73      * Trickplay setting is enabled.
74      */
75     public static final int TRICKPLAY_SETTING_ENABLED = 1;
76 
77     @GuardedBy("TunerPreferences.class")
78     private static final Bundle sPreferenceValues = new Bundle();
79     private static LoadPreferencesTask sLoadPreferencesTask;
80     private static ContentObserver sContentObserver;
81     private static TunerPreferencesChangedListener sPreferencesChangedListener = null;
82 
83     private static boolean sInitialized;
84 
85     /**
86      * Listeners for TunerPreferences change.
87      */
88     public interface TunerPreferencesChangedListener {
onTunerPreferencesChanged()89         void onTunerPreferencesChanged();
90     }
91 
92     /**
93      * Initializes the USB tuner preferences.
94      */
95     @MainThread
initialize(final Context context)96     public static void initialize(final Context context) {
97         if (sInitialized) {
98             return;
99         }
100         sInitialized = true;
101         if (useContentProvider(context)) {
102             loadPreferences(context);
103             sContentObserver = new ContentObserver(new Handler()) {
104                 @Override
105                 public void onChange(boolean selfChange) {
106                     loadPreferences(context);
107                 }
108             };
109             context.getContentResolver().registerContentObserver(
110                     TunerPreferenceProvider.Preferences.CONTENT_URI, true, sContentObserver);
111         } else {
112             new AsyncTask<Void, Void, Void>() {
113                 @Override
114                 protected Void doInBackground(Void... params) {
115                     getSharedPreferences(context);
116                     return null;
117                 }
118             }.execute();
119         }
120     }
121 
122     /**
123      * Releases the resources.
124      */
release(Context context)125     public static synchronized void release(Context context) {
126         if (useContentProvider(context) && sContentObserver != null) {
127             context.getContentResolver().unregisterContentObserver(sContentObserver);
128         }
129         setTunerPreferencesChangedListener(null);
130     }
131 
132     /**
133      * Sets the listener for TunerPreferences change.
134      */
setTunerPreferencesChangedListener( TunerPreferencesChangedListener listener)135     public static void setTunerPreferencesChangedListener(
136             TunerPreferencesChangedListener listener) {
137         sPreferencesChangedListener = listener;
138     }
139 
140     /**
141      * Loads the preferences from database.
142      * <p>
143      * This preferences is used across processes, so the preferences should be loaded again when the
144      * databases changes.
145      */
146     @MainThread
loadPreferences(Context context)147     public static void loadPreferences(Context context) {
148         if (sLoadPreferencesTask != null
149                 && sLoadPreferencesTask.getStatus() != AsyncTask.Status.FINISHED) {
150             sLoadPreferencesTask.cancel(true);
151         }
152         sLoadPreferencesTask = new LoadPreferencesTask(context);
153         sLoadPreferencesTask.execute();
154     }
155 
useContentProvider(Context context)156     private static boolean useContentProvider(Context context) {
157         // If TIS is a part of LC, it should use ContentProvider to resolve multiple process access.
158         return TisConfiguration.isPackagedWithLiveChannels(context);
159     }
160 
getChannelDataVersion(Context context)161     public static synchronized int getChannelDataVersion(Context context) {
162         SoftPreconditions.checkState(sInitialized);
163         if (useContentProvider(context)) {
164             return sPreferenceValues.getInt(PREFS_KEY_CHANNEL_DATA_VERSION,
165                     CHANNEL_DATA_VERSION_NOT_SET);
166         } else {
167             return getSharedPreferences(context)
168                     .getInt(TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION,
169                             CHANNEL_DATA_VERSION_NOT_SET);
170         }
171     }
172 
setChannelDataVersion(Context context, int version)173     public static synchronized void setChannelDataVersion(Context context, int version) {
174         if (useContentProvider(context)) {
175             setPreference(context, PREFS_KEY_CHANNEL_DATA_VERSION, version);
176         } else {
177             getSharedPreferences(context).edit()
178                     .putInt(TunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, version)
179                     .apply();
180         }
181     }
182 
getScannedChannelCount(Context context)183     public static synchronized int getScannedChannelCount(Context context) {
184         SoftPreconditions.checkState(sInitialized);
185         if (useContentProvider(context)) {
186             return sPreferenceValues.getInt(PREFS_KEY_SCANNED_CHANNEL_COUNT);
187         } else {
188             return getSharedPreferences(context)
189                     .getInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, 0);
190         }
191     }
192 
setScannedChannelCount(Context context, int channelCount)193     public static synchronized void setScannedChannelCount(Context context, int channelCount) {
194         if (useContentProvider(context)) {
195             setPreference(context, PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount);
196         } else {
197             getSharedPreferences(context).edit()
198                     .putInt(TunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount)
199                     .apply();
200         }
201     }
202 
getLastPostalCode(Context context)203     public static synchronized String getLastPostalCode(Context context) {
204         SoftPreconditions.checkState(sInitialized);
205         if (useContentProvider(context)) {
206             return sPreferenceValues.getString(PREFS_KEY_LAST_POSTAL_CODE);
207         } else {
208             return getSharedPreferences(context).getString(PREFS_KEY_LAST_POSTAL_CODE, null);
209         }
210     }
211 
setLastPostalCode(Context context, String postalCode)212     public static synchronized void setLastPostalCode(Context context, String postalCode) {
213         if (useContentProvider(context)) {
214             setPreference(context, PREFS_KEY_LAST_POSTAL_CODE, postalCode);
215         } else {
216             getSharedPreferences(context).edit()
217                     .putString(PREFS_KEY_LAST_POSTAL_CODE, postalCode).apply();
218         }
219     }
220 
isScanDone(Context context)221     public static synchronized boolean isScanDone(Context context) {
222         SoftPreconditions.checkState(sInitialized);
223         if (useContentProvider(context)) {
224             return sPreferenceValues.getBoolean(PREFS_KEY_SCAN_DONE);
225         } else {
226             return getSharedPreferences(context)
227                     .getBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, false);
228         }
229     }
230 
setScanDone(Context context)231     public static synchronized void setScanDone(Context context) {
232         if (useContentProvider(context)) {
233             setPreference(context, PREFS_KEY_SCAN_DONE, true);
234         } else {
235             getSharedPreferences(context).edit()
236                     .putBoolean(TunerPreferences.PREFS_KEY_SCAN_DONE, true)
237                     .apply();
238         }
239     }
240 
shouldShowSetupActivity(Context context)241     public static synchronized boolean shouldShowSetupActivity(Context context) {
242         SoftPreconditions.checkState(sInitialized);
243         if (useContentProvider(context)) {
244             return sPreferenceValues.getBoolean(PREFS_KEY_LAUNCH_SETUP);
245         } else {
246             return getSharedPreferences(context)
247                     .getBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, false);
248         }
249     }
250 
setShouldShowSetupActivity(Context context, boolean need)251     public static synchronized void setShouldShowSetupActivity(Context context, boolean need) {
252         if (useContentProvider(context)) {
253             setPreference(context, PREFS_KEY_LAUNCH_SETUP, need);
254         } else {
255             getSharedPreferences(context).edit()
256                     .putBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, need)
257                     .apply();
258         }
259     }
260 
getTrickplayExpiredMs(Context context)261     public static synchronized long getTrickplayExpiredMs(Context context) {
262         SoftPreconditions.checkState(sInitialized);
263         if (useContentProvider(context)) {
264             return sPreferenceValues.getLong(PREFS_KEY_TRICKPLAY_EXPIRED_MS, 0);
265         } else {
266             return getSharedPreferences(context)
267                     .getLong(TunerPreferences.PREFS_KEY_TRICKPLAY_EXPIRED_MS, 0);
268         }
269     }
270 
setTrickplayExpiredMs(Context context, long timeMs)271     public static synchronized void setTrickplayExpiredMs(Context context, long timeMs) {
272         if (useContentProvider(context)) {
273             setPreference(context, PREFS_KEY_TRICKPLAY_EXPIRED_MS, timeMs);
274         } else {
275             getSharedPreferences(context).edit()
276                     .putLong(TunerPreferences.PREFS_KEY_TRICKPLAY_EXPIRED_MS, timeMs)
277                     .apply();
278         }
279     }
280 
getTrickplaySetting(Context context)281     public static synchronized  @TrickplaySetting int getTrickplaySetting(Context context) {
282         SoftPreconditions.checkState(sInitialized);
283         if (useContentProvider(context)) {
284             return sPreferenceValues.getInt(PREFS_KEY_TRICKPLAY_SETTING, TRICKPLAY_SETTING_NOT_SET);
285         } else {
286             return getSharedPreferences(context)
287                 .getInt(TunerPreferences.PREFS_KEY_TRICKPLAY_SETTING, TRICKPLAY_SETTING_NOT_SET);
288         }
289     }
290 
setTrickplaySetting(Context context, @TrickplaySetting int trickplaySetting)291     public static synchronized void setTrickplaySetting(Context context,
292             @TrickplaySetting int trickplaySetting) {
293         SoftPreconditions.checkState(sInitialized);
294         SoftPreconditions.checkArgument(trickplaySetting != TRICKPLAY_SETTING_NOT_SET);
295         if (useContentProvider(context)) {
296             setPreference(context, PREFS_KEY_TRICKPLAY_SETTING, trickplaySetting);
297         } else {
298             getSharedPreferences(context).edit()
299                 .putInt(TunerPreferences.PREFS_KEY_TRICKPLAY_SETTING, trickplaySetting)
300                 .apply();
301         }
302     }
303 
getStoreTsStream(Context context)304     public static synchronized boolean getStoreTsStream(Context context) {
305         SoftPreconditions.checkState(sInitialized);
306         if (useContentProvider(context)) {
307             return sPreferenceValues.getBoolean(PREFS_KEY_STORE_TS_STREAM, false);
308         } else {
309             return getSharedPreferences(context)
310                     .getBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, false);
311         }
312     }
313 
setStoreTsStream(Context context, boolean shouldStore)314     public static synchronized void setStoreTsStream(Context context, boolean shouldStore) {
315         if (useContentProvider(context)) {
316             setPreference(context, PREFS_KEY_STORE_TS_STREAM, shouldStore);
317         } else {
318             getSharedPreferences(context).edit()
319                     .putBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, shouldStore)
320                     .apply();
321         }
322     }
323 
getSharedPreferences(Context context)324     private static SharedPreferences getSharedPreferences(Context context) {
325         return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
326     }
327 
setPreference(Context context, String key, String value)328     private static synchronized void setPreference(Context context, String key, String value) {
329         sPreferenceValues.putString(key, value);
330         savePreference(context, key, value);
331     }
332 
setPreference(Context context, String key, int value)333     private static synchronized void setPreference(Context context, String key, int value) {
334         sPreferenceValues.putInt(key, value);
335         savePreference(context, key, Integer.toString(value));
336     }
337 
setPreference(Context context, String key, long value)338     private static synchronized  void setPreference(Context context, String key, long value) {
339         sPreferenceValues.putLong(key, value);
340         savePreference(context, key, Long.toString(value));
341     }
342 
setPreference(Context context, String key, boolean value)343     private static synchronized void setPreference(Context context, String key, boolean value) {
344         sPreferenceValues.putBoolean(key, value);
345         savePreference(context, key, Boolean.toString(value));
346     }
347 
savePreference(final Context context, final String key, final String value)348     private static void savePreference(final Context context, final String key,
349             final String value) {
350         new AsyncTask<Void, Void, Void>() {
351             @Override
352             protected Void doInBackground(Void... params) {
353                 ContentResolver resolver = context.getContentResolver();
354                 ContentValues values = new ContentValues();
355                 values.put(Preferences.COLUMN_KEY, key);
356                 values.put(Preferences.COLUMN_VALUE, value);
357                 try {
358                     resolver.insert(Preferences.CONTENT_URI, values);
359                 } catch (Exception e) {
360                     SoftPreconditions.warn(TAG, "setPreference", "Error writing preference values",
361                             e);
362                 }
363                 return null;
364             }
365         }.execute();
366     }
367 
368     private static class LoadPreferencesTask extends AsyncTask<Void, Void, Bundle> {
369         private final Context mContext;
LoadPreferencesTask(Context context)370         private LoadPreferencesTask(Context context) {
371             mContext = context;
372         }
373 
374         @Override
doInBackground(Void... params)375         protected Bundle doInBackground(Void... params) {
376             Bundle bundle = new Bundle();
377             ContentResolver resolver = mContext.getContentResolver();
378             String[] projection = new String[] { Preferences.COLUMN_KEY, Preferences.COLUMN_VALUE };
379             try (Cursor cursor = resolver.query(Preferences.CONTENT_URI, projection, null, null,
380                     null)) {
381                 if (cursor != null) {
382                     while (!isCancelled() && cursor.moveToNext()) {
383                         String key = cursor.getString(0);
384                         String value = cursor.getString(1);
385                         switch (key) {
386                             case PREFS_KEY_TRICKPLAY_EXPIRED_MS:
387                                 bundle.putLong(key, Long.parseLong(value));
388                                 break;
389                             case PREFS_KEY_CHANNEL_DATA_VERSION:
390                             case PREFS_KEY_SCANNED_CHANNEL_COUNT:
391                             case PREFS_KEY_TRICKPLAY_SETTING:
392                                 try {
393                                     bundle.putInt(key, Integer.parseInt(value));
394                                 } catch (NumberFormatException e) {
395                                     // Does nothing.
396                                 }
397                                 break;
398                             case PREFS_KEY_SCAN_DONE:
399                             case PREFS_KEY_LAUNCH_SETUP:
400                             case PREFS_KEY_STORE_TS_STREAM:
401                                 bundle.putBoolean(key, Boolean.parseBoolean(value));
402                                 break;
403                             case PREFS_KEY_LAST_POSTAL_CODE:
404                                 bundle.putString(key, value);
405                                 break;
406                         }
407                     }
408                 }
409             } catch (Exception e) {
410                 SoftPreconditions.warn(TAG, "getPreference", "Error querying preference values", e);
411                 return null;
412             }
413             return bundle;
414         }
415 
416         @Override
onPostExecute(Bundle bundle)417         protected void onPostExecute(Bundle bundle) {
418             synchronized (TunerPreferences.class) {
419                 if (bundle != null) {
420                     sPreferenceValues.putAll(bundle);
421                 }
422             }
423             if (sPreferencesChangedListener != null) {
424                 sPreferencesChangedListener.onTunerPreferencesChanged();
425             }
426         }
427     }
428 }