• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.model;
18 
19 import android.content.ContentValues;
20 import android.content.Context;
21 import android.content.Entity;
22 import android.net.Uri;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 import android.provider.ContactsContract.Contacts;
26 import android.provider.ContactsContract.Data;
27 import android.provider.ContactsContract.RawContacts;
28 
29 import com.android.contacts.common.model.AccountTypeManager;
30 import com.android.contacts.common.model.account.AccountType;
31 import com.android.contacts.common.model.account.AccountWithDataSet;
32 import com.android.contacts.model.dataitem.DataItem;
33 import com.google.common.base.Objects;
34 import com.google.common.collect.Lists;
35 
36 import java.util.ArrayList;
37 import java.util.List;
38 
39 /**
40  * RawContact represents a single raw contact in the raw contacts database.
41  * It has specialized getters/setters for raw contact
42  * items, and also contains a collection of DataItem objects.  A RawContact contains the information
43  * from a single account.
44  *
45  * This allows RawContact objects to be thought of as a class with raw contact
46  * fields (like account type, name, data set, sync state, etc.) and a list of
47  * DataItem objects that represent contact information elements (like phone
48  * numbers, email, address, etc.).
49  */
50 final public class RawContact implements Parcelable {
51 
52     private AccountTypeManager mAccountTypeManager;
53     private final ContentValues mValues;
54     private final ArrayList<NamedDataItem> mDataItems;
55 
56     final public static class NamedDataItem implements Parcelable {
57         public final Uri mUri;
58 
59         // This use to be a DataItem. DataItem creation is now delayed until the point of request
60         // since there is no benefit to storing them here due to the multiple inheritance.
61         // Eventually instanceof still has to be used anyways to determine which sub-class of
62         // DataItem it is. And having parent DataItem's here makes it very difficult to serialize or
63         // parcelable.
64         //
65         // Instead of having a common DataItem super class, we should refactor this to be a generic
66         // Object where the object is a concrete class that no longer relies on ContentValues.
67         // (this will also make the classes easier to use).
68         // Since instanceof is used later anyways, having a list of Objects won't hurt and is no
69         // worse than having a DataItem.
70         public final ContentValues mContentValues;
71 
NamedDataItem(Uri uri, ContentValues values)72         public NamedDataItem(Uri uri, ContentValues values) {
73             this.mUri = uri;
74             this.mContentValues = values;
75         }
76 
NamedDataItem(Parcel parcel)77         public NamedDataItem(Parcel parcel) {
78             this.mUri = parcel.readParcelable(Uri.class.getClassLoader());
79             this.mContentValues = parcel.readParcelable(ContentValues.class.getClassLoader());
80         }
81 
82         @Override
describeContents()83         public int describeContents() {
84             return 0;
85         }
86 
87         @Override
writeToParcel(Parcel parcel, int i)88         public void writeToParcel(Parcel parcel, int i) {
89             parcel.writeParcelable(mUri, i);
90             parcel.writeParcelable(mContentValues, i);
91         }
92 
93         public static final Parcelable.Creator<NamedDataItem> CREATOR
94                 = new Parcelable.Creator<NamedDataItem>() {
95 
96             @Override
97             public NamedDataItem createFromParcel(Parcel parcel) {
98                 return new NamedDataItem(parcel);
99             }
100 
101             @Override
102             public NamedDataItem[] newArray(int i) {
103                 return new NamedDataItem[i];
104             }
105         };
106 
107         @Override
hashCode()108         public int hashCode() {
109             return Objects.hashCode(mUri, mContentValues);
110         }
111 
112         @Override
equals(Object obj)113         public boolean equals(Object obj) {
114             if (obj == null) return false;
115             if (getClass() != obj.getClass()) return false;
116 
117             final NamedDataItem other = (NamedDataItem) obj;
118             return Objects.equal(mUri, other.mUri) &&
119                     Objects.equal(mContentValues, other.mContentValues);
120         }
121     }
122 
createFrom(Entity entity)123     public static RawContact createFrom(Entity entity) {
124         final ContentValues values = entity.getEntityValues();
125         final ArrayList<Entity.NamedContentValues> subValues = entity.getSubValues();
126 
127         RawContact rawContact = new RawContact(values);
128         for (Entity.NamedContentValues subValue : subValues) {
129             rawContact.addNamedDataItemValues(subValue.uri, subValue.values);
130         }
131         return rawContact;
132     }
133 
134     /**
135      * A RawContact object can be created with or without a context.
136      */
RawContact()137     public RawContact() {
138         this(new ContentValues());
139     }
140 
RawContact(ContentValues values)141     public RawContact(ContentValues values) {
142         mValues = values;
143         mDataItems = new ArrayList<NamedDataItem>();
144     }
145 
146     /**
147      * Constructor for the parcelable.
148      *
149      * @param parcel The parcel to de-serialize from.
150      */
RawContact(Parcel parcel)151     private RawContact(Parcel parcel) {
152         mValues = parcel.readParcelable(ContentValues.class.getClassLoader());
153         mDataItems = Lists.newArrayList();
154         parcel.readTypedList(mDataItems, NamedDataItem.CREATOR);
155     }
156 
157     @Override
describeContents()158     public int describeContents() {
159         return 0;
160     }
161 
162     @Override
writeToParcel(Parcel parcel, int i)163     public void writeToParcel(Parcel parcel, int i) {
164         parcel.writeParcelable(mValues, i);
165         parcel.writeTypedList(mDataItems);
166     }
167 
168     /**
169      * Create for building the parcelable.
170      */
171     public static final Parcelable.Creator<RawContact> CREATOR
172             = new Parcelable.Creator<RawContact>() {
173 
174         @Override
175         public RawContact createFromParcel(Parcel parcel) {
176             return new RawContact(parcel);
177         }
178 
179         @Override
180         public RawContact[] newArray(int i) {
181             return new RawContact[i];
182         }
183     };
184 
getAccountTypeManager(Context context)185     public AccountTypeManager getAccountTypeManager(Context context) {
186         if (mAccountTypeManager == null) {
187             mAccountTypeManager = AccountTypeManager.getInstance(context);
188         }
189         return mAccountTypeManager;
190     }
191 
getValues()192     public ContentValues getValues() {
193         return mValues;
194     }
195 
196     /**
197      * Returns the id of the raw contact.
198      */
getId()199     public Long getId() {
200         return getValues().getAsLong(RawContacts._ID);
201     }
202 
203     /**
204      * Returns the account name of the raw contact.
205      */
getAccountName()206     public String getAccountName() {
207         return getValues().getAsString(RawContacts.ACCOUNT_NAME);
208     }
209 
210     /**
211      * Returns the account type of the raw contact.
212      */
getAccountTypeString()213     public String getAccountTypeString() {
214         return getValues().getAsString(RawContacts.ACCOUNT_TYPE);
215     }
216 
217     /**
218      * Returns the data set of the raw contact.
219      */
getDataSet()220     public String getDataSet() {
221         return getValues().getAsString(RawContacts.DATA_SET);
222     }
223 
224     /**
225      * Returns the account type and data set of the raw contact.
226      */
getAccountTypeAndDataSetString()227     public String getAccountTypeAndDataSetString() {
228         return getValues().getAsString(RawContacts.ACCOUNT_TYPE_AND_DATA_SET);
229     }
230 
isDirty()231     public boolean isDirty() {
232         return getValues().getAsBoolean(RawContacts.DIRTY);
233     }
234 
getVersion()235     public long getVersion() {
236         return getValues().getAsLong(RawContacts.DIRTY);
237     }
238 
getSourceId()239     public String getSourceId() {
240         return getValues().getAsString(RawContacts.SOURCE_ID);
241     }
242 
getSync1()243     public String getSync1() {
244         return getValues().getAsString(RawContacts.SYNC1);
245     }
246 
getSync2()247     public String getSync2() {
248         return getValues().getAsString(RawContacts.SYNC2);
249     }
250 
getSync3()251     public String getSync3() {
252         return getValues().getAsString(RawContacts.SYNC3);
253     }
254 
getSync4()255     public String getSync4() {
256         return getValues().getAsString(RawContacts.SYNC4);
257     }
258 
isDeleted()259     public boolean isDeleted() {
260         return getValues().getAsBoolean(RawContacts.DELETED);
261     }
262 
isNameVerified()263     public boolean isNameVerified() {
264         return getValues().getAsBoolean(RawContacts.NAME_VERIFIED);
265     }
266 
getContactId()267     public long getContactId() {
268         return getValues().getAsLong(Contacts.Entity.CONTACT_ID);
269     }
270 
isStarred()271     public boolean isStarred() {
272         return getValues().getAsBoolean(Contacts.STARRED);
273     }
274 
getAccountType(Context context)275     public AccountType getAccountType(Context context) {
276         return getAccountTypeManager(context).getAccountType(getAccountTypeString(), getDataSet());
277     }
278 
279     /**
280      * Sets the account name, account type, and data set strings.
281      * Valid combinations for account-name, account-type, data-set
282      * 1) null, null, null (local account)
283      * 2) non-null, non-null, null (valid account without data-set)
284      * 3) non-null, non-null, non-null (valid account with data-set)
285      */
setAccount(String accountName, String accountType, String dataSet)286     private void setAccount(String accountName, String accountType, String dataSet) {
287         final ContentValues values = getValues();
288         if (accountName == null) {
289             if (accountType == null && dataSet == null) {
290                 // This is a local account
291                 values.putNull(RawContacts.ACCOUNT_NAME);
292                 values.putNull(RawContacts.ACCOUNT_TYPE);
293                 values.putNull(RawContacts.DATA_SET);
294                 return;
295             }
296         } else {
297             if (accountType != null) {
298                 // This is a valid account, either with or without a dataSet.
299                 values.put(RawContacts.ACCOUNT_NAME, accountName);
300                 values.put(RawContacts.ACCOUNT_TYPE, accountType);
301                 if (dataSet == null) {
302                     values.putNull(RawContacts.DATA_SET);
303                 } else {
304                     values.put(RawContacts.DATA_SET, dataSet);
305                 }
306                 return;
307             }
308         }
309         throw new IllegalArgumentException(
310                 "Not a valid combination of account name, type, and data set.");
311     }
312 
setAccount(AccountWithDataSet accountWithDataSet)313     public void setAccount(AccountWithDataSet accountWithDataSet) {
314         setAccount(accountWithDataSet.name, accountWithDataSet.type, accountWithDataSet.dataSet);
315     }
316 
setAccountToLocal()317     public void setAccountToLocal() {
318         setAccount(null, null, null);
319     }
320 
321     /**
322      * Creates and inserts a DataItem object that wraps the content values, and returns it.
323      */
addDataItemValues(ContentValues values)324     public void addDataItemValues(ContentValues values) {
325         addNamedDataItemValues(Data.CONTENT_URI, values);
326     }
327 
addNamedDataItemValues(Uri uri, ContentValues values)328     public NamedDataItem addNamedDataItemValues(Uri uri, ContentValues values) {
329         final NamedDataItem namedItem = new NamedDataItem(uri, values);
330         mDataItems.add(namedItem);
331         return namedItem;
332     }
333 
getContentValues()334     public ArrayList<ContentValues> getContentValues() {
335         final ArrayList<ContentValues> list = Lists.newArrayListWithCapacity(mDataItems.size());
336         for (NamedDataItem dataItem : mDataItems) {
337             if (Data.CONTENT_URI.equals(dataItem.mUri)) {
338                 list.add(dataItem.mContentValues);
339             }
340         }
341         return list;
342     }
343 
getDataItems()344     public List<DataItem> getDataItems() {
345         final ArrayList<DataItem> list = Lists.newArrayListWithCapacity(mDataItems.size());
346         for (NamedDataItem dataItem : mDataItems) {
347             if (Data.CONTENT_URI.equals(dataItem.mUri)) {
348                 list.add(DataItem.createFrom(dataItem.mContentValues));
349             }
350         }
351         return list;
352     }
353 
toString()354     public String toString() {
355         final StringBuilder sb = new StringBuilder();
356         sb.append("RawContact: ").append(mValues);
357         for (RawContact.NamedDataItem namedDataItem : mDataItems) {
358             sb.append("\n  ").append(namedDataItem.mUri);
359             sb.append("\n  -> ").append(namedDataItem.mContentValues);
360         }
361         return sb.toString();
362     }
363 
364     @Override
hashCode()365     public int hashCode() {
366         return Objects.hashCode(mValues, mDataItems);
367     }
368 
369     @Override
equals(Object obj)370     public boolean equals(Object obj) {
371         if (obj == null) return false;
372         if (getClass() != obj.getClass()) return false;
373 
374         RawContact other = (RawContact) obj;
375         return Objects.equal(mValues, other.mValues) &&
376                 Objects.equal(mDataItems, other.mDataItems);
377     }
378 }
379