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