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 package com.android.contacts.common.list; 17 18 import android.content.Context; 19 import android.content.SharedPreferences; 20 import android.preference.PreferenceManager; 21 22 import com.android.contacts.common.model.AccountTypeManager; 23 import com.android.contacts.common.model.account.AccountWithDataSet; 24 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Manages {@link ContactListFilter}. All methods must be called from UI thread. 30 */ 31 public abstract class ContactListFilterController { 32 33 // singleton to cache the filter controller 34 private static ContactListFilterControllerImpl sFilterController = null; 35 36 public interface ContactListFilterListener { 37 void onContactListFilterChanged(); 38 } 39 40 public static ContactListFilterController getInstance(Context context) { 41 // We may need to synchronize this in the future if background task will call this. 42 if (sFilterController == null) { 43 sFilterController = new ContactListFilterControllerImpl(context); 44 } 45 return sFilterController; 46 } 47 48 public abstract void addListener(ContactListFilterListener listener); 49 50 public abstract void removeListener(ContactListFilterListener listener); 51 52 /** 53 * Return the currently-active filter. 54 */ 55 public abstract ContactListFilter getFilter(); 56 57 /** 58 * @param filter the filter 59 * @param persistent True when the given filter should be saved soon. False when the filter 60 * should not be saved. The latter case may happen when some Intent requires a certain type of 61 * UI (e.g. single contact) temporarily. 62 */ 63 public abstract void setContactListFilter(ContactListFilter filter, boolean persistent); 64 65 public abstract void selectCustomFilter(); 66 67 /** 68 * Checks if the current filter is valid and reset the filter if not. It may happen when 69 * an account is removed while the filter points to the account with 70 * {@link ContactListFilter#FILTER_TYPE_ACCOUNT} type, for example. It may also happen if 71 * the current filter is {@link ContactListFilter#FILTER_TYPE_SINGLE_CONTACT}, in 72 * which case, we should switch to the last saved filter in {@link SharedPreferences}. 73 */ 74 public abstract void checkFilterValidity(boolean notifyListeners); 75 } 76 77 /** 78 * Stores the {@link ContactListFilter} selected by the user and saves it to 79 * {@link SharedPreferences} if necessary. 80 */ 81 class ContactListFilterControllerImpl extends ContactListFilterController { 82 private final Context mContext; 83 private final List<ContactListFilterListener> mListeners = 84 new ArrayList<ContactListFilterListener>(); 85 private ContactListFilter mFilter; 86 87 public ContactListFilterControllerImpl(Context context) { 88 mContext = context; 89 mFilter = ContactListFilter.restoreDefaultPreferences(getSharedPreferences()); 90 checkFilterValidity(true /* notify listeners */); 91 } 92 93 @Override 94 public void addListener(ContactListFilterListener listener) { 95 mListeners.add(listener); 96 } 97 98 @Override 99 public void removeListener(ContactListFilterListener listener) { 100 mListeners.remove(listener); 101 } 102 103 @Override 104 public ContactListFilter getFilter() { 105 return mFilter; 106 } 107 108 private SharedPreferences getSharedPreferences() { 109 return PreferenceManager.getDefaultSharedPreferences(mContext); 110 } 111 112 @Override 113 public void setContactListFilter(ContactListFilter filter, boolean persistent) { 114 setContactListFilter(filter, persistent, true); 115 } 116 117 private void setContactListFilter(ContactListFilter filter, boolean persistent, 118 boolean notifyListeners) { 119 if (!filter.equals(mFilter)) { 120 mFilter = filter; 121 if (persistent) { 122 ContactListFilter.storeToPreferences(getSharedPreferences(), mFilter); 123 } 124 if (notifyListeners && !mListeners.isEmpty()) { 125 notifyContactListFilterChanged(); 126 } 127 } 128 } 129 130 @Override 131 public void selectCustomFilter() { 132 setContactListFilter(ContactListFilter.createFilterWithType( 133 ContactListFilter.FILTER_TYPE_CUSTOM), true); 134 } 135 136 private void notifyContactListFilterChanged() { 137 for (ContactListFilterListener listener : mListeners) { 138 listener.onContactListFilterChanged(); 139 } 140 } 141 142 @Override 143 public void checkFilterValidity(boolean notifyListeners) { 144 if (mFilter == null) { 145 return; 146 } 147 148 switch (mFilter.filterType) { 149 case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT: 150 setContactListFilter( 151 ContactListFilter.restoreDefaultPreferences(getSharedPreferences()), 152 false, notifyListeners); 153 break; 154 case ContactListFilter.FILTER_TYPE_ACCOUNT: 155 if (!filterAccountExists()) { 156 // The current account filter points to invalid account. Use "all" filter 157 // instead. 158 setContactListFilter(ContactListFilter.createFilterWithType( 159 ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS), true, notifyListeners); 160 } 161 } 162 } 163 164 /** 165 * @return true if the Account for the current filter exists. 166 */ 167 private boolean filterAccountExists() { 168 final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(mContext); 169 final AccountWithDataSet filterAccount = new AccountWithDataSet( 170 mFilter.accountName, mFilter.accountType, mFilter.dataSet); 171 return accountTypeManager.contains(filterAccount, false); 172 } 173 } 174