1819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott/*
2819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Copyright (C) 2016 The Android Open Source Project
3819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott *
4819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Licensed under the Apache License, Version 2.0 (the "License");
5819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * you may not use this file except in compliance with the License.
6819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * You may obtain a copy of the License at
7819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott *
8819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott *      http://www.apache.org/licenses/LICENSE-2.0
9819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott *
10819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Unless required by applicable law or agreed to in writing, software
11819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * distributed under the License is distributed on an "AS IS" BASIS,
12819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * See the License for the specific language governing permissions and
14819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * limitations under the License.
15819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott */
1669c182afb0e6d82a341a28b4317aa703af768906Gary Maipackage com.android.contacts.model;
17819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
18819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.content.ContentProviderOperation;
19819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.database.MatrixCursor;
20819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.net.Uri;
21819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.os.Parcel;
22819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.os.Parcelable;
23819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.provider.ContactsContract;
24819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.provider.ContactsContract.CommonDataKinds.Email;
25819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.provider.ContactsContract.CommonDataKinds.Phone;
26819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
27a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerottimport android.text.TextUtils;
28819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
290a49afa2ad697307cc04ef4cb86570574fa720f2Gary Maiimport com.android.contacts.ContactPhotoManager;
3069c182afb0e6d82a341a28b4317aa703af768906Gary Maiimport com.android.contacts.model.account.AccountWithDataSet;
310a49afa2ad697307cc04ef4cb86570574fa720f2Gary Mai
322aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerottimport com.google.common.collect.ComparisonChain;
332aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerottimport com.google.common.collect.Ordering;
34819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
35819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport java.util.Arrays;
36819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport java.util.Collection;
372aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerottimport java.util.Collections;
382aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerottimport java.util.Comparator;
39819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottimport java.util.List;
402aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerottimport java.util.Objects;
41819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
42819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott/**
43819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott * Holds data for contacts loaded from the SIM card.
44819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott */
45819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerottpublic class SimContact implements Parcelable {
46819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    private final long mId;
47819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    private final String mName;
48819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    private final String mPhone;
49819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    private final String[] mEmails;
50819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
51a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott    public SimContact(long id, String name, String phone) {
52a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott        this(id, name, phone, null);
53a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott    }
54a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott
55819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public SimContact(long id, String name, String phone, String[] emails) {
562aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        mId = id;
572aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        mName = name;
5819d7ecafdf245ef8895f94b62253bf6dc73f5a17Marcus Hagerott        mPhone = phone == null ? "" : phone.trim();
592aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        mEmails = emails;
602aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
616c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott
62a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott    public SimContact(SimContact other) {
63a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott        this(other.mId, other.mName, other.mPhone, other.mEmails);
64a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott    }
65a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott
66819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public long getId() {
67819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return mId;
68819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
69819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
70819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public String getName() {
71819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return mName;
72819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
73819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
74819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public String getPhone() {
75819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return mPhone;
76819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
77819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
78819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public String[] getEmails() {
79819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return mEmails;
80819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
81819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
82819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public void appendCreateContactOperations(List<ContentProviderOperation> ops,
83819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            AccountWithDataSet targetAccount) {
848e9e782cb7f15a8bcca3335374f641d5a149a5a2Marcus Hagerott        // There is nothing to save so skip it.
858e9e782cb7f15a8bcca3335374f641d5a149a5a2Marcus Hagerott        if (!hasName() && !hasPhone() && !hasEmails()) return;
86819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
87819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        final int rawContactOpIndex = ops.size();
88819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
89819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withYieldAllowed(true)
90819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, targetAccount.name)
91819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, targetAccount.type)
92819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withValue(ContactsContract.RawContacts.DATA_SET, targetAccount.dataSet)
93819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .build());
94819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        if (mName != null) {
95819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            ops.add(createInsertOp(rawContactOpIndex, StructuredName.CONTENT_ITEM_TYPE,
96819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                    StructuredName.DISPLAY_NAME, mName));
97819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        }
9819d7ecafdf245ef8895f94b62253bf6dc73f5a17Marcus Hagerott        if (!mPhone.isEmpty()) {
99819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            ops.add(createInsertOp(rawContactOpIndex, Phone.CONTENT_ITEM_TYPE,
100819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                    Phone.NUMBER, mPhone));
101819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        }
102819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        if (mEmails != null) {
103819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            for (String email : mEmails) {
104819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                ops.add(createInsertOp(rawContactOpIndex, Email.CONTENT_ITEM_TYPE,
105819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                        Email.ADDRESS, email));
106819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            }
107819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        }
108819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
109819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
110819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    private ContentProviderOperation createInsertOp(int rawContactOpIndex, String mimeType,
111819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            String column, String value) {
112819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
113819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactOpIndex)
114819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withValue(ContactsContract.Data.MIMETYPE, mimeType)
115819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .withValue(column, value)
116819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .build();
117819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
118819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
119819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public void appendAsContactRow(MatrixCursor cursor) {
120819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        cursor.newRow().add(ContactsContract.Contacts._ID, mId)
121819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .add(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, mName)
122819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                .add(ContactsContract.Contacts.LOOKUP_KEY, getLookupKey());
123819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
124819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
1252aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    public boolean hasName() {
126a75206b1cba895ce629b9383e4fd0fef24049e7bMarcus Hagerott        return !TextUtils.isEmpty(mName);
1272aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
1282aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott
1292aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    public boolean hasPhone() {
13019d7ecafdf245ef8895f94b62253bf6dc73f5a17Marcus Hagerott        return !mPhone.isEmpty();
1312aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
1322aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott
1332aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    public boolean hasEmails() {
1342aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        return mEmails != null && mEmails.length > 0;
1352aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
1362aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott
137819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    /**
138819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     * Generate a "fake" lookup key. This is needed because
1390a49afa2ad697307cc04ef4cb86570574fa720f2Gary Mai     * {@link ContactPhotoManager} will only generate a letter avatar
140819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     * if the contact has a lookup key.
141819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     */
142819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    private String getLookupKey() {
143819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        if (mName != null) {
144819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            return "sim-n-" + Uri.encode(mName);
145819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        } else if (mPhone != null) {
146819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            return "sim-p-" + Uri.encode(mPhone);
147819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        } else {
148819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            return null;
149819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        }
150819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
151819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
152819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    @Override
153819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public String toString() {
154819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return "SimContact{" +
155819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                "mId=" + mId +
156819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                ", mName='" + mName + '\'' +
157819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                ", mPhone='" + mPhone + '\'' +
158819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                ", mEmails=" + Arrays.toString(mEmails) +
159819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott                '}';
160819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
161819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
162819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    @Override
163819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public boolean equals(Object o) {
164819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        if (this == o) return true;
165819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        if (o == null || getClass() != o.getClass()) return false;
166819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
167819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        final SimContact that = (SimContact) o;
168819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
1696c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        return mId == that.mId && Objects.equals(mName, that.mName) &&
1706c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott                Objects.equals(mPhone, that.mPhone) && Arrays.equals(mEmails, that.mEmails);
171819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
172819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
173819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    @Override
174819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public int hashCode() {
175819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        int result = (int) (mId ^ (mId >>> 32));
176819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        result = 31 * result + (mName != null ? mName.hashCode() : 0);
177819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        result = 31 * result + (mPhone != null ? mPhone.hashCode() : 0);
178819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        result = 31 * result + Arrays.hashCode(mEmails);
179819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return result;
180819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
181819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
182819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    @Override
183819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public int describeContents() {
184819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return 0;
185819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
186819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
187819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    @Override
188819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public void writeToParcel(Parcel dest, int flags) {
189819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        dest.writeLong(mId);
190819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        dest.writeString(mName);
191819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        dest.writeString(mPhone);
192819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        dest.writeStringArray(mEmails);
193819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
194819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
1956c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott    public static final Creator<SimContact> CREATOR = new Creator<SimContact>() {
1966c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        @Override
1976c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        public SimContact createFromParcel(Parcel source) {
1986c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott            final long id = source.readLong();
1996c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott            final String name = source.readString();
2006c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott            final String phone = source.readString();
2016c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott            final String[] emails = source.createStringArray();
2026c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott            return new SimContact(id, name, phone, emails);
2036c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        }
2046c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott
2056c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        @Override
2066c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        public SimContact[] newArray(int size) {
2076c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott            return new SimContact[size];
2086c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        }
2096c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott    };
2106c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott
211819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    /**
212819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     * Convert a collection of SIM contacts to a Cursor matching a query from
213819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     * {@link android.provider.ContactsContract.Contacts#CONTENT_URI} with the provided projection.
214819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     *
215819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     * This allows a collection of SIM contacts to be displayed using the existing adapters for
216819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     * contacts.
217819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott     */
218819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    public static final MatrixCursor convertToContactsCursor(Collection<SimContact> contacts,
219819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            String[] projection) {
220819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        final MatrixCursor result = new MatrixCursor(projection);
221819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        for (SimContact contact : contacts) {
222819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott            contact.appendAsContactRow(result);
223819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        }
224819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott        return result;
225819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott    }
226819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott
2272aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    /**
2282aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott     * Returns the index of a contact with a matching name and phone
2292aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott     * @param contacts list to search. Should be sorted using
2302aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott     * {@link SimContact#compareByPhoneThenName()}
2312aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott     * @param phone the phone to search for
2322aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott     * @param name the name to search for
2332aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott     */
2342aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    public static int findByPhoneAndName(List<SimContact> contacts, String phone, String name) {
2356c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott        return Collections.binarySearch(contacts, new SimContact(-1, name, phone, null),
2366c42b4c3cdfa23031b7cad5d90b68647b75a3948Marcus Hagerott                compareByPhoneThenName());
2372aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
2382aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott
2392aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    public static final Comparator<SimContact> compareByPhoneThenName() {
2402aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        return new Comparator<SimContact>() {
2412aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott            @Override
2422aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott            public int compare(SimContact lhs, SimContact rhs) {
2432aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott                return ComparisonChain.start()
24419d7ecafdf245ef8895f94b62253bf6dc73f5a17Marcus Hagerott                        .compare(lhs.mPhone, rhs.mPhone)
2452aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott                        .compare(lhs.mName, rhs.mName, Ordering.<String>natural().nullsFirst())
2462aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott                        .result();
2472aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott            }
2482aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        };
2492aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
2502aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott
2512aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    public static final Comparator<SimContact> compareById() {
2522aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        return new Comparator<SimContact>() {
2532aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott            @Override
2542aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott            public int compare(SimContact lhs, SimContact rhs) {
2552aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott                // We assume ids are unique.
2562aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott                return Long.compare(lhs.mId, rhs.mId);
2572aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott            }
2582aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott        };
2592aa3198b6881c3272a0295fec85646e7ef2282cfMarcus Hagerott    }
260819214d472fdadf3d69cb4580e238506194ed30eMarcus Hagerott}
261