Home | History | Annotate | Download | only in tuner
      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 {
     89         void onTunerPreferencesChanged();
     90     }
     91 
     92     /**
     93      * Initializes the USB tuner preferences.
     94      */
     95     @MainThread
     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      */
    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      */
    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
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    324     private static SharedPreferences getSharedPreferences(Context context) {
    325         return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
    326     }
    327 
    328     private static synchronized void setPreference(Context context, String key, String value) {
    329         sPreferenceValues.putString(key, value);
    330         savePreference(context, key, value);
    331     }
    332 
    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 
    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 
    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 
    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;
    370         private LoadPreferencesTask(Context context) {
    371             mContext = context;
    372         }
    373 
    374         @Override
    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
    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 }