12b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro/* 22b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * Copyright (C) 2011 The Android Open Source Project 32b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * 42b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * Licensed under the Apache License, Version 2.0 (the "License"); 52b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * you may not use this file except in compliance with the License. 62b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * You may obtain a copy of the License at 72b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * 82b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * http://www.apache.org/licenses/LICENSE-2.0 92b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * 102b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * Unless required by applicable law or agreed to in writing, software 112b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * distributed under the License is distributed on an "AS IS" BASIS, 122b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * See the License for the specific language governing permissions and 142b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * limitations under the License. 152b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro */ 162b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 172b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoropackage com.android.contacts.model; 182b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 192b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoroimport com.android.internal.util.Objects; 20558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport com.google.common.collect.Lists; 212b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 222b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoroimport android.accounts.Account; 233ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.content.Context; 243ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.database.Cursor; 253ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.net.Uri; 262b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoroimport android.os.Parcel; 27558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport android.os.Parcelable.Creator; 283ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.provider.BaseColumns; 293ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.provider.ContactsContract; 303ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.provider.ContactsContract.RawContacts; 313ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onukiimport android.text.TextUtils; 322b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 33558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport java.util.ArrayList; 34558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport java.util.List; 35558669dab4109afebd19eade1f95a396215fb44dMakoto Onukiimport java.util.regex.Pattern; 36558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 372b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro/** 382b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro * Wrapper for an account that includes a data set (which may be null). 392b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro */ 402b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoropublic class AccountWithDataSet extends Account { 41558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki private static final String STRINGIFY_SEPARATOR = "\u0001"; 42558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki private static final String ARRAY_STRINGIFY_SEPARATOR = "\u0002"; 43558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 44558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki private static final Pattern STRINGIFY_SEPARATOR_PAT = 45558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki Pattern.compile(Pattern.quote(STRINGIFY_SEPARATOR)); 46558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki private static final Pattern ARRAY_STRINGIFY_SEPARATOR_PAT = 47558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki Pattern.compile(Pattern.quote(ARRAY_STRINGIFY_SEPARATOR)); 482b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 492b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public final String dataSet; 506ad227f990265254864a04d3289292ca42330c71Makoto Onuki private final AccountTypeWithDataSet mAccountTypeWithDataSet; 512b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 523ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki private static final String[] ID_PROJECTION = new String[] {BaseColumns._ID}; 533ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki private static final Uri RAW_CONTACTS_URI_LIMIT_1 = RawContacts.CONTENT_URI.buildUpon() 543ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY, "1").build(); 553ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki 563ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki 572b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public AccountWithDataSet(String name, String type, String dataSet) { 582b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro super(name, type); 592b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro this.dataSet = dataSet; 606ad227f990265254864a04d3289292ca42330c71Makoto Onuki mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet); 612b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 622b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 63558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public AccountWithDataSet(Parcel in) { 642b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro super(in); 65558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki this.dataSet = in.readString(); 666ad227f990265254864a04d3289292ca42330c71Makoto Onuki mAccountTypeWithDataSet = AccountTypeWithDataSet.get(type, dataSet); 672b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 682b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 69558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki @Override 70558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public void writeToParcel(Parcel dest, int flags) { 71558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki super.writeToParcel(dest, flags); 72558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki dest.writeString(dataSet); 73558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 74558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 75558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki // For Parcelable 76558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public static final Creator<AccountWithDataSet> CREATOR = new Creator<AccountWithDataSet>() { 77558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public AccountWithDataSet createFromParcel(Parcel source) { 78558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return new AccountWithDataSet(source); 79558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 80558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 81558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public AccountWithDataSet[] newArray(int size) { 82558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return new AccountWithDataSet[size]; 83558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 84558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki }; 85558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 863ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki public AccountTypeWithDataSet getAccountTypeWithDataSet() { 876ad227f990265254864a04d3289292ca42330c71Makoto Onuki return mAccountTypeWithDataSet; 882b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 892b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 903ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki /** 913ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki * Return {@code true} if this account has any contacts in the database. 923ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki * Touches DB. Don't use in the UI thread. 933ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki */ 943ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki public boolean hasData(Context context) { 953ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki final String BASE_SELECTION = 963ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki RawContacts.ACCOUNT_TYPE + " = ?" + " AND " + RawContacts.ACCOUNT_NAME + " = ?"; 973ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki final String selection; 983ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki final String[] args; 993ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki if (TextUtils.isEmpty(dataSet)) { 1003ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " IS NULL"; 1013ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki args = new String[] {type, name}; 1023ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki } else { 1033ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki selection = BASE_SELECTION + " AND " + RawContacts.DATA_SET + " = ?"; 1043ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki args = new String[] {type, name, dataSet}; 1053ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki } 1063ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki 1073ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1, 1083ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki ID_PROJECTION, selection, args, null); 1093ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki if (c == null) return false; 1103ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki try { 1113ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki return c.moveToFirst(); 1123ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki } finally { 1133ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki c.close(); 1143ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki } 1153ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki } 1163ae114e72617f2faea281d82f7f4ee026d8c5674Makoto Onuki 1172b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro @Override 1182b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public boolean equals(Object o) { 1192b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro return (o instanceof AccountWithDataSet) && super.equals(o) 1202b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro && Objects.equal(((AccountWithDataSet) o).dataSet, dataSet); 1212b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 1222b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 1232b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro @Override 1242b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public int hashCode() { 1252b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro return 31 * super.hashCode() 1262b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro + (dataSet == null ? 0 : dataSet.hashCode()); 1272b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 1282b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro 1292b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro @Override 1302b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro public String toString() { 1312b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro return "AccountWithDataSet {name=" + name + ", type=" + type + ", dataSet=" + dataSet + "}"; 1322b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro } 133558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 134558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki private static StringBuilder addStringified(StringBuilder sb, AccountWithDataSet account) { 135558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki sb.append(account.name); 136558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki sb.append(STRINGIFY_SEPARATOR); 137558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki sb.append(account.type); 138558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki sb.append(STRINGIFY_SEPARATOR); 139558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki if (!TextUtils.isEmpty(account.dataSet)) sb.append(account.dataSet); 140558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 141558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return sb; 142558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 143558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 144558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki /** 145558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Pack the instance into a string. 146558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki */ 147558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public String stringify() { 148558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return addStringified(new StringBuilder(), this).toString(); 149558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 150558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 151558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki /** 152558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Unpack a string created by {@link #stringify}. 153131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki * 154131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki * @throws IllegalArgumentException if it's an invalid string. 155558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki */ 156558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public static AccountWithDataSet unstringify(String s) { 157558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki final String[] array = STRINGIFY_SEPARATOR_PAT.split(s, 3); 158558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki if (array.length < 3) { 159131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki throw new IllegalArgumentException("Invalid string " + s); 160558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 161558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return new AccountWithDataSet(array[0], array[1], 162558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki TextUtils.isEmpty(array[2]) ? null : array[2]); 163558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 164558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 165558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki /** 166558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Pack a list of {@link AccountWithDataSet} into a string. 167558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki */ 168558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public static String stringifyList(List<AccountWithDataSet> accounts) { 169558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki final StringBuilder sb = new StringBuilder(); 170558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 171558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki for (AccountWithDataSet account : accounts) { 172558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki if (sb.length() > 0) { 173558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki sb.append(ARRAY_STRINGIFY_SEPARATOR); 174558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 175558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki addStringified(sb, account); 176558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 177558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 178558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return sb.toString(); 179558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 180558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 181558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki /** 182558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki * Unpack a list of {@link AccountWithDataSet} into a string. 183131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki * 184131e6ac666868645b48ae6932575d85751ff57c0Makoto Onuki * @throws IllegalArgumentException if it's an invalid string. 185558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki */ 186558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki public static List<AccountWithDataSet> unstringifyList(String s) { 187558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki final ArrayList<AccountWithDataSet> ret = Lists.newArrayList(); 188558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki if (TextUtils.isEmpty(s)) { 189558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return ret; 190558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 191558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 192558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki final String[] array = ARRAY_STRINGIFY_SEPARATOR_PAT.split(s); 193558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 194558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki for (int i = 0; i < array.length; i++) { 195558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki ret.add(unstringify(array[i])); 196558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 197558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki 198558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki return ret; 199558669dab4109afebd19eade1f95a396215fb44dMakoto Onuki } 2002b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro} 201