• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.car.radio.storage;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.hardware.radio.ProgramSelector;
22 import android.net.Uri;
23 import android.os.AsyncTask;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.Nullable;
27 import androidx.lifecycle.LiveData;
28 
29 import com.android.car.broadcastradio.support.Program;
30 import com.android.car.broadcastradio.support.platform.ProgramSelectorExt;
31 import com.android.car.radio.SkipMode;
32 import com.android.car.radio.bands.ProgramType;
33 import com.android.car.radio.util.Log;
34 
35 import java.util.List;
36 import java.util.Objects;
37 
38 /**
39  * Manages persistent storage for broadcast radio application.
40  */
41 public class RadioStorage {
42     private static final String TAG = "BcRadioApp.storage";
43     private static final String PREF_NAME = "RadioAppPrefs";
44 
45     private static final String PREF_KEY_RECENT_TYPE = "recentProgramType";
46     private static final String PREF_KEY_RECENT_PROGRAM_PREFIX = "recentProgram-";
47 
48     private static final String PREF_KEY_SKIP_MODE = "smartSeekMode";
49 
50     private static RadioStorage sInstance;
51 
52     private final SharedPreferences mPrefs;
53     private final RadioDatabase mDatabase;
54     private final LiveData<List<Program>> mFavorites;
55 
RadioStorage(Context context)56     private RadioStorage(Context context) {
57         mPrefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
58         mDatabase = RadioDatabase.buildInstance(context);
59 
60         mFavorites = mDatabase.getAllFavorites();
61     }
62 
63     /**
64      * Returns singleton instance of {@link RadioStorage}.
65      */
getInstance(Context context)66     public static @NonNull RadioStorage getInstance(Context context) {
67         if (sInstance != null) return sInstance;
68         synchronized (RadioStorage.class) {
69             if (sInstance != null) return sInstance;
70             sInstance = new RadioStorage(context.getApplicationContext());
71             return sInstance;
72         }
73     }
74 
75     /**
76      * Returns a list of all favorites added previously by the user.
77      */
78     @NonNull
getFavorites()79     public LiveData<List<Program>> getFavorites() {
80         return mFavorites;
81     }
82 
83     /**
84      * Checks, if a given program is favorite.
85      *
86      * @param favorites List of favorites.
87      * @param selector Program to check.
88      */
isFavorite(@onNull List<Program> favorites, @NonNull ProgramSelector selector)89     public static boolean isFavorite(@NonNull List<Program> favorites,
90             @NonNull ProgramSelector selector) {
91         return favorites.contains(new Program(selector, ""));
92     }
93 
94     /**
95      * Checks, if a given program is favorite.
96      *
97      * @param selector Program to check.
98      */
isFavorite(@onNull ProgramSelector selector)99     public boolean isFavorite(@NonNull ProgramSelector selector) {
100         List<Program> favorites = mFavorites.getValue();
101         if (favorites == null) {
102             Log.w(TAG, "Database is not ready yet");
103             return false;
104         }
105         return isFavorite(favorites, selector);
106     }
107 
108     private class AddFavoriteTask extends AsyncTask<Program, Void, Void> {
109         @Override
doInBackground(Program... programs)110         protected Void doInBackground(Program... programs) {
111             mDatabase.insertFavorite(programs[0]);
112             return null;
113         }
114     }
115 
116     private class RemoveFavoriteTask extends AsyncTask<ProgramSelector, Void, Void> {
117         @Override
doInBackground(ProgramSelector... selectors)118         protected Void doInBackground(ProgramSelector... selectors) {
119             mDatabase.removeFavorite(selectors[0]);
120             return null;
121         }
122     }
123 
124     /**
125      * Adds a new program to the favorites list.
126      *
127      * After the operation succeeds, the list is refreshed via live object returned
128      * from {@link #getFavorites}.
129      *
130      * @param favorite A program to add.
131      */
addFavorite(@onNull Program favorite)132     public void addFavorite(@NonNull Program favorite) {
133         new AddFavoriteTask().execute(Objects.requireNonNull(favorite));
134     }
135 
136     /**
137      * Removes a program from the favorites list.
138      *
139      * After the operation succeeds, the list is refreshed via live object returned
140      * from {@link #getFavorites}.
141      *
142      * @param favorite A program to remove.
143      */
removeFavorite(@onNull ProgramSelector favorite)144     public void removeFavorite(@NonNull ProgramSelector favorite) {
145         new RemoveFavoriteTask().execute(Objects.requireNonNull(favorite));
146     }
147 
148     /**
149      * Stores recently selected program so it can be recalled on next app launch.
150      *
151      * @param sel Program to store as recently selected.
152      */
setRecentlySelected(@onNull ProgramSelector sel)153     public void setRecentlySelected(@NonNull ProgramSelector sel) {
154         ProgramType pt = ProgramType.fromSelector(sel);
155         int ptid = pt == null ? 0 : pt.id;
156 
157         SharedPreferences.Editor editor = mPrefs.edit();
158         boolean hasChanges = false;
159 
160         String prefName = PREF_KEY_RECENT_PROGRAM_PREFIX + ptid;
161         Uri selUri = ProgramSelectorExt.toUri(sel);
162         if (selUri == null) return;
163         String selUriStr = selUri.toString();
164         if (!mPrefs.getString(prefName, "").equals(selUriStr)) {
165             editor.putString(prefName, selUriStr);
166             hasChanges = true;
167         }
168 
169         if (mPrefs.getInt(PREF_KEY_RECENT_TYPE, -1) != ptid) {
170             editor.putInt(PREF_KEY_RECENT_TYPE, ptid);
171             hasChanges = true;
172         }
173 
174         if (hasChanges) editor.apply();
175     }
176 
177     /**
178      * Retrieves recently selected program.
179      *
180      * This function can either retrieve the recently selected program for a specific
181      * {@link ProgramType} (band) or just the recently selected program in general.
182      *
183      * @param pt Program type to filter the result on, or {@code null} for general check
184      * @return Selector of the recent program or {@code null}, if there was none saved
185      */
getRecentlySelected(@ullable ProgramType pt)186     public @Nullable ProgramSelector getRecentlySelected(@Nullable ProgramType pt) {
187         int ptid = pt != null ? pt.id : mPrefs.getInt(PREF_KEY_RECENT_TYPE, -1);
188         if (ptid == -1) return null;
189 
190         String selUriStr = mPrefs.getString(PREF_KEY_RECENT_PROGRAM_PREFIX + ptid, "");
191         if (selUriStr.equals("")) return null;
192 
193         return ProgramSelectorExt.fromUri(Uri.parse(selUriStr));
194     }
195 
196     /**
197      * Stores the last {@link SkipMode} set.
198      */
setSkipMode(@onNull SkipMode mode)199     public void setSkipMode(@NonNull SkipMode mode) {
200         int value = mode.ordinal();
201         SharedPreferences.Editor editor = mPrefs.edit();
202 
203         if (mPrefs.getInt(PREF_KEY_SKIP_MODE,
204                 SkipMode.DEFAULT_MODE.ordinal()) != value) {
205             editor.putInt(PREF_KEY_SKIP_MODE, value);
206             editor.apply();
207         }
208     }
209 
210     /**
211      * Gets the last {@link SkipMode} set.
212      */
213     @NonNull
getSkipMode()214     public SkipMode getSkipMode() {
215         int value = mPrefs.getInt(PREF_KEY_SKIP_MODE, SkipMode.DEFAULT_MODE.ordinal());
216         SkipMode mode = SkipMode.valueOf(value);
217         if (mode == null) {
218             Log.e(TAG, "getSkipMode(): invalid pref value " + value + "; returning "
219                     + SkipMode.DEFAULT_MODE + " instead");
220             mode = SkipMode.DEFAULT_MODE;
221         }
222         return mode;
223     }
224 }
225