15aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank/* 25aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * Copyright (C) 2010 The Android Open Source Project 35aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * 45aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 55aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * you may not use this file except in compliance with the License. 65aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * You may obtain a copy of the License at 75aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * 85aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * http://www.apache.org/licenses/LICENSE-2.0 95aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * 105aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * Unless required by applicable law or agreed to in writing, software 115aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * distributed under the License is distributed on an "AS IS" BASIS, 125aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * See the License for the specific language governing permissions and 145aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * limitations under the License. 155aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank */ 165aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 175aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankpackage com.android.exchange.provider; 185aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 191f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikovimport android.accounts.AccountManager; 205aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.ContentProvider; 215aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.ContentValues; 227307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blankimport android.content.Context; 235aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.UriMatcher; 245aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.database.Cursor; 255aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.database.MatrixCursor; 265aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.net.Uri; 275aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.os.Binder; 28c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.os.Bundle; 29469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blankimport android.provider.ContactsContract; 30d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 31d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 32d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 33c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.provider.ContactsContract.Contacts; 34d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.Data; 35c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.provider.ContactsContract.Directory; 36222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport android.provider.ContactsContract.DisplayNameSources; 37c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.provider.ContactsContract.RawContacts; 38d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.text.TextUtils; 39e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shraunerimport android.util.Log; 40e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shraunerimport android.util.Pair; 41d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 426ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.Configuration; 436ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.mail.PackedString; 446ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.provider.Account; 456ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.provider.EmailContent; 466ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.provider.EmailContent.AccountColumns; 476ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.service.AccountServiceProxy; 486ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.emailcommon.utility.Utility; 496ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.exchange.Eas; 506ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.exchange.R; 516ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.exchange.provider.GalResult.GalData; 52bb0141b49e7eff978fa445249dc888461ea581e3Martin Hibdonimport com.android.exchange.service.EasService; 536ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.mail.utils.LogUtils; 546ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albert 55222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport java.text.Collator; 56222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport java.util.ArrayList; 57222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport java.util.Comparator; 58d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport java.util.HashMap; 59222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport java.util.HashSet; 60d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport java.util.List; 61222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport java.util.Set; 62222dec5216626980f1450d8917e9b73e2d4c9040Alon Albertimport java.util.TreeMap; 635aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 645aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank/** 655aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * ExchangeDirectoryProvider provides real-time data from the Exchange server; at the moment, it is 665aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * used solely to provide GAL (Global Address Lookup) service to email address adapters 675aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank */ 685aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankpublic class ExchangeDirectoryProvider extends ContentProvider { 696ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albert private static final String TAG = Eas.LOG_TAG; 706ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albert 712bf91acb8174aab82582ce975a4b60702c810a9cMarc Blank public static final String EXCHANGE_GAL_AUTHORITY = 722bf91acb8174aab82582ce975a4b60702c810a9cMarc Blank com.android.exchange.Configuration.EXCHANGE_GAL_AUTHORITY; 735aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 74d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov private static final int DEFAULT_CONTACT_ID = 1; 75e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 76469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank private static final int DEFAULT_LOOKUP_LIMIT = 20; 77e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner private static final int MAX_LOOKUP_LIMIT = 100; 78d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 795aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank private static final int GAL_BASE = 0; 801f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_DIRECTORIES = GAL_BASE; 811f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_FILTER = GAL_BASE + 1; 821f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_CONTACT = GAL_BASE + 2; 831f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_CONTACT_WITH_ID = GAL_BASE + 3; 84f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov private static final int GAL_EMAIL_FILTER = GAL_BASE + 4; 85222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private static final int GAL_PHONE_FILTER = GAL_BASE + 5; 865aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 877f29df6b105b1b7fe83713245a680d151fd32887Marc Blank private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 887307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank /*package*/ final HashMap<String, Long> mAccountIdMap = new HashMap<String, Long>(); 895aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 907f29df6b105b1b7fe83713245a680d151fd32887Marc Blank static { 917f29df6b105b1b7fe83713245a680d151fd32887Marc Blank sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "directories", GAL_DIRECTORIES); 927f29df6b105b1b7fe83713245a680d151fd32887Marc Blank sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/filter/*", GAL_FILTER); 937f29df6b105b1b7fe83713245a680d151fd32887Marc Blank sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/lookup/*/entities", GAL_CONTACT); 947f29df6b105b1b7fe83713245a680d151fd32887Marc Blank sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/lookup/*/#/entities", 957f29df6b105b1b7fe83713245a680d151fd32887Marc Blank GAL_CONTACT_WITH_ID); 967f29df6b105b1b7fe83713245a680d151fd32887Marc Blank sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "data/emails/filter/*", GAL_EMAIL_FILTER); 97222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "data/phones/filter/*", GAL_PHONE_FILTER); 98222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 997f29df6b105b1b7fe83713245a680d151fd32887Marc Blank } 1007f29df6b105b1b7fe83713245a680d151fd32887Marc Blank 1015aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 1025aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public boolean onCreate() { 10388e51a3c990658e8b104881cb9d6c6a8d488a8a6Tony Mantler EmailContent.init(getContext()); 1045aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return true; 1055aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 1065aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 107d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static class GalProjection { 108d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov final int size; 109d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov final HashMap<String, Integer> columnMap = new HashMap<String, Integer>(); 110d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 111d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalProjection(String[] projection) { 112d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov size = projection.length; 113d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 114d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov columnMap.put(projection[i], i); 115d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 116d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 117d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 118d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 119d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static class GalContactRow { 120d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov private final GalProjection mProjection; 121d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov private Object[] row; 122d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static long dataId = 1; 123d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 12456d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy GalContactRow(GalProjection projection, long contactId, String accountName, 12556d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy String displayName) { 126d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov this.mProjection = projection; 127d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row = new Object[projection.size]; 128d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 129d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.Entity.CONTACT_ID, contactId); 130d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 131d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // We only have one raw contact per aggregate, so they can have the same ID 132d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.Entity.RAW_CONTACT_ID, contactId); 133d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.Entity.DATA_ID, dataId++); 134d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 135d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.DISPLAY_NAME, displayName); 136d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 137d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // TODO alternative display name 138d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.DISPLAY_NAME_ALTERNATIVE, displayName); 139d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 140c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank put(RawContacts.ACCOUNT_TYPE, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE); 141d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(RawContacts.ACCOUNT_NAME, accountName); 142d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 143d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Data.IS_READ_ONLY, 1); 144d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 145d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 146d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov Object[] getRow () { 147d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov return row; 148d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 149d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 150d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov void put(String columnName, Object value) { 151222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final Integer integer = mProjection.columnMap.get(columnName); 152d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (integer != null) { 153d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[integer] = value; 154d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else { 1556ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albert LogUtils.e(TAG, "Unsupported column: " + columnName); 156d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 157d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 158d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 159d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static void addEmailAddress(MatrixCursor cursor, GalProjection galProjection, 16056d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy long contactId, String accountName, String displayName, String address) { 161d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (!TextUtils.isEmpty(address)) { 162222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final GalContactRow r = new GalContactRow( 16356d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy galProjection, contactId, accountName, displayName); 164d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 165d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Email.TYPE, Email.TYPE_WORK); 166d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Email.ADDRESS, address); 167d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor.addRow(r.getRow()); 168d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 169d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 170d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 171d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static void addPhoneRow(MatrixCursor cursor, GalProjection projection, long contactId, 17256d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy String accountName, String displayName, int type, String number) { 173d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 174222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final GalContactRow r = new GalContactRow( 17556d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy projection, contactId, accountName, displayName); 176d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 177d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Phone.TYPE, type); 178d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Phone.NUMBER, number); 179d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor.addRow(r.getRow()); 180d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 181d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 182d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 183d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov public static void addNameRow(MatrixCursor cursor, GalProjection galProjection, 18456d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy long contactId, String accountName, String displayName, 185d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String firstName, String lastName) { 186222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final GalContactRow r = new GalContactRow( 18756d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy galProjection, contactId, accountName, displayName); 188d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 189d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(StructuredName.GIVEN_NAME, firstName); 190d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(StructuredName.FAMILY_NAME, lastName); 191d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(StructuredName.DISPLAY_NAME, displayName); 192d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor.addRow(r.getRow()); 193d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 194d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 195d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 1967307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank /** 1977307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank * Find the record id of an Account, given its name (email address) 1987307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank * @param accountName the name of the account 1997307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank * @return the record id of the Account, or -1 if not found 2007307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank */ 2017307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank /*package*/ long getAccountIdByName(Context context, String accountName) { 2027307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank Long accountId = mAccountIdMap.get(accountName); 2037307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank if (accountId == null) { 2047307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank accountId = Utility.getFirstRowLong(context, Account.CONTENT_URI, 2057307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank EmailContent.ID_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?", 2067307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank new String[] {accountName}, null, EmailContent.ID_PROJECTION_COLUMN , -1L); 2077307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank if (accountId != -1) { 2087307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank mAccountIdMap.put(accountName, accountId); 2097307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank } 2107307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank } 2117307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank return accountId; 2127307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank } 2137307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank 2145aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 2155aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 2165aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank String sortOrder) { 2176ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albert LogUtils.d(TAG, "ExchangeDirectoryProvider: query: %s", uri.toString()); 218222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final int match = sURIMatcher.match(uri); 219222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final MatrixCursor cursor; 220d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov Object[] row; 221222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final PackedString ps; 222222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String lookupKey; 223d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 2245aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank switch (match) { 2251f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov case GAL_DIRECTORIES: { 2261f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov // Assuming that GAL can be used with all exchange accounts 227222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final android.accounts.Account[] accounts = AccountManager.get(getContext()) 228c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank .getAccountsByType(Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE); 2291f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov cursor = new MatrixCursor(projection); 2301f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (accounts != null) { 2311f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov for (android.accounts.Account account : accounts) { 2321f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row = new Object[projection.length]; 2331f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 2341f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 235222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String column = projection[i]; 2361f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (column.equals(Directory.ACCOUNT_NAME)) { 2371f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = account.name; 2381f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.ACCOUNT_TYPE)) { 2391f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = account.type; 2401f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.TYPE_RESOURCE_ID)) { 241222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String accountType = Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE; 242222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final Bundle bundle = new AccountServiceProxy(getContext()) 243d1771c4473a98c032c95ff66fa816043e08976f1Todd Kennedy .getConfigurationData(accountType); 244c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank // Default to the alternative name, erring on the conservative side 245c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank int exchangeName = R.string.exchange_name_alternate; 246c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank if (bundle != null && !bundle.getBoolean( 247c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank Configuration.EXCHANGE_CONFIGURATION_USE_ALTERNATE_STRINGS, 248c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank true)) { 249c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank exchangeName = R.string.exchange_name; 2501f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 251c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank row[i] = exchangeName; 2521f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.DISPLAY_NAME)) { 253aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov // If the account name is an email address, extract 254aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov // the domain name and use it as the directory display name 255aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov final String accountName = account.name; 256222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final int atIndex = accountName.indexOf('@'); 257aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov if (atIndex != -1 && atIndex < accountName.length() - 2) { 258aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov final char firstLetter = Character.toUpperCase( 259aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov accountName.charAt(atIndex + 1)); 260aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov row[i] = firstLetter + accountName.substring(atIndex + 2); 261aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov } else { 262aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov row[i] = account.name; 263aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov } 2641f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.EXPORT_SUPPORT)) { 2651f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY; 2661f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.SHORTCUT_SUPPORT)) { 267831936a7ee4cbf93c847a66d7cd3062680676f22Dmitri Plotnikov row[i] = Directory.SHORTCUT_SUPPORT_NONE; 2681f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2691f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2701f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov cursor.addRow(row); 2711f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2721f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2731f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return cursor; 2741f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2751f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 276f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov case GAL_FILTER: 277222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert case GAL_PHONE_FILTER: 278f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov case GAL_EMAIL_FILTER: { 279222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String filter = uri.getLastPathSegment(); 2805aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank // We should have at least two characters before doing a GAL search 2815aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (filter == null || filter.length() < 2) { 2825aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return null; 2835aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 2841f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 285222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME); 2861f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (accountName == null) { 2871f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return null; 2881f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2891f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 290469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank // Enforce a limit on the number of lookup responses 291222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String limitString = uri.getQueryParameter(ContactsContract.LIMIT_PARAM_KEY); 292469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank int limit = DEFAULT_LOOKUP_LIMIT; 293469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank if (limitString != null) { 294469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank try { 295469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank limit = Integer.parseInt(limitString); 296469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } catch (NumberFormatException e) { 297469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank limit = 0; 298469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } 299469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank if (limit <= 0) { 300469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank throw new IllegalArgumentException("Limit not valid: " + limitString); 301469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } 302469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } 303469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank 304222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final long callingId = Binder.clearCallingIdentity(); 3055aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank try { 3067307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank // Find the account id to pass along to EasSyncService 307222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final long accountId = getAccountIdByName(getContext(), accountName); 3087307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank if (accountId == -1) { 3097307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank // The account was deleted? 3107307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank return null; 3117307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank } 3127307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank 313e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final boolean isEmail = match == GAL_EMAIL_FILTER; 314e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final boolean isPhone = match == GAL_PHONE_FILTER; 315e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // For phone filter queries we request more results from the server 316e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // than requested by the caller because we omit contacts without 317e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // phone numbers, and the server lacks the ability to do this filtering 318e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // for us. We then enforce the limit when constructing the cursor 319e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // containing the results. 320e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner int queryLimit = limit; 321e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (isPhone) { 322e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner queryLimit = 3 * queryLimit; 323e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 324e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (queryLimit > MAX_LOOKUP_LIMIT) { 325e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner queryLimit = MAX_LOOKUP_LIMIT; 326e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 327e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 3285aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank // Get results from the Exchange account 329bb0141b49e7eff978fa445249dc888461ea581e3Martin Hibdon final GalResult galResult = EasService.searchGal(getContext(), accountId, 330e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner filter, queryLimit); 3312db0b68170b046b41c0319768d7018d093e536a4Anthony Lee if (galResult != null && (galResult.getNumEntries() > 0)) { 332e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return buildGalResultCursor( 333e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner projection, galResult, sortOrder, limit, isEmail, isPhone); 3345aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3355aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } finally { 3365aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank Binder.restoreCallingIdentity(callingId); 3375aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3385aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank break; 339d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 340d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 341d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov case GAL_CONTACT: 342d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov case GAL_CONTACT_WITH_ID: { 343222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME); 3441f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (accountName == null) { 3451f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return null; 3461f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 3471f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 348222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final GalProjection galProjection = new GalProjection(projection); 349d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor = new MatrixCursor(projection); 350d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // Handle the decomposition of the key into rows suitable for CP2 351222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final List<String> pathSegments = uri.getPathSegments(); 352d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov lookupKey = pathSegments.get(2); 353222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final long contactId = (match == GAL_CONTACT_WITH_ID) 354d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov ? Long.parseLong(pathSegments.get(3)) 355d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov : DEFAULT_CONTACT_ID; 356d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov ps = new PackedString(lookupKey); 357222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String displayName = ps.get(GalData.DISPLAY_NAME); 35856d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy GalContactRow.addEmailAddress(cursor, galProjection, contactId, 359d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov accountName, displayName, ps.get(GalData.EMAIL_ADDRESS)); 36056d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy GalContactRow.addPhoneRow(cursor, galProjection, contactId, 361d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName, displayName, Phone.TYPE_HOME, ps.get(GalData.HOME_PHONE)); 36256d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy GalContactRow.addPhoneRow(cursor, galProjection, contactId, 363d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName, displayName, Phone.TYPE_WORK, ps.get(GalData.WORK_PHONE)); 36456d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy GalContactRow.addPhoneRow(cursor, galProjection, contactId, 365d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName, displayName, Phone.TYPE_MOBILE, ps.get(GalData.MOBILE_PHONE)); 36656d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy GalContactRow.addNameRow(cursor, galProjection, contactId, displayName, 367d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov ps.get(GalData.FIRST_NAME), ps.get(GalData.LAST_NAME), displayName); 368d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov return cursor; 369d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 3705aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3715aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3725aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return null; 3735aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3745aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 375222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert /*package*/ Cursor buildGalResultCursor(String[] projection, GalResult galResult, 376e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner String sortOrder, int limit, boolean isEmailFilter, boolean isPhoneFilter) { 3775aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int displayNameIndex = -1; 378222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int displayNameSourceIndex = -1; 379222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int alternateDisplayNameIndex = -1; 3805aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int emailIndex = -1; 381222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int emailTypeIndex = -1; 382222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int phoneNumberIndex = -1; 383222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int phoneTypeIndex = -1; 384222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int hasPhoneNumberIndex = -1; 385d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov int idIndex = -1; 386222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int contactIdIndex = -1; 387d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov int lookupIndex = -1; 3885aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3895aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank for (int i = 0; i < projection.length; i++) { 390222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String column = projection[i]; 3915aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (Contacts.DISPLAY_NAME.equals(column) || 3925aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank Contacts.DISPLAY_NAME_PRIMARY.equals(column)) { 3935aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank displayNameIndex = i; 3945aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } else if (Contacts.DISPLAY_NAME_ALTERNATIVE.equals(column)) { 395d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov alternateDisplayNameIndex = i; 396222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else if (Contacts.DISPLAY_NAME_SOURCE.equals(column)) { 397222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert displayNameSourceIndex = i; 398222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else if (Contacts.HAS_PHONE_NUMBER.equals(column)) { 399222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert hasPhoneNumberIndex = i; 400d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else if (Contacts._ID.equals(column)) { 401d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov idIndex = i; 402222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else if (Phone.CONTACT_ID.equals(column)) { 403222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert contactIdIndex = i; 404d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else if (Contacts.LOOKUP_KEY.equals(column)) { 405d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov lookupIndex = i; 406222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else if (isPhoneFilter) { 407222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (Phone.NUMBER.equals(column)) { 408222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert phoneNumberIndex = i; 409222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else if (Phone.TYPE.equals(column)) { 410222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert phoneTypeIndex = i; 411222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 412222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else { 413222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // Cannot support for Email and Phone in same query, so default 414222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // is to return email addresses. 415222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (Email.ADDRESS.equals(column)) { 416222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert emailIndex = i; 417222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else if (Email.TYPE.equals(column)) { 418222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert emailTypeIndex = i; 419222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 4205aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 4215aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 4225aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 423e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner boolean usePrimarySortKey = false; 424e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner boolean useAlternateSortKey = false; 425e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (Contacts.SORT_KEY_PRIMARY.equals(sortOrder)) { 426e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner usePrimarySortKey = true; 427e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else if (Contacts.SORT_KEY_ALTERNATIVE.equals(sortOrder)) { 428e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner useAlternateSortKey = true; 429e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else if (sortOrder != null && sortOrder.length() > 0) { 430e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner Log.w(TAG, "Ignoring unsupported sort order: " + sortOrder); 431e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 4325aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 433222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final TreeMap<GalSortKey, Object[]> sortedResultsMap = 434222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert new TreeMap<GalSortKey, Object[]>(new NameComparator()); 435222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 436222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // id populates the _ID column and is incremented for each row in the 437222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // result set, so each row has a unique id. 438222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int id = 1; 439222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // contactId populates the CONTACT_ID column and is incremented for 440222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // each contact. For the email and phone filters, there may be more 441222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // than one row with the same contactId if a given contact has multiple 442222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // email addresses or multiple phone numbers. 443222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert int contactId = 1; 444222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 445222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final int count = galResult.galData.size(); 4465aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank for (int i = 0; i < count; i++) { 447222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final GalData galDataRow = galResult.galData.get(i); 448222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 449e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final List<PhoneInfo> phones = new ArrayList<PhoneInfo>(); 450222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert addPhoneInfo(phones, galDataRow.get(GalData.WORK_PHONE), Phone.TYPE_WORK); 451222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert addPhoneInfo(phones, galDataRow.get(GalData.OFFICE), Phone.TYPE_COMPANY_MAIN); 452222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert addPhoneInfo(phones, galDataRow.get(GalData.HOME_PHONE), Phone.TYPE_HOME); 453222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert addPhoneInfo(phones, galDataRow.get(GalData.MOBILE_PHONE), Phone.TYPE_MOBILE); 454222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 455e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // Track whether we added a result for this contact or not, in 456e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // order to stop once we have maxResult contacts. 457e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner boolean addedContact = false; 458e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 459e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner Pair<String, Integer> displayName = getDisplayName(galDataRow, phones); 460e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (TextUtils.isEmpty(displayName.first)) { 461e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // can't use a contact if we can't find a decent name for it. 462e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner continue; 463d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 464e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner galDataRow.put(GalData.DISPLAY_NAME, displayName.first); 465d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 466e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String alternateDisplayName = getAlternateDisplayName( 467e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner galDataRow, displayName.first); 468e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String sortName = usePrimarySortKey ? displayName.first 469e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner : (useAlternateSortKey ? alternateDisplayName : ""); 470e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final Object[] row = new Object[projection.length]; 4715aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (displayNameIndex != -1) { 472e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner row[displayNameIndex] = displayName.first; 473d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 474e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (displayNameSourceIndex != -1) { 475e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner row[displayNameSourceIndex] = displayName.second; 476222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 477222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 478d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (alternateDisplayNameIndex != -1) { 479222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert row[alternateDisplayNameIndex] = alternateDisplayName; 4805aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 481222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 482e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (hasPhoneNumberIndex != -1) { 483222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (phones.size() > 0) { 484222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert row[hasPhoneNumberIndex] = true; 485222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 486d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 487222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 488222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (contactIdIndex != -1) { 489222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert row[contactIdIndex] = contactId; 4905aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 491222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 4928999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu if (lookupIndex != -1) { 4938999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu // We use the packed string as our lookup key; it contains ALL of the gal data 4948999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu // We do this because we are not able to provide a stable id to ContactsProvider 4958999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu row[lookupIndex] = Uri.encode(galDataRow.toPackedString()); 4968999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu } 4978999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu 498222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (isPhoneFilter) { 499222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final Set<String> uniqueNumbers = new HashSet<String>(); 500222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 501222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert for (PhoneInfo phone : phones) { 502222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (!uniqueNumbers.add(phone.mNumber)) { 503222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert continue; 504222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 505e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (phoneNumberIndex != -1) { 506222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert row[phoneNumberIndex] = phone.mNumber; 507222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 508e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (phoneTypeIndex != -1) { 509222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert row[phoneTypeIndex] = phone.mType; 510222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 511222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert if (idIndex != -1) { 512222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert row[idIndex] = id; 513222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 514222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert sortedResultsMap.put(new GalSortKey(sortName, id), row.clone()); 515e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner addedContact = true; 516222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert id++; 517222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 518222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 519222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } else { 520e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner boolean haveEmail = false; 521e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner Object address = galDataRow.get(GalData.EMAIL_ADDRESS); 522e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (address != null && !TextUtils.isEmpty(address.toString())) { 523e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (emailIndex != -1) { 524e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner row[emailIndex] = address; 525e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 526e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (emailTypeIndex != -1) { 527e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner row[emailTypeIndex] = Email.TYPE_WORK; 528e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 529e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner haveEmail = true; 530222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 531222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 532e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (!isEmailFilter || haveEmail) { 533e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (idIndex != -1) { 534e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner row[idIndex] = id; 535e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 536e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner sortedResultsMap.put(new GalSortKey(sortName, id), row.clone()); 537e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner addedContact = true; 538e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner id++; 539e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 540e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 541e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (addedContact) { 542e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner contactId++; 543e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (contactId > limit) { 544e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner break; 545222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 546222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 547222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 548222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final MatrixCursor cursor = new MatrixCursor(projection, sortedResultsMap.size()); 549222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert for(Object[] result : sortedResultsMap.values()) { 550222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert cursor.addRow(result); 5515aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 552222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 5535aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return cursor; 5545aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 5555aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 556e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner /** 557e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * Try to create a display name from various fields. 558e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * 559e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * @return a display name for contact and its source 560e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner */ 561e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner private static Pair<String, Integer> getDisplayName(GalData galDataRow, List<PhoneInfo> phones) { 562e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner String displayName = galDataRow.get(GalData.DISPLAY_NAME); 563e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (!TextUtils.isEmpty(displayName)) { 564e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return Pair.create(displayName, DisplayNameSources.STRUCTURED_NAME); 565e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 566e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 567e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // try to get displayName from name fields 568e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String firstName = galDataRow.get(GalData.FIRST_NAME); 569e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String lastName = galDataRow.get(GalData.LAST_NAME); 570e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (!TextUtils.isEmpty(firstName) || !TextUtils.isEmpty(lastName)) { 571e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (!TextUtils.isEmpty(firstName) && !TextUtils.isEmpty(lastName)) { 572e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner displayName = firstName + " " + lastName; 573e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else if (!TextUtils.isEmpty(firstName)) { 574e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner displayName = firstName; 575e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else { 576e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner displayName = lastName; 577e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 578e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return Pair.create(displayName, DisplayNameSources.STRUCTURED_NAME); 579e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 580e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 581e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // try to get displayName from email 582e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String emailAddress = galDataRow.get(GalData.EMAIL_ADDRESS); 583e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (!TextUtils.isEmpty(emailAddress)) { 584e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return Pair.create(emailAddress, DisplayNameSources.EMAIL); 585e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 586e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 587e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // try to get displayName from phone numbers 588e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (phones != null && phones.size() > 0) { 589e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final PhoneInfo phone = (PhoneInfo) phones.get(0); 590e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (phone != null && !TextUtils.isEmpty(phone.mNumber)) { 591e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return Pair.create(phone.mNumber, DisplayNameSources.PHONE); 592e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 593e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 594e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return Pair.create(null, null); 595e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 596e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 597e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner /** 598e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * Try to create the alternate display name from various fields. The CP2 599e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * Alternate Display Name field is LastName FirstName to support user 600e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * choice of how to order names for display. 601e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * 602e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner * @return alternate display name for contact and its source 603e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner */ 604e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner private static String getAlternateDisplayName(GalData galDataRow, String displayName) { 605e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // try to get displayName from name fields 606e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String firstName = galDataRow.get(GalData.FIRST_NAME); 607e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final String lastName = galDataRow.get(GalData.LAST_NAME); 608e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (!TextUtils.isEmpty(firstName) && !TextUtils.isEmpty(lastName)) { 609e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return lastName + " " + firstName; 610e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else if (!TextUtils.isEmpty(lastName)) { 611e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return lastName; 612e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 613e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return displayName; 614e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } 615e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 616222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private void addPhoneInfo(List<PhoneInfo> phones, String number, int type) { 6178999766c3798c606840477abd203fc02fb55aa13Yu Ping Hu if (!TextUtils.isEmpty(number)) { 618222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert phones.add(new PhoneInfo(number, type)); 619222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 620222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 621222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 6225aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 6235aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public String getType(Uri uri) { 624222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final int match = sURIMatcher.match(uri); 6255aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank switch (match) { 6265aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank case GAL_FILTER: 6275aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return Contacts.CONTENT_ITEM_TYPE; 6285aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 6295aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return null; 6305aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 6315aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 6325aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 6335aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public int delete(Uri uri, String selection, String[] selectionArgs) { 6345aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank throw new UnsupportedOperationException(); 6355aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 6365aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 6375aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 6385aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public Uri insert(Uri uri, ContentValues values) { 6395aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank throw new UnsupportedOperationException(); 6405aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 6415aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 6425aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 6435aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 6445aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank throw new UnsupportedOperationException(); 6455aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 646222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 647222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert /** 648222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * Sort key for Gal filter results. 649222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * - primary key is name 650222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * for SORT_KEY_PRIMARY, this is displayName 651222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * for SORT_KEY_ALTERNATIVE, this is alternativeDisplayName 652222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * if no sort order is specified, this key is empty 653222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * - secondary key is id, so ordering of the original results are 654222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * preserved both between contacts with the same name and for 655222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert * multiple results within a given contact 656222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert */ 657674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee protected static class GalSortKey { 658222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert final String sortName; 659674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee final int id; 660222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 661674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee public GalSortKey(final String sortName, final int id) { 662222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert this.sortName = sortName; 663222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert this.id = id; 664222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 665222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 666222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 667674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee /** 668674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee * The Comparator that is used by ExchangeDirectoryProvider 669674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee */ 670674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee protected static class NameComparator implements Comparator<GalSortKey> { 671222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private final Collator collator; 672222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 673222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert public NameComparator() { 674222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert collator = Collator.getInstance(); 675222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert // Case insensitive sorting 676222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert collator.setStrength(Collator.SECONDARY); 677222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 678222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 679222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert @Override 680674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee public int compare(final GalSortKey lhs, final GalSortKey rhs) { 681674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee if (lhs.sortName != null && rhs.sortName != null) { 682e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner final int res = collator.compare(lhs.sortName, rhs.sortName); 683674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee if (res != 0) { 684674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee return res; 685674df0303129dcfa54a2cee2bf7e11195986220bAnthony Lee } 686e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else if (lhs.sortName != null) { 687e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return 1; 688e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner } else if (rhs.sortName != null) { 689e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return -1; 690222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 691e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner 692e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner // Either the names compared equally or both were null, use the id to compare. 693e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner if (lhs.id != rhs.id) { 694e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return lhs.id > rhs.id ? 1 : -1; 695222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 696e7e74f5d67647510a0394dcc8346a9cd7781d970Jay Shrauner return 0; 697222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 698222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 699222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 700222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private static class PhoneInfo { 701222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private String mNumber; 702222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private int mType; 703222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert 704222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert private PhoneInfo(String number, int type) { 705222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert mNumber = number; 706222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert mType = type; 707222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 708222dec5216626980f1450d8917e9b73e2d4c9040Alon Albert } 7095aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank} 710