1/*
2 * Copyright (C) 2015 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 */
16package com.android.car.dialer;
17
18import android.content.Context;
19import android.database.Cursor;
20import android.provider.ContactsContract;
21import android.support.annotation.Nullable;
22import android.text.TextUtils;
23import android.util.Log;
24
25import com.android.car.dialer.telecom.PhoneLoader;
26import com.android.car.dialer.telecom.TelecomUtils;
27
28/**
29 * Encapsulates data about a phone Contact entry. Typically loaded from the local Contact store.
30 */
31// TODO: Refactor to use Builder design pattern.
32public class ContactEntry implements Comparable<ContactEntry> {
33    private final Context mContext;
34
35    /**
36     * An unique primary key for searching an entry.
37     */
38    private int mId;
39
40    /**
41     * Whether this contact entry is starred by user.
42     */
43    private boolean mIsStarred;
44
45    /**
46     * Contact-specific information about whether or not a contact has been pinned by the user at
47     * a particular position within the system contact application's user interface.
48     */
49    private int mPinnedPosition;
50
51    /**
52     * Phone number.
53     */
54    private String mNumber;
55
56    /**
57     * The display name.
58     */
59    @Nullable
60    private String mDisplayName;
61
62    /**
63     * A URI that can be used to retrieve a thumbnail of the contact's photo.
64     */
65    private String mAvatarThumbnailUri;
66
67    /**
68     * A URI that can be used to retrieve the contact's full-size photo.
69     */
70    private String mAvatarUri;
71
72    /**
73     * An opaque value that contains hints on how to find the contact if its row id changed
74     * as a result of a sync or aggregation
75     */
76    private String mLookupKey;
77
78    /**
79     * The type of data, for example Home or Work.
80     */
81    private int mType;
82
83    /**
84     * The user defined label for the the contact method.
85     */
86    private String mLabel;
87
88    /**
89     * Parses a Contact entry for a Cursor loaded from the OS Strequents DB.
90     */
91    public static ContactEntry fromCursor(Cursor cursor, Context context) {
92        int idColumnIndex = PhoneLoader.getIdColumnIndex(cursor);
93        int starredColumn = cursor.getColumnIndex(ContactsContract.Contacts.STARRED);
94        int pinnedColumn = cursor.getColumnIndex("pinned");
95        int displayNameColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
96        int avatarUriColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.PHOTO_URI);
97        int avatarThumbnailColumnIndex = cursor.getColumnIndex(
98                ContactsContract.Contacts.PHOTO_THUMBNAIL_URI);
99        int lookupKeyColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY);
100        int typeColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA2);
101        int labelColumnIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA3);
102
103        String name = cursor.getString(displayNameColumnIndex);
104        String number = PhoneLoader.getPhoneNumber(cursor, context.getContentResolver());
105        int starred = cursor.getInt(starredColumn);
106        int pinnedPosition = cursor.getInt(pinnedColumn);
107        ContactEntry contactEntry = new ContactEntry(context, name, number, starred > 0,
108                pinnedPosition);
109        contactEntry.setId(cursor.getInt(idColumnIndex));
110        contactEntry.setAvatarUri(cursor.getString(avatarUriColumnIndex));
111        contactEntry.setAvatarThumbnailUri(cursor.getString(avatarThumbnailColumnIndex));
112        contactEntry.setLookupKey(cursor.getString(lookupKeyColumnIndex));
113        contactEntry.setType(cursor.getInt(typeColumnIndex));
114        contactEntry.setLabel(cursor.getString(labelColumnIndex));
115        return contactEntry;
116    }
117
118    public ContactEntry(
119            Context context, String name, String number, boolean isStarred, int pinnedPosition) {
120        mContext = context;
121        this.mDisplayName = name;
122        this.mNumber = number;
123        this.mIsStarred = isStarred;
124        this.mPinnedPosition = pinnedPosition;
125    }
126
127    /**
128     * Retrieves a best-effort contact name ready for display to the user.
129     * It takes into account the number associated with a name for fail cases.
130     */
131    public String getDisplayName() {
132        if (!TextUtils.isEmpty(mDisplayName)) {
133            return mDisplayName;
134        }
135        if (isVoicemail()) {
136            return mContext.getResources().getString(R.string.voicemail);
137        } else {
138            String displayName = TelecomUtils.getFormattedNumber(mContext, mNumber);
139            if (TextUtils.isEmpty(displayName)) {
140                displayName = mContext.getString(R.string.unknown);
141            }
142            return displayName;
143        }
144    }
145
146    public boolean isVoicemail() {
147        return mNumber.equals(TelecomUtils.getVoicemailNumber(mContext));
148    }
149
150    @Override
151    public int compareTo(ContactEntry strequentContactEntry) {
152        if (mIsStarred == strequentContactEntry.mIsStarred) {
153            if (mPinnedPosition == strequentContactEntry.mPinnedPosition) {
154                if (mDisplayName == strequentContactEntry.mDisplayName) {
155                    return compare(mNumber, strequentContactEntry.mNumber);
156                }
157                return compare(mDisplayName, strequentContactEntry.mDisplayName);
158            } else {
159                if (mPinnedPosition > 0 && strequentContactEntry.mPinnedPosition > 0) {
160                    return mPinnedPosition - strequentContactEntry.mPinnedPosition;
161                }
162
163                if (mPinnedPosition > 0) {
164                    return -1;
165                }
166
167                return 1;
168            }
169        }
170
171        if (mIsStarred) {
172            return -1;
173        }
174
175        return 1;
176    }
177
178    @Override
179    public boolean equals(Object obj) {
180        if (obj instanceof ContactEntry) {
181            ContactEntry other = (ContactEntry) obj;
182            if (compare(mDisplayName, other.mDisplayName) == 0
183                    && compare(mNumber, other.mNumber) == 0
184                    && mIsStarred == other.mIsStarred
185                    && mPinnedPosition == other.mPinnedPosition) {
186                return true;
187            }
188        }
189        return false;
190    }
191
192    @Override
193    public int hashCode() {
194        int result = 17;
195        result = 31 * result + (mIsStarred ? 1 : 0);
196        result = 31 * result + mPinnedPosition;
197        result = 31 * result + (mDisplayName == null ? 0 : mDisplayName.hashCode());
198        result = 31 * result + (mNumber == null ? 0 : mNumber.hashCode());
199        return result;
200    }
201
202    private int compare(final String one, final String two) {
203        if (one == null ^ two == null) {
204            return (one == null) ? -1 : 1;
205        }
206
207        if (one == null && two == null) {
208            return 0;
209        }
210
211        return one.compareTo(two);
212    }
213
214    public int getId() {
215        return mId;
216    }
217
218    private void setId(int id) {
219        mId = id;
220    }
221
222    public String getAvatarUri() {
223        return mAvatarUri;
224    }
225
226    private void setAvatarUri(String avatarUri) {
227        mAvatarUri = avatarUri;
228    }
229
230    public String getLookupKey() {
231        return mLookupKey;
232    }
233
234    private void setLookupKey(String lookupKey) {
235        mLookupKey = lookupKey;
236    }
237
238    public int getType() {
239        return mType;
240    }
241
242    private void setType(int type) {
243        mType = type;
244    }
245
246    public String getLabel() {
247        return mLabel;
248    }
249
250    private void setLabel(String label) {
251        mLabel = label;
252    }
253
254    public String getAvatarThumbnailUri() {
255        return mAvatarThumbnailUri;
256    }
257
258    private void setAvatarThumbnailUri(String avatarThumbnailUri) {
259        mAvatarThumbnailUri = avatarThumbnailUri;
260    }
261
262    public String getNumber() {
263        return mNumber;
264    }
265
266    public boolean isStarred() {
267        return mIsStarred;
268    }
269
270    public int getPinnedPosition() {
271        return mPinnedPosition;
272    }
273
274}
275