ExchangeDirectoryProvider.java revision 469544cd1b9652c446c96b97f4abbdb65d7e06aa
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 com.android.email.R; 201f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikovimport com.android.email.VendorPolicyLoader; 21d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport com.android.email.mail.PackedString; 225aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport com.android.email.provider.EmailContent.Account; 235aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport com.android.exchange.EasSyncService; 24385a0be662509754e687bcfa9813208b050bf951Marc Blankimport com.android.exchange.ExchangeService; 255aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport com.android.exchange.provider.GalResult.GalData; 265aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 271f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikovimport android.accounts.AccountManager; 285aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.ContentProvider; 295aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.ContentValues; 305aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.UriMatcher; 315aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.database.Cursor; 325aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.database.MatrixCursor; 335aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.net.Uri; 345aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.os.Binder; 35469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blankimport android.provider.ContactsContract; 365aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.provider.ContactsContract.CommonDataKinds; 37469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blankimport android.provider.ContactsContract.Contacts; 38469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blankimport android.provider.ContactsContract.Directory; 39469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blankimport android.provider.ContactsContract.RawContacts; 40d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 41d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 42d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 43d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.Data; 44d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.text.TextUtils; 45d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 46d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport java.util.HashMap; 47d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport java.util.List; 485aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 495aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank/** 505aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * ExchangeDirectoryProvider provides real-time data from the Exchange server; at the moment, it is 515aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * used solely to provide GAL (Global Address Lookup) service to email address adapters 525aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank */ 535aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankpublic class ExchangeDirectoryProvider extends ContentProvider { 54eb9cccf5c94b043baecb03d06738f7eedef03378Marc Blank public static final String EXCHANGE_GAL_AUTHORITY = "com.android.exchange.directory.provider"; 555aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 56d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov private static final int DEFAULT_CONTACT_ID = 1; 57469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank private static final int DEFAULT_LOOKUP_LIMIT = 20; 58d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 595aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank private static final int GAL_BASE = 0; 601f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_DIRECTORIES = GAL_BASE; 611f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_FILTER = GAL_BASE + 1; 621f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_CONTACT = GAL_BASE + 2; 631f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov private static final int GAL_CONTACT_WITH_ID = GAL_BASE + 3; 64f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov private static final int GAL_EMAIL_FILTER = GAL_BASE + 4; 655aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 665aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 675aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 685aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank static { 691f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "directories", GAL_DIRECTORIES); 705aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/filter/*", GAL_FILTER); 711f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/lookup/*/entities", GAL_CONTACT); 72d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/lookup/*/#/entities", 73d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GAL_CONTACT_WITH_ID); 74f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "data/emails/filter/*", GAL_EMAIL_FILTER); 755aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 765aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 775aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 785aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public boolean onCreate() { 795aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return true; 805aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 815aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 82d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static class GalProjection { 83d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov final int size; 84d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov final HashMap<String, Integer> columnMap = new HashMap<String, Integer>(); 85d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 86d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalProjection(String[] projection) { 87d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov size = projection.length; 88d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 89d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov columnMap.put(projection[i], i); 90d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 91d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 92d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 93d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 94d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static class GalContactRow { 95d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov private final GalProjection mProjection; 96d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov private Object[] row; 97d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static long dataId = 1; 98d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 99d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow(GalProjection projection, long contactId, String lookupKey, 100d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String accountName, String displayName) { 101d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov this.mProjection = projection; 102d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row = new Object[projection.size]; 103d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 104d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.Entity.CONTACT_ID, contactId); 105d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 106d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // We only have one raw contact per aggregate, so they can have the same ID 107d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.Entity.RAW_CONTACT_ID, contactId); 108d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.Entity.DATA_ID, dataId++); 109d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 110d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.DISPLAY_NAME, displayName); 111d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 112d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // TODO alternative display name 113d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Contacts.DISPLAY_NAME_ALTERNATIVE, displayName); 114d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 115d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(RawContacts.ACCOUNT_TYPE, com.android.email.Email.EXCHANGE_ACCOUNT_MANAGER_TYPE); 116d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(RawContacts.ACCOUNT_NAME, accountName); 117d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 118d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov put(Data.IS_READ_ONLY, 1); 119d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 120d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 121d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov Object[] getRow () { 122d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov return row; 123d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 124d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 125d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov void put(String columnName, Object value) { 126d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov Integer integer = mProjection.columnMap.get(columnName); 127d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (integer != null) { 128d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[integer] = value; 129d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else { 130d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov System.out.println("Unsupported column: " + columnName); 131d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 132d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 133d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 134d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static void addEmailAddress(MatrixCursor cursor, GalProjection galProjection, 135d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov long contactId, String lookupKey, String accountName, String displayName, 136d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String address) { 137d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (!TextUtils.isEmpty(address)) { 138d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow r = new GalContactRow( 139d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov galProjection, contactId, lookupKey, accountName, displayName); 140d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 141d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Email.TYPE, Email.TYPE_WORK); 142d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Email.ADDRESS, address); 143d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor.addRow(r.getRow()); 144d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 145d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 146d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 147d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov static void addPhoneRow(MatrixCursor cursor, GalProjection projection, long contactId, 148d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String lookupKey, String accountName, String displayName, int type, String number) { 149d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (!TextUtils.isEmpty(number)) { 150d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow r = new GalContactRow( 151d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov projection, contactId, lookupKey, accountName, displayName); 152d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 153d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Phone.TYPE, type); 154d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Phone.NUMBER, number); 155d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor.addRow(r.getRow()); 156d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 157d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 158d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 159d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov public static void addNameRow(MatrixCursor cursor, GalProjection galProjection, 160d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov long contactId, String lookupKey, String accountName, String displayName, 161d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String firstName, String lastName) { 162d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow r = new GalContactRow( 163d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov galProjection, contactId, lookupKey, accountName, displayName); 164d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 165d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(StructuredName.GIVEN_NAME, firstName); 166d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(StructuredName.FAMILY_NAME, lastName); 167d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov r.put(StructuredName.DISPLAY_NAME, displayName); 168d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor.addRow(r.getRow()); 169d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 170d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 171d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 1725aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 1735aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 1745aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank String sortOrder) { 1755aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int match = sURIMatcher.match(uri); 176d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov MatrixCursor cursor; 177d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov Object[] row; 178d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov PackedString ps; 179d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String lookupKey; 180d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 1815aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank switch (match) { 1821f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov case GAL_DIRECTORIES: { 1831f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov // Assuming that GAL can be used with all exchange accounts 1841f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov android.accounts.Account[] accounts = AccountManager.get(getContext()) 1851f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov .getAccountsByType(com.android.email.Email.EXCHANGE_ACCOUNT_MANAGER_TYPE); 1861f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov cursor = new MatrixCursor(projection); 1871f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (accounts != null) { 1881f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov for (android.accounts.Account account : accounts) { 1891f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row = new Object[projection.length]; 1901f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 1911f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov for (int i = 0; i < projection.length; i++) { 1921f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov String column = projection[i]; 1931f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (column.equals(Directory.ACCOUNT_NAME)) { 1941f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = account.name; 1951f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.ACCOUNT_TYPE)) { 1961f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = account.type; 1971f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.TYPE_RESOURCE_ID)) { 1981f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (VendorPolicyLoader.getInstance(getContext()) 1991f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov .useAlternateExchangeStrings()) { 2001f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = R.string.exchange_name_alternate; 2011f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else { 2021f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = R.string.exchange_name; 2031f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2041f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.DISPLAY_NAME)) { 2051f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = account.name; 2061f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.EXPORT_SUPPORT)) { 2071f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY; 2081f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } else if (column.equals(Directory.SHORTCUT_SUPPORT)) { 2091f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov row[i] = Directory.SHORTCUT_SUPPORT_FULL; 2101f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2111f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2121f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov cursor.addRow(row); 2131f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2141f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2151f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return cursor; 2161f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2171f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 218f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov case GAL_FILTER: 219f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov case GAL_EMAIL_FILTER: { 2205aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank String filter = uri.getLastPathSegment(); 2215aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank // We should have at least two characters before doing a GAL search 2225aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (filter == null || filter.length() < 2) { 2235aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return null; 2245aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 2251f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 2261f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME); 2271f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (accountName == null) { 2281f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return null; 2291f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2301f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 231469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank // Enforce a limit on the number of lookup responses 232469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank String limitString = uri.getQueryParameter(ContactsContract.LIMIT_PARAM_KEY); 233469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank int limit = DEFAULT_LOOKUP_LIMIT; 234469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank if (limitString != null) { 235469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank try { 236469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank limit = Integer.parseInt(limitString); 237469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } catch (NumberFormatException e) { 238469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank limit = 0; 239469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } 240469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank if (limit <= 0) { 241469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank throw new IllegalArgumentException("Limit not valid: " + limitString); 242469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } 243469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank } 244469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank 245385a0be662509754e687bcfa9813208b050bf951Marc Blank Account account = ExchangeService.getAccountByName(accountName); 2461f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (account == null) { 2471f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return null; 2481f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2491f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 2505aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank long callingId = Binder.clearCallingIdentity(); 2515aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank try { 2525aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank // Get results from the Exchange account 2535aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank GalResult galResult = EasSyncService.searchGal(getContext(), account.mId, 254469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank filter, limit); 2555aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (galResult != null) { 2565aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return buildGalResultCursor(projection, galResult); 2575aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 2585aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } finally { 2595aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank Binder.restoreCallingIdentity(callingId); 2605aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 2615aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank break; 262d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 263d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 264d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov case GAL_CONTACT: 265d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov case GAL_CONTACT_WITH_ID: { 2661f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME); 2671f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov if (accountName == null) { 2681f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov return null; 2691f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov } 2701f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov 271d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalProjection galProjection = new GalProjection(projection); 272d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov cursor = new MatrixCursor(projection); 273d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // Handle the decomposition of the key into rows suitable for CP2 2741f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov List<String> pathSegments = uri.getPathSegments(); 275d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov lookupKey = pathSegments.get(2); 276d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov long contactId = (match == GAL_CONTACT_WITH_ID) 277d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov ? Long.parseLong(pathSegments.get(3)) 278d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov : DEFAULT_CONTACT_ID; 279d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov ps = new PackedString(lookupKey); 280d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String displayName = ps.get(GalData.DISPLAY_NAME); 281d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow.addEmailAddress(cursor, galProjection, contactId, lookupKey, 282d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov accountName, displayName, ps.get(GalData.EMAIL_ADDRESS)); 283d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow.addPhoneRow(cursor, galProjection, contactId, accountName, 284d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName, displayName, Phone.TYPE_HOME, ps.get(GalData.HOME_PHONE)); 285d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow.addPhoneRow(cursor, galProjection, contactId, accountName, 286d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName, displayName, Phone.TYPE_WORK, ps.get(GalData.WORK_PHONE)); 287d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow.addPhoneRow(cursor, galProjection, contactId, accountName, 288d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName, displayName, Phone.TYPE_MOBILE, ps.get(GalData.MOBILE_PHONE)); 289d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov GalContactRow.addNameRow(cursor, galProjection, contactId, accountName, displayName, 290d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov ps.get(GalData.FIRST_NAME), ps.get(GalData.LAST_NAME), displayName); 291d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov return cursor; 292d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 2935aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 2945aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 2955aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return null; 2965aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 2975aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 2985aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank /*package*/ Cursor buildGalResultCursor(String[] projection, GalResult galResult) { 2995aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int displayNameIndex = -1; 300d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov int alternateDisplayNameIndex = -1;; 3015aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int emailIndex = -1; 302d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov int idIndex = -1; 303d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov int lookupIndex = -1; 3045aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3055aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank for (int i = 0; i < projection.length; i++) { 3065aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank String column = projection[i]; 3075aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (Contacts.DISPLAY_NAME.equals(column) || 3085aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank Contacts.DISPLAY_NAME_PRIMARY.equals(column)) { 3095aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank displayNameIndex = i; 3105aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } else if (Contacts.DISPLAY_NAME_ALTERNATIVE.equals(column)) { 311d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov alternateDisplayNameIndex = i; 3125aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } else if (CommonDataKinds.Email.ADDRESS.equals(column)) { 3135aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank emailIndex = i; 314d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else if (Contacts._ID.equals(column)) { 315d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov idIndex = i; 316d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else if (Contacts.LOOKUP_KEY.equals(column)) { 317d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov lookupIndex = i; 3185aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3195aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3205aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3215aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank Object[] row = new Object[projection.length]; 3225aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3235aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank /* 3245aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * ContactsProvider will ensure that every request has a non-null projection. 3255aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank */ 3265aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank MatrixCursor cursor = new MatrixCursor(projection); 3275aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int count = galResult.galData.size(); 3285aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank for (int i = 0; i < count; i++) { 3295aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank GalData galDataRow = galResult.galData.get(i); 330d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String firstName = galDataRow.get(GalData.FIRST_NAME); 331d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String lastName = galDataRow.get(GalData.LAST_NAME); 332d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov String displayName = galDataRow.get(GalData.DISPLAY_NAME); 333d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // If we don't have a display name, try to create one using first and last name 334d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (displayName == null) { 335d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (firstName != null && lastName != null) { 336d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName = firstName + " " + lastName; 337d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else if (firstName != null) { 338d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName = firstName; 339d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else if (lastName != null) { 340d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov displayName = lastName; 341d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 342d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 343d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov galDataRow.put(GalData.DISPLAY_NAME, displayName); 344d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov 3455aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (displayNameIndex != -1) { 346d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[displayNameIndex] = displayName; 347d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 348d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (alternateDisplayNameIndex != -1) { 349d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // Try to create an alternate display name, using first and last name 350d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // TODO: Check with Contacts team to make sure we're using this properly 351d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (firstName != null && lastName != null) { 352d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[alternateDisplayNameIndex] = lastName + " " + firstName; 353d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } else { 354d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[alternateDisplayNameIndex] = displayName; 355d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 3565aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3575aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank if (emailIndex != -1) { 358d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[emailIndex] = galDataRow.get(GalData.EMAIL_ADDRESS); 359d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 360d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (idIndex != -1) { 361d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[idIndex] = i + 1; // Let's be 1 based 362d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov } 363d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov if (lookupIndex != -1) { 364d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // We use the packed string as our lookup key; it contains ALL of the gal data 365d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov // We do this because we are not able to provide a stable id to ContactsProvider 366d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov row[lookupIndex] = Uri.encode(galDataRow.toPackedString()); 3675aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3685aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank cursor.addRow(row); 3695aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3705aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return cursor; 3715aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3725aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3735aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 3745aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public String getType(Uri uri) { 3755aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank int match = sURIMatcher.match(uri); 3765aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank switch (match) { 3775aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank case GAL_FILTER: 3785aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return Contacts.CONTENT_ITEM_TYPE; 3795aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3805aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank return null; 3815aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3825aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3835aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 3845aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public int delete(Uri uri, String selection, String[] selectionArgs) { 3855aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank throw new UnsupportedOperationException(); 3865aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3875aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3885aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 3895aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public Uri insert(Uri uri, ContentValues values) { 3905aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank throw new UnsupportedOperationException(); 3915aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3925aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank 3935aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank @Override 3945aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 3955aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank throw new UnsupportedOperationException(); 3965aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank } 3975aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank} 398