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.list; 18 19 import android.content.SharedPreferences; 20 import android.graphics.drawable.Drawable; 21 import android.net.Uri; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.provider.ContactsContract.RawContacts; 25 import android.text.TextUtils; 26 27 /** 28 * Contact list filter parameters. 29 */ 30 public final class ContactListFilter implements Comparable<ContactListFilter>, Parcelable { 31 32 public static final int FILTER_TYPE_DEFAULT = -1; 33 public static final int FILTER_TYPE_ALL_ACCOUNTS = -2; 34 public static final int FILTER_TYPE_CUSTOM = -3; 35 public static final int FILTER_TYPE_STARRED = -4; 36 public static final int FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY = -5; 37 public static final int FILTER_TYPE_SINGLE_CONTACT = -6; 38 39 public static final int FILTER_TYPE_ACCOUNT = 0; 40 41 /** 42 * Obsolete filter which had been used in Honeycomb. This may be stored in 43 * {@link SharedPreferences}, but should be replaced with ALL filter when it is found. 44 * 45 * TODO: "group" filter and relevant variables are all obsolete. Remove them. 46 */ 47 private static final int FILTER_TYPE_GROUP = 1; 48 49 private static final String KEY_FILTER_TYPE = "filter.type"; 50 private static final String KEY_ACCOUNT_NAME = "filter.accountName"; 51 private static final String KEY_ACCOUNT_TYPE = "filter.accountType"; 52 private static final String KEY_DATA_SET = "filter.dataSet"; 53 54 public final int filterType; 55 public final String accountType; 56 public final String accountName; 57 public final String dataSet; 58 public final Drawable icon; 59 private String mId; 60 61 public ContactListFilter(int filterType, String accountType, String accountName, String dataSet, 62 Drawable icon) { 63 this.filterType = filterType; 64 this.accountType = accountType; 65 this.accountName = accountName; 66 this.dataSet = dataSet; 67 this.icon = icon; 68 } 69 70 public static ContactListFilter createFilterWithType(int filterType) { 71 return new ContactListFilter(filterType, null, null, null, null); 72 } 73 74 public static ContactListFilter createAccountFilter(String accountType, String accountName, 75 String dataSet, Drawable icon) { 76 return new ContactListFilter(ContactListFilter.FILTER_TYPE_ACCOUNT, accountType, 77 accountName, dataSet, icon); 78 } 79 80 /** 81 * Returns true if this filter is based on data and may become invalid over time. 82 */ 83 public boolean isValidationRequired() { 84 return filterType == FILTER_TYPE_ACCOUNT; 85 } 86 87 @Override 88 public String toString() { 89 switch (filterType) { 90 case FILTER_TYPE_DEFAULT: 91 return "default"; 92 case FILTER_TYPE_ALL_ACCOUNTS: 93 return "all_accounts"; 94 case FILTER_TYPE_CUSTOM: 95 return "custom"; 96 case FILTER_TYPE_STARRED: 97 return "starred"; 98 case FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY: 99 return "with_phones"; 100 case FILTER_TYPE_SINGLE_CONTACT: 101 return "single"; 102 case FILTER_TYPE_ACCOUNT: 103 return "account: " + accountType + (dataSet != null ? "/" + dataSet : "") 104 + " " + accountName; 105 } 106 return super.toString(); 107 } 108 109 @Override 110 public int compareTo(ContactListFilter another) { 111 int res = accountName.compareTo(another.accountName); 112 if (res != 0) { 113 return res; 114 } 115 116 res = accountType.compareTo(another.accountType); 117 if (res != 0) { 118 return res; 119 } 120 121 return filterType - another.filterType; 122 } 123 124 @Override 125 public int hashCode() { 126 int code = filterType; 127 if (accountType != null) { 128 code = code * 31 + accountType.hashCode(); 129 code = code * 31 + accountName.hashCode(); 130 } 131 if (dataSet != null) { 132 code = code * 31 + dataSet.hashCode(); 133 } 134 return code; 135 } 136 137 @Override 138 public boolean equals(Object other) { 139 if (this == other) { 140 return true; 141 } 142 143 if (!(other instanceof ContactListFilter)) { 144 return false; 145 } 146 147 ContactListFilter otherFilter = (ContactListFilter) other; 148 if (filterType != otherFilter.filterType 149 || !TextUtils.equals(accountName, otherFilter.accountName) 150 || !TextUtils.equals(accountType, otherFilter.accountType) 151 || !TextUtils.equals(dataSet, otherFilter.dataSet)) { 152 return false; 153 } 154 155 return true; 156 } 157 158 /** 159 * Store the given {@link ContactListFilter} to preferences. If the requested filter is 160 * of type {@link #FILTER_TYPE_SINGLE_CONTACT} then do not save it to preferences because 161 * it is a temporary state. 162 */ 163 public static void storeToPreferences(SharedPreferences prefs, ContactListFilter filter) { 164 if (filter != null && filter.filterType == FILTER_TYPE_SINGLE_CONTACT) { 165 return; 166 } 167 prefs.edit() 168 .putInt(KEY_FILTER_TYPE, filter == null ? FILTER_TYPE_DEFAULT : filter.filterType) 169 .putString(KEY_ACCOUNT_NAME, filter == null ? null : filter.accountName) 170 .putString(KEY_ACCOUNT_TYPE, filter == null ? null : filter.accountType) 171 .putString(KEY_DATA_SET, filter == null ? null : filter.dataSet) 172 .apply(); 173 } 174 175 /** 176 * Try to obtain ContactListFilter object saved in SharedPreference. 177 * If there's no info there, return ALL filter instead. 178 */ 179 public static ContactListFilter restoreDefaultPreferences(SharedPreferences prefs) { 180 ContactListFilter filter = restoreFromPreferences(prefs); 181 if (filter == null) { 182 filter = ContactListFilter.createFilterWithType(FILTER_TYPE_ALL_ACCOUNTS); 183 } 184 // "Group" filter is obsolete and thus is not exposed anymore. The "single contact mode" 185 // should also not be stored in preferences anymore since it is a temporary state. 186 if (filter.filterType == FILTER_TYPE_GROUP || 187 filter.filterType == FILTER_TYPE_SINGLE_CONTACT) { 188 filter = ContactListFilter.createFilterWithType(FILTER_TYPE_ALL_ACCOUNTS); 189 } 190 return filter; 191 } 192 193 private static ContactListFilter restoreFromPreferences(SharedPreferences prefs) { 194 int filterType = prefs.getInt(KEY_FILTER_TYPE, FILTER_TYPE_DEFAULT); 195 if (filterType == FILTER_TYPE_DEFAULT) { 196 return null; 197 } 198 199 String accountName = prefs.getString(KEY_ACCOUNT_NAME, null); 200 String accountType = prefs.getString(KEY_ACCOUNT_TYPE, null); 201 String dataSet = prefs.getString(KEY_DATA_SET, null); 202 return new ContactListFilter(filterType, accountType, accountName, dataSet, null); 203 } 204 205 206 @Override 207 public void writeToParcel(Parcel dest, int flags) { 208 dest.writeInt(filterType); 209 dest.writeString(accountName); 210 dest.writeString(accountType); 211 dest.writeString(dataSet); 212 } 213 214 public static final Parcelable.Creator<ContactListFilter> CREATOR = 215 new Parcelable.Creator<ContactListFilter>() { 216 @Override 217 public ContactListFilter createFromParcel(Parcel source) { 218 int filterType = source.readInt(); 219 String accountName = source.readString(); 220 String accountType = source.readString(); 221 String dataSet = source.readString(); 222 return new ContactListFilter(filterType, accountType, accountName, dataSet, null); 223 } 224 225 @Override 226 public ContactListFilter[] newArray(int size) { 227 return new ContactListFilter[size]; 228 } 229 }; 230 231 @Override 232 public int describeContents() { 233 return 0; 234 } 235 236 /** 237 * Returns a string that can be used as a stable persistent identifier for this filter. 238 */ 239 public String getId() { 240 if (mId == null) { 241 StringBuilder sb = new StringBuilder(); 242 sb.append(filterType); 243 if (accountType != null) { 244 sb.append('-').append(accountType); 245 } 246 if (dataSet != null) { 247 sb.append('/').append(dataSet); 248 } 249 if (accountName != null) { 250 sb.append('-').append(accountName.replace('-', '_')); 251 } 252 mId = sb.toString(); 253 } 254 return mId; 255 } 256 257 /** 258 * Adds the account query parameters to the given {@code uriBuilder}. 259 * 260 * @throws IllegalStateException if the filter type is not {@link #FILTER_TYPE_ACCOUNT}. 261 */ 262 public Uri.Builder addAccountQueryParameterToUrl(Uri.Builder uriBuilder) { 263 if (filterType != FILTER_TYPE_ACCOUNT) { 264 throw new IllegalStateException("filterType must be FILTER_TYPE_ACCOUNT"); 265 } 266 uriBuilder.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName); 267 uriBuilder.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType); 268 if (!TextUtils.isEmpty(dataSet)) { 269 uriBuilder.appendQueryParameter(RawContacts.DATA_SET, dataSet); 270 } 271 return uriBuilder; 272 } 273 274 public String toDebugString() { 275 final StringBuilder builder = new StringBuilder(); 276 builder.append("[filter type: " + filterType + " (" + filterTypeToString(filterType) + ")"); 277 if (filterType == FILTER_TYPE_ACCOUNT) { 278 builder.append(", accountType: " + accountType) 279 .append(", accountName: " + accountName) 280 .append(", dataSet: " + dataSet); 281 } 282 builder.append(", icon: " + icon + "]"); 283 return builder.toString(); 284 } 285 286 public static final String filterTypeToString(int filterType) { 287 switch (filterType) { 288 case FILTER_TYPE_DEFAULT: 289 return "FILTER_TYPE_DEFAULT"; 290 case FILTER_TYPE_ALL_ACCOUNTS: 291 return "FILTER_TYPE_ALL_ACCOUNTS"; 292 case FILTER_TYPE_CUSTOM: 293 return "FILTER_TYPE_CUSTOM"; 294 case FILTER_TYPE_STARRED: 295 return "FILTER_TYPE_STARRED"; 296 case FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY: 297 return "FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY"; 298 case FILTER_TYPE_SINGLE_CONTACT: 299 return "FILTER_TYPE_SINGLE_CONTACT"; 300 case FILTER_TYPE_ACCOUNT: 301 return "FILTER_TYPE_ACCOUNT"; 302 default: 303 return "(unknown)"; 304 } 305 } 306 } 307