1 /*
2  * Copyright 2019 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.media.testmediaapp.prefs;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
22 
23 import androidx.preference.PreferenceManager;
24 
25 import com.android.car.media.testmediaapp.prefs.TmaEnumPrefs.TmaAccountType;
26 import com.android.car.media.testmediaapp.prefs.TmaEnumPrefs.TmaBrowseNodeType;
27 import com.android.car.media.testmediaapp.prefs.TmaEnumPrefs.TmaLoginEventOrder;
28 import com.android.car.media.testmediaapp.prefs.TmaEnumPrefs.TmaReplyDelay;
29 
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.Objects;
33 
34 
35 /** Singleton class to access the application's preferences. */
36 public class TmaPrefs {
37 
38     private static TmaPrefs sPrefs;
39 
40     public final PrefEntry<TmaAccountType> mAccountType;
41     public final PrefEntry<TmaBrowseNodeType> mRootNodeType;
42 
43     /** Wait time before sending a node reply, unless overridden in json (when supported). */
44     public final PrefEntry<TmaReplyDelay> mRootReplyDelay;
45 
46     /** Wait time for openAssetFile. */
47     public final PrefEntry<TmaReplyDelay> mAssetReplyDelay;
48 
49     /** Media apps event (update playback state, load browse tree) order after login. */
50     public final PrefEntry<TmaLoginEventOrder> mLoginEventOrder;
51 
52 
getInstance(Context context)53     public synchronized static TmaPrefs getInstance(Context context) {
54         if (sPrefs == null) {
55             sPrefs = new TmaPrefs(context);
56         }
57         return sPrefs;
58     }
59 
60     public interface PrefValueChangedListener<T> {
onValueChanged(T oldValue, T newValue)61         void onValueChanged(T oldValue, T newValue);
62     }
63 
64     /** The set of keys used to store the preferences. */
65     private enum TmaPrefKey {
66         ACCOUNT_TYPE_KEY,
67         ROOT_NODE_TYPE_KEY,
68         ROOT_REPLY_DELAY_KEY,
69         ASSET_REPLY_DELAY_KEY,
70         LOGIN_EVENT_ORDER_KEY
71     }
72 
73     /**
74      *   Represents a entry in the prefs
75      */
76     public abstract class PrefEntry<T> {
77 
78         protected final String mKey;
79 
PrefEntry(TmaPrefKey prefKey)80         PrefEntry(TmaPrefKey prefKey) {
81             mKey = prefKey.name();
82         }
83 
getValue()84         public abstract T getValue();
setValue(T value)85         public abstract void setValue(T value);
86 
registerChangeListener(PrefValueChangedListener<T> listener)87         public void registerChangeListener(PrefValueChangedListener<T> listener) {
88             if (mListeners.get(listener) != null) return;
89 
90             T currentValue = getValue();
91             listener.onValueChanged(currentValue, currentValue);
92 
93             OnSharedPreferenceChangeListener listenerWrapper =
94                     new OnSharedPreferenceChangeListener() {
95                         private T mOldValue = currentValue;
96 
97                         @Override
98                         public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
99                                 String key) {
100                             if (mKey.equals(key)) {
101                                 T newValue = getValue();
102                                 if (!Objects.equals(mOldValue, newValue)) {
103                                     listener.onValueChanged(mOldValue, newValue);
104                                     mOldValue = newValue;
105                                 }
106                             }
107                         }
108                     };
109 
110             mSharedPrefs.registerOnSharedPreferenceChangeListener(listenerWrapper);
111             mListeners.put(listener, listenerWrapper);
112         }
113     }
114 
115 
116     private final Map<PrefValueChangedListener, OnSharedPreferenceChangeListener> mListeners
117             = new HashMap<>(5);
118 
119     private final SharedPreferences mSharedPrefs;
120 
121 
TmaPrefs(Context context)122     private TmaPrefs(Context context) {
123         mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
124 
125         mAccountType = new EnumPrefEntry<>(TmaPrefKey.ACCOUNT_TYPE_KEY,
126                 TmaAccountType.values(), TmaAccountType.NONE);
127 
128         mRootNodeType = new EnumPrefEntry<>(TmaPrefKey.ROOT_NODE_TYPE_KEY,
129                 TmaBrowseNodeType.values(), TmaBrowseNodeType.NULL);
130 
131         mRootReplyDelay = new EnumPrefEntry<>(TmaPrefKey.ROOT_REPLY_DELAY_KEY,
132                 TmaReplyDelay.values(), TmaReplyDelay.NONE);
133 
134         mAssetReplyDelay = new EnumPrefEntry<>(TmaPrefKey.ASSET_REPLY_DELAY_KEY,
135                 TmaReplyDelay.values(), TmaReplyDelay.NONE);
136 
137         mLoginEventOrder = new EnumPrefEntry<>(TmaPrefKey.LOGIN_EVENT_ORDER_KEY,
138                 TmaLoginEventOrder.values(), TmaLoginEventOrder.PLAYBACK_STATE_UPDATE_FIRST);
139     }
140 
141 
142     /** Handles the conversion between the enum values and the shared preferences. */
143     private class EnumPrefEntry<T extends Enum & TmaEnumPrefs.EnumPrefValue>
144             extends PrefEntry<T> {
145 
146         private final T[] mEnumValues;
147         private final T mDefaultValue;
148 
EnumPrefEntry(TmaPrefKey prefKey, T[] enumValues, T defaultValue)149         EnumPrefEntry(TmaPrefKey prefKey, T[] enumValues, T defaultValue) {
150             super(prefKey);
151             mEnumValues = enumValues;
152             mDefaultValue = defaultValue;
153         }
154 
155         @Override
getValue()156         public T getValue() {
157             String id = mSharedPrefs.getString(mKey, null);
158             if (id != null) {
159                 for (T value : mEnumValues) {
160                     if (value.getId().equals(id)) {
161                         return value;
162                     }
163                 }
164             }
165             return mDefaultValue;
166         }
167 
168         @Override
setValue(T value)169         public void setValue(T value) {
170             mSharedPrefs.edit().putString(mKey, value.getId()).commit();
171         }
172     }
173 
174 }
175