1 /*
2  * Copyright (C) 2010 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.contacts.common.preference;
18 
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.content.SharedPreferences.Editor;
22 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
23 import android.os.Handler;
24 import android.preference.PreferenceManager;
25 import android.provider.Settings;
26 import android.provider.Settings.SettingNotFoundException;
27 import android.text.TextUtils;
28 import com.android.contacts.common.R;
29 import com.android.contacts.common.model.account.AccountWithDataSet;
30 
31 /** Manages user preferences for contacts. */
32 public class ContactsPreferences implements OnSharedPreferenceChangeListener {
33 
34   /** The value for the DISPLAY_ORDER key to show the given name first. */
35   public static final int DISPLAY_ORDER_PRIMARY = 1;
36 
37   /** The value for the DISPLAY_ORDER key to show the family name first. */
38   public static final int DISPLAY_ORDER_ALTERNATIVE = 2;
39 
40   public static final String DISPLAY_ORDER_KEY = "android.contacts.DISPLAY_ORDER";
41 
42   /** The value for the SORT_ORDER key corresponding to sort by given name first. */
43   public static final int SORT_ORDER_PRIMARY = 1;
44 
45   public static final String SORT_ORDER_KEY = "android.contacts.SORT_ORDER";
46 
47   /** The value for the SORT_ORDER key corresponding to sort by family name first. */
48   public static final int SORT_ORDER_ALTERNATIVE = 2;
49 
50   public static final String PREF_DISPLAY_ONLY_PHONES = "only_phones";
51 
52   public static final boolean PREF_DISPLAY_ONLY_PHONES_DEFAULT = false;
53 
54   /**
55    * Value to use when a preference is unassigned and needs to be read from the shared preferences
56    */
57   private static final int PREFERENCE_UNASSIGNED = -1;
58 
59   private final Context mContext;
60   private final SharedPreferences mPreferences;
61   private int mSortOrder = PREFERENCE_UNASSIGNED;
62   private int mDisplayOrder = PREFERENCE_UNASSIGNED;
63   private String mDefaultAccount = null;
64   private ChangeListener mListener = null;
65   private Handler mHandler;
66   private String mDefaultAccountKey;
67   private String mDefaultAccountSavedKey;
68 
ContactsPreferences(Context context)69   public ContactsPreferences(Context context) {
70     mContext = context;
71     mHandler = new Handler();
72     mPreferences = mContext.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
73     mDefaultAccountKey =
74         mContext.getResources().getString(R.string.contact_editor_default_account_key);
75     mDefaultAccountSavedKey =
76         mContext.getResources().getString(R.string.contact_editor_anything_saved_key);
77     maybeMigrateSystemSettings();
78   }
79 
isSortOrderUserChangeable()80   public boolean isSortOrderUserChangeable() {
81     return mContext.getResources().getBoolean(R.bool.config_sort_order_user_changeable);
82   }
83 
getDefaultSortOrder()84   public int getDefaultSortOrder() {
85     if (mContext.getResources().getBoolean(R.bool.config_default_sort_order_primary)) {
86       return SORT_ORDER_PRIMARY;
87     } else {
88       return SORT_ORDER_ALTERNATIVE;
89     }
90   }
91 
getSortOrder()92   public int getSortOrder() {
93     if (!isSortOrderUserChangeable()) {
94       return getDefaultSortOrder();
95     }
96     if (mSortOrder == PREFERENCE_UNASSIGNED) {
97       mSortOrder = mPreferences.getInt(SORT_ORDER_KEY, getDefaultSortOrder());
98     }
99     return mSortOrder;
100   }
101 
setSortOrder(int sortOrder)102   public void setSortOrder(int sortOrder) {
103     mSortOrder = sortOrder;
104     final Editor editor = mPreferences.edit();
105     editor.putInt(SORT_ORDER_KEY, sortOrder);
106     editor.commit();
107   }
108 
isDisplayOrderUserChangeable()109   public boolean isDisplayOrderUserChangeable() {
110     return mContext.getResources().getBoolean(R.bool.config_display_order_user_changeable);
111   }
112 
getDefaultDisplayOrder()113   public int getDefaultDisplayOrder() {
114     if (mContext.getResources().getBoolean(R.bool.config_default_display_order_primary)) {
115       return DISPLAY_ORDER_PRIMARY;
116     } else {
117       return DISPLAY_ORDER_ALTERNATIVE;
118     }
119   }
120 
getDisplayOrder()121   public int getDisplayOrder() {
122     if (!isDisplayOrderUserChangeable()) {
123       return getDefaultDisplayOrder();
124     }
125     if (mDisplayOrder == PREFERENCE_UNASSIGNED) {
126       mDisplayOrder = mPreferences.getInt(DISPLAY_ORDER_KEY, getDefaultDisplayOrder());
127     }
128     return mDisplayOrder;
129   }
130 
setDisplayOrder(int displayOrder)131   public void setDisplayOrder(int displayOrder) {
132     mDisplayOrder = displayOrder;
133     final Editor editor = mPreferences.edit();
134     editor.putInt(DISPLAY_ORDER_KEY, displayOrder);
135     editor.commit();
136   }
137 
isDefaultAccountUserChangeable()138   public boolean isDefaultAccountUserChangeable() {
139     return mContext.getResources().getBoolean(R.bool.config_default_account_user_changeable);
140   }
141 
getDefaultAccount()142   public String getDefaultAccount() {
143     if (!isDefaultAccountUserChangeable()) {
144       return mDefaultAccount;
145     }
146     if (TextUtils.isEmpty(mDefaultAccount)) {
147       final String accountString = mPreferences.getString(mDefaultAccountKey, mDefaultAccount);
148       if (!TextUtils.isEmpty(accountString)) {
149         final AccountWithDataSet accountWithDataSet = AccountWithDataSet.unstringify(accountString);
150         mDefaultAccount = accountWithDataSet.name;
151       }
152     }
153     return mDefaultAccount;
154   }
155 
setDefaultAccount(AccountWithDataSet accountWithDataSet)156   public void setDefaultAccount(AccountWithDataSet accountWithDataSet) {
157     mDefaultAccount = accountWithDataSet == null ? null : accountWithDataSet.name;
158     final Editor editor = mPreferences.edit();
159     if (TextUtils.isEmpty(mDefaultAccount)) {
160       editor.remove(mDefaultAccountKey);
161     } else {
162       editor.putString(mDefaultAccountKey, accountWithDataSet.stringify());
163     }
164     editor.putBoolean(mDefaultAccountSavedKey, true);
165     editor.commit();
166   }
167 
registerChangeListener(ChangeListener listener)168   public void registerChangeListener(ChangeListener listener) {
169     if (mListener != null) {
170       unregisterChangeListener();
171     }
172 
173     mListener = listener;
174 
175     // Reset preferences to "unknown" because they may have changed while the
176     // listener was unregistered.
177     mDisplayOrder = PREFERENCE_UNASSIGNED;
178     mSortOrder = PREFERENCE_UNASSIGNED;
179     mDefaultAccount = null;
180 
181     mPreferences.registerOnSharedPreferenceChangeListener(this);
182   }
183 
unregisterChangeListener()184   public void unregisterChangeListener() {
185     if (mListener != null) {
186       mListener = null;
187     }
188 
189     mPreferences.unregisterOnSharedPreferenceChangeListener(this);
190   }
191 
192   @Override
onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key)193   public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
194     // This notification is not sent on the Ui thread. Use the previously created Handler
195     // to switch to the Ui thread
196     mHandler.post(
197         new Runnable() {
198           @Override
199           public void run() {
200             refreshValue(key);
201           }
202         });
203   }
204 
205   /**
206    * Forces the value for the given key to be looked up from shared preferences and notifies the
207    * registered {@link ChangeListener}
208    *
209    * @param key the {@link SharedPreferences} key to look up
210    */
refreshValue(String key)211   public void refreshValue(String key) {
212     if (DISPLAY_ORDER_KEY.equals(key)) {
213       mDisplayOrder = PREFERENCE_UNASSIGNED;
214       mDisplayOrder = getDisplayOrder();
215     } else if (SORT_ORDER_KEY.equals(key)) {
216       mSortOrder = PREFERENCE_UNASSIGNED;
217       mSortOrder = getSortOrder();
218     } else if (mDefaultAccountKey.equals(key)) {
219       mDefaultAccount = null;
220       mDefaultAccount = getDefaultAccount();
221     }
222     if (mListener != null) {
223       mListener.onChange();
224     }
225   }
226 
227   /**
228    * If there are currently no preferences (which means this is the first time we are run), For sort
229    * order and display order, check to see if there are any preferences stored in system settings
230    * (pre-L) which can be copied into our own SharedPreferences. For default account setting, check
231    * to see if there are any preferences stored in the previous SharedPreferences which can be
232    * copied into current SharedPreferences.
233    */
maybeMigrateSystemSettings()234   private void maybeMigrateSystemSettings() {
235     if (!mPreferences.contains(SORT_ORDER_KEY)) {
236       int sortOrder = getDefaultSortOrder();
237       try {
238         sortOrder = Settings.System.getInt(mContext.getContentResolver(), SORT_ORDER_KEY);
239       } catch (SettingNotFoundException e) {
240       }
241       setSortOrder(sortOrder);
242     }
243 
244     if (!mPreferences.contains(DISPLAY_ORDER_KEY)) {
245       int displayOrder = getDefaultDisplayOrder();
246       try {
247         displayOrder = Settings.System.getInt(mContext.getContentResolver(), DISPLAY_ORDER_KEY);
248       } catch (SettingNotFoundException e) {
249       }
250       setDisplayOrder(displayOrder);
251     }
252 
253     if (!mPreferences.contains(mDefaultAccountKey)) {
254       final SharedPreferences previousPrefs =
255           PreferenceManager.getDefaultSharedPreferences(mContext);
256       final String defaultAccount = previousPrefs.getString(mDefaultAccountKey, null);
257       if (!TextUtils.isEmpty(defaultAccount)) {
258         final AccountWithDataSet accountWithDataSet =
259             AccountWithDataSet.unstringify(defaultAccount);
260         setDefaultAccount(accountWithDataSet);
261       }
262     }
263   }
264 
265   public interface ChangeListener {
266 
onChange()267     void onChange();
268   }
269 }
270