1 /* 2 * Copyright (C) 2011 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.model.account; 18 19 import android.accounts.Account; 20 import android.content.Context; 21 import android.database.Cursor; 22 import android.net.Uri; 23 import android.os.Parcel; 24 import android.provider.BaseColumns; 25 import android.provider.ContactsContract; 26 import android.provider.ContactsContract.RawContacts; 27 import android.text.TextUtils; 28 29 import com.google.common.base.Objects; 30 import com.google.common.collect.Lists; 31 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.regex.Pattern; 35 36 /** 37 * Wrapper for an account that includes a data set (which may be null). 38 */ 39 public class AccountWithDataSet extends Account { 40 private static final String STRINGIFY_SEPARATOR = "\u0001"; 41 private static final String ARRAY_STRINGIFY_SEPARATOR = "\u0002"; 42 43 private static final Pattern STRINGIFY_SEPARATOR_PAT = 44 Pattern.compile(Pattern.quote(STRINGIFY_SEPARATOR)); 45 private static final Pattern ARRAY_STRINGIFY_SEPARATOR_PAT = 46 Pattern.compile(Pattern.quote(ARRAY_STRINGIFY_SEPARATOR)); 47 48 public final String dataSet; 49 private final AccountTypeWithDataSet mAccountTypeWithDataSet; 50 51 private static final String[] ID_PROJECTION = new String[] {BaseColumns._ID}; 52 private static final Uri RAW_CONTACTS_URI_LIMIT_1 = RawContacts.CONTENT_URI.buildUpon() 53 .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, "1").build(); 54 55 56 public AccountWithDataSet(String name, String type, String dataSet) { 57 super(name, type); 58 this.dataSet = dataSet; 59 mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet); 60 } 61 62 public AccountWithDataSet(Parcel in) { 63 super(in); 64 this.dataSet = in.readString(); 65 mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet); 66 } 67 68 @Override 69 public void writeToParcel(Parcel dest, int flags) { 70 super.writeToParcel(dest, flags); 71 dest.writeString(dataSet); 72 } 73 74 // For Parcelable 75 public static final Creator<AccountWithDataSet> CREATOR = new Creator<AccountWithDataSet>() { 76 public AccountWithDataSet createFromParcel(Parcel source) { 77 return new AccountWithDataSet(source); 78 } 79 80 public AccountWithDataSet[] newArray(int size) { 81 return new AccountWithDataSet[size]; 82 } 83 }; 84 85 public AccountTypeWithDataSet getAccountTypeWithDataSet() { 86 return mAccountTypeWithDataSet; 87 } 88 89 /** 90 * Return {@code true} if this account has any contacts in the database. 91 * Touches DB. Don't use in the UI thread. 92 */ 93 public boolean hasData(Context context) { 94 final String BASE_SELECTION = 95 RawContacts.ACCOUNT_TYPE + " = ?" + " AND " + RawContacts.ACCOUNT_NAME + " = ?"; 96 final String selection; 97 final String[] args; 98 if (TextUtils.isEmpty(dataSet)) { 99 selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " IS NULL"; 100 args = new String[] {type, name}; 101 } else { 102 selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " = ?"; 103 args = new String[] {type, name, dataSet}; 104 } 105 106 final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1, 107 ID_PROJECTION, selection, args, null); 108 if (c == null) return false; 109 try { 110 return c.moveToFirst(); 111 } finally { 112 c.close(); 113 } 114 } 115 116 @Override 117 public boolean equals(Object o) { 118 return (o instanceof AccountWithDataSet) && super.equals(o) 119 && Objects.equal(((AccountWithDataSet) o).dataSet, dataSet); 120 } 121 122 @Override 123 public int hashCode() { 124 return 31 * super.hashCode() 125 + (dataSet == null ? 0 : dataSet.hashCode()); 126 } 127 128 @Override 129 public String toString() { 130 return "AccountWithDataSet {name=" + name + ", type=" + type + ", dataSet=" + dataSet + "}"; 131 } 132 133 private static StringBuilder addStringified(StringBuilder sb, AccountWithDataSet account) { 134 sb.append(account.name); 135 sb.append(STRINGIFY_SEPARATOR); 136 sb.append(account.type); 137 sb.append(STRINGIFY_SEPARATOR); 138 if (!TextUtils.isEmpty(account.dataSet)) sb.append(account.dataSet); 139 140 return sb; 141 } 142 143 /** 144 * Pack the instance into a string. 145 */ 146 public String stringify() { 147 return addStringified(new StringBuilder(), this).toString(); 148 } 149 150 /** 151 * Unpack a string created by {@link #stringify}. 152 * 153 * @throws IllegalArgumentException if it's an invalid string. 154 */ 155 public static AccountWithDataSet unstringify(String s) { 156 final String[] array = STRINGIFY_SEPARATOR_PAT.split(s, 3); 157 if (array.length < 3) { 158 throw new IllegalArgumentException("Invalid string " + s); 159 } 160 return new AccountWithDataSet(array[0], array[1], 161 TextUtils.isEmpty(array[2]) ? null : array[2]); 162 } 163 164 /** 165 * Pack a list of {@link AccountWithDataSet} into a string. 166 */ 167 public static String stringifyList(List<AccountWithDataSet> accounts) { 168 final StringBuilder sb = new StringBuilder(); 169 170 for (AccountWithDataSet account : accounts) { 171 if (sb.length() > 0) { 172 sb.append(ARRAY_STRINGIFY_SEPARATOR); 173 } 174 addStringified(sb, account); 175 } 176 177 return sb.toString(); 178 } 179 180 /** 181 * Unpack a list of {@link AccountWithDataSet} into a string. 182 * 183 * @throws IllegalArgumentException if it's an invalid string. 184 */ 185 public static List<AccountWithDataSet> unstringifyList(String s) { 186 final ArrayList<AccountWithDataSet> ret = Lists.newArrayList(); 187 if (TextUtils.isEmpty(s)) { 188 return ret; 189 } 190 191 final String[] array = ARRAY_STRINGIFY_SEPARATOR_PAT.split(s); 192 193 for (int i = 0; i < array.length; i++) { 194 ret.add(unstringify(array[i])); 195 } 196 197 return ret; 198 } 199 } 200