Home | History | Annotate | Download | only in preference
      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.accounts.Account;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.SharedPreferences;
     23 import android.content.SharedPreferences.Editor;
     24 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
     25 import android.net.Uri;
     26 import android.os.Bundle;
     27 import android.os.Handler;
     28 import android.preference.PreferenceManager;
     29 import android.provider.ContactsContract;
     30 import android.provider.Settings;
     31 import android.provider.Settings.SettingNotFoundException;
     32 import android.text.TextUtils;
     33 
     34 import com.android.contacts.common.R;
     35 import com.android.contacts.common.model.account.AccountWithDataSet;
     36 import com.android.contacts.common.model.account.GoogleAccountType;
     37 import com.android.contacts.common.model.AccountTypeManager;
     38 
     39 import java.util.ArrayList;
     40 import java.util.List;
     41 
     42 /**
     43  * Manages user preferences for contacts.
     44  */
     45 public class ContactsPreferences implements OnSharedPreferenceChangeListener {
     46 
     47     /**
     48      * The value for the DISPLAY_ORDER key to show the given name first.
     49      */
     50     public static final int DISPLAY_ORDER_PRIMARY = 1;
     51 
     52     /**
     53      * The value for the DISPLAY_ORDER key to show the family name first.
     54      */
     55     public static final int DISPLAY_ORDER_ALTERNATIVE = 2;
     56 
     57     public static final String DISPLAY_ORDER_KEY = "android.contacts.DISPLAY_ORDER";
     58 
     59     /**
     60      * The value for the SORT_ORDER key corresponding to sort by given name first.
     61      */
     62     public static final int SORT_ORDER_PRIMARY = 1;
     63 
     64     public static final String SORT_ORDER_KEY = "android.contacts.SORT_ORDER";
     65 
     66     /**
     67      * The value for the SORT_ORDER key corresponding to sort by family name first.
     68      */
     69     public static final int SORT_ORDER_ALTERNATIVE = 2;
     70 
     71     public static final String PREF_DISPLAY_ONLY_PHONES = "only_phones";
     72 
     73     public static final boolean PREF_DISPLAY_ONLY_PHONES_DEFAULT = false;
     74 
     75     public static final String DO_NOT_SYNC_CONTACT_METADATA_MSG = "Do not sync metadata";
     76 
     77     public static final String CONTACT_METADATA_AUTHORITY = "com.android.contacts.metadata";
     78 
     79     public static final String SHOULD_CLEAR_METADATA_BEFORE_SYNCING =
     80             "should_clear_metadata_before_syncing";
     81 
     82     public static final String ONLY_CLEAR_DONOT_SYNC = "only_clear_donot_sync";
     83     /**
     84      * Value to use when a preference is unassigned and needs to be read from the shared preferences
     85      */
     86     private static final int PREFERENCE_UNASSIGNED = -1;
     87 
     88     private final Context mContext;
     89     private int mSortOrder = PREFERENCE_UNASSIGNED;
     90     private int mDisplayOrder = PREFERENCE_UNASSIGNED;
     91     private String mDefaultAccount = null;
     92     private ChangeListener mListener = null;
     93     private Handler mHandler;
     94     private final SharedPreferences mPreferences;
     95     private String mDefaultAccountKey;
     96     private String mDefaultAccountSavedKey;
     97 
     98     public ContactsPreferences(Context context) {
     99         mContext = context;
    100         mHandler = new Handler();
    101         mPreferences = mContext.getSharedPreferences(context.getPackageName(),
    102                 Context.MODE_PRIVATE);
    103         mDefaultAccountKey = mContext.getResources().getString(
    104                 R.string.contact_editor_default_account_key);
    105         mDefaultAccountSavedKey = mContext.getResources().getString(
    106                 R.string.contact_editor_anything_saved_key);
    107         maybeMigrateSystemSettings();
    108     }
    109 
    110     public boolean isSortOrderUserChangeable() {
    111         return mContext.getResources().getBoolean(R.bool.config_sort_order_user_changeable);
    112     }
    113 
    114     public int getDefaultSortOrder() {
    115         if (mContext.getResources().getBoolean(R.bool.config_default_sort_order_primary)) {
    116             return SORT_ORDER_PRIMARY;
    117         } else {
    118             return SORT_ORDER_ALTERNATIVE;
    119         }
    120     }
    121 
    122     public int getSortOrder() {
    123         if (!isSortOrderUserChangeable()) {
    124             return getDefaultSortOrder();
    125         }
    126         if (mSortOrder == PREFERENCE_UNASSIGNED) {
    127             mSortOrder = mPreferences.getInt(SORT_ORDER_KEY, getDefaultSortOrder());
    128         }
    129         return mSortOrder;
    130     }
    131 
    132     public void setSortOrder(int sortOrder) {
    133         mSortOrder = sortOrder;
    134         final Editor editor = mPreferences.edit();
    135         editor.putInt(SORT_ORDER_KEY, sortOrder);
    136         editor.commit();
    137     }
    138 
    139     public boolean isDisplayOrderUserChangeable() {
    140         return mContext.getResources().getBoolean(R.bool.config_display_order_user_changeable);
    141     }
    142 
    143     public int getDefaultDisplayOrder() {
    144         if (mContext.getResources().getBoolean(R.bool.config_default_display_order_primary)) {
    145             return DISPLAY_ORDER_PRIMARY;
    146         } else {
    147             return DISPLAY_ORDER_ALTERNATIVE;
    148         }
    149     }
    150 
    151     public int getDisplayOrder() {
    152         if (!isDisplayOrderUserChangeable()) {
    153             return getDefaultDisplayOrder();
    154         }
    155         if (mDisplayOrder == PREFERENCE_UNASSIGNED) {
    156             mDisplayOrder = mPreferences.getInt(DISPLAY_ORDER_KEY, getDefaultDisplayOrder());
    157         }
    158         return mDisplayOrder;
    159     }
    160 
    161     public void setDisplayOrder(int displayOrder) {
    162         mDisplayOrder = displayOrder;
    163         final Editor editor = mPreferences.edit();
    164         editor.putInt(DISPLAY_ORDER_KEY, displayOrder);
    165         editor.commit();
    166     }
    167 
    168     public boolean isDefaultAccountUserChangeable() {
    169         return mContext.getResources().getBoolean(R.bool.config_default_account_user_changeable);
    170     }
    171 
    172     public String getDefaultAccount() {
    173         if (!isDefaultAccountUserChangeable()) {
    174             return mDefaultAccount;
    175         }
    176         if (TextUtils.isEmpty(mDefaultAccount)) {
    177             final String accountString = mPreferences
    178                     .getString(mDefaultAccountKey, mDefaultAccount);
    179             if (!TextUtils.isEmpty(accountString)) {
    180                 final AccountWithDataSet accountWithDataSet = AccountWithDataSet.unstringify(
    181                         accountString);
    182                 mDefaultAccount = accountWithDataSet.name;
    183             }
    184         }
    185         return mDefaultAccount;
    186     }
    187 
    188     public void setDefaultAccount(AccountWithDataSet accountWithDataSet) {
    189         mDefaultAccount = accountWithDataSet == null ? null : accountWithDataSet.name;
    190         final Editor editor = mPreferences.edit();
    191         if (TextUtils.isEmpty(mDefaultAccount)) {
    192             editor.remove(mDefaultAccountKey);
    193         } else {
    194             editor.putString(mDefaultAccountKey, accountWithDataSet.stringify());
    195         }
    196         editor.putBoolean(mDefaultAccountSavedKey, true);
    197         editor.commit();
    198     }
    199 
    200     public String getContactMetadataSyncAccountName() {
    201         final Account syncAccount = getContactMetadataSyncAccount();
    202         return syncAccount == null ? DO_NOT_SYNC_CONTACT_METADATA_MSG : syncAccount.name;
    203     }
    204 
    205     public void setContactMetadataSyncAccount(AccountWithDataSet accountWithDataSet) {
    206         final String mContactMetadataSyncAccount =
    207                 accountWithDataSet == null ? null : accountWithDataSet.name;
    208         requestMetadataSyncForAccount(mContactMetadataSyncAccount);
    209     }
    210 
    211     private Account getContactMetadataSyncAccount() {
    212         for (Account account : getFocusGoogleAccounts()) {
    213             if (ContentResolver.getIsSyncable(account, CONTACT_METADATA_AUTHORITY) == 1
    214                     && ContentResolver.getSyncAutomatically(account, CONTACT_METADATA_AUTHORITY)) {
    215                 return account;
    216             }
    217         }
    218         return null;
    219     }
    220 
    221     /**
    222      * Turn on contact metadata sync for this {@param accountName} and turn off automatic sync
    223      * for other accounts. If accountName is null, then turn off automatic sync for all accounts.
    224      */
    225     private void requestMetadataSyncForAccount(String accountName) {
    226         for (Account account : getFocusGoogleAccounts()) {
    227             if (!TextUtils.isEmpty(accountName) && accountName.equals(account.name)) {
    228                 // Request sync.
    229                 final Bundle b = new Bundle();
    230                 b.putBoolean(SHOULD_CLEAR_METADATA_BEFORE_SYNCING, true);
    231                 b.putBoolean(ONLY_CLEAR_DONOT_SYNC, false);
    232                 b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    233                 b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    234                 ContentResolver.requestSync(account, CONTACT_METADATA_AUTHORITY, b);
    235 
    236                 ContentResolver.setSyncAutomatically(account, CONTACT_METADATA_AUTHORITY, true);
    237             } else if (ContentResolver.getSyncAutomatically(account, CONTACT_METADATA_AUTHORITY)) {
    238                 // Turn off automatic sync for previous sync account.
    239                 ContentResolver.setSyncAutomatically(account, CONTACT_METADATA_AUTHORITY, false);
    240                 if (TextUtils.isEmpty(accountName)) {
    241                     // Request sync to clear old data.
    242                     final Bundle b = new Bundle();
    243                     b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
    244                     b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
    245                     b.putBoolean(SHOULD_CLEAR_METADATA_BEFORE_SYNCING, true);
    246                     b.putBoolean(ONLY_CLEAR_DONOT_SYNC, true);
    247                     ContentResolver.requestSync(account, CONTACT_METADATA_AUTHORITY, b);
    248                 }
    249             }
    250         }
    251     }
    252 
    253     /**
    254      * @return google accounts with "com.google" account type and null data set.
    255      */
    256     private List<Account> getFocusGoogleAccounts() {
    257         List<Account> focusGoogleAccounts = new ArrayList<Account>();
    258         final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext);
    259         List<AccountWithDataSet> accounts = accountTypeManager.getAccounts(true);
    260         for (AccountWithDataSet account : accounts) {
    261             if (GoogleAccountType.ACCOUNT_TYPE.equals(account.type) && account.dataSet == null) {
    262                 focusGoogleAccounts.add(account.getAccountOrNull());
    263             }
    264         }
    265         return focusGoogleAccounts;
    266     }
    267 
    268     public void registerChangeListener(ChangeListener listener) {
    269         if (mListener != null) unregisterChangeListener();
    270 
    271         mListener = listener;
    272 
    273         // Reset preferences to "unknown" because they may have changed while the
    274         // listener was unregistered.
    275         mDisplayOrder = PREFERENCE_UNASSIGNED;
    276         mSortOrder = PREFERENCE_UNASSIGNED;
    277         mDefaultAccount = null;
    278 
    279         mPreferences.registerOnSharedPreferenceChangeListener(this);
    280     }
    281 
    282     public void unregisterChangeListener() {
    283         if (mListener != null) {
    284             mListener = null;
    285         }
    286 
    287         mPreferences.unregisterOnSharedPreferenceChangeListener(this);
    288     }
    289 
    290     @Override
    291     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
    292         // This notification is not sent on the Ui thread. Use the previously created Handler
    293         // to switch to the Ui thread
    294         mHandler.post(new Runnable() {
    295             @Override
    296             public void run() {
    297                 refreshValue(key);
    298             }
    299         });
    300     }
    301 
    302     /**
    303      * Forces the value for the given key to be looked up from shared preferences and notifies
    304      * the registered {@link ChangeListener}
    305      *
    306      * @param key the {@link SharedPreferences} key to look up
    307      */
    308     public void refreshValue(String key) {
    309         if (DISPLAY_ORDER_KEY.equals(key)) {
    310             mDisplayOrder = PREFERENCE_UNASSIGNED;
    311             mDisplayOrder = getDisplayOrder();
    312         } else if (SORT_ORDER_KEY.equals(key)) {
    313             mSortOrder = PREFERENCE_UNASSIGNED;
    314             mSortOrder = getSortOrder();
    315         } else if (mDefaultAccountKey.equals(key)) {
    316             mDefaultAccount = null;
    317             mDefaultAccount = getDefaultAccount();
    318         }
    319         if (mListener != null) mListener.onChange();
    320     }
    321 
    322     public interface ChangeListener {
    323         void onChange();
    324     }
    325 
    326     /**
    327      * If there are currently no preferences (which means this is the first time we are run),
    328      * For sort order and display order, check to see if there are any preferences stored in
    329      * system settings (pre-L) which can be copied into our own SharedPreferences.
    330      * For default account setting, check to see if there are any preferences stored in the previous
    331      * SharedPreferences which can be copied into current SharedPreferences.
    332      */
    333     private void maybeMigrateSystemSettings() {
    334         if (!mPreferences.contains(SORT_ORDER_KEY)) {
    335             int sortOrder = getDefaultSortOrder();
    336             try {
    337                  sortOrder = Settings.System.getInt(mContext.getContentResolver(),
    338                         SORT_ORDER_KEY);
    339             } catch (SettingNotFoundException e) {
    340             }
    341             setSortOrder(sortOrder);
    342         }
    343 
    344         if (!mPreferences.contains(DISPLAY_ORDER_KEY)) {
    345             int displayOrder = getDefaultDisplayOrder();
    346             try {
    347                 displayOrder = Settings.System.getInt(mContext.getContentResolver(),
    348                         DISPLAY_ORDER_KEY);
    349             } catch (SettingNotFoundException e) {
    350             }
    351             setDisplayOrder(displayOrder);
    352         }
    353 
    354         if (!mPreferences.contains(mDefaultAccountKey)) {
    355             final SharedPreferences previousPrefs =
    356                     PreferenceManager.getDefaultSharedPreferences(mContext);
    357             final String defaultAccount = previousPrefs.getString(mDefaultAccountKey, null);
    358             if (!TextUtils.isEmpty(defaultAccount)) {
    359                 final AccountWithDataSet accountWithDataSet = AccountWithDataSet.unstringify(
    360                         defaultAccount);
    361                 setDefaultAccount(accountWithDataSet);
    362             }
    363         }
    364     }
    365 }
    366