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
19c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.Configuration;
20c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.mail.PackedString;
217372782488977df778a33d990401ce9e397f646bMarc Blankimport com.android.emailcommon.provider.Account;
22c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent;
23c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.provider.EmailContent.AccountColumns;
24c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.service.AccountServiceProxy;
25c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.emailcommon.utility.Utility;
26c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.exchange.Eas;
275aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport com.android.exchange.EasSyncService;
28c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport com.android.exchange.R;
295aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport com.android.exchange.provider.GalResult.GalData;
305aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
311f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikovimport android.accounts.AccountManager;
325aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.ContentProvider;
335aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.ContentValues;
347307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blankimport android.content.Context;
355aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.content.UriMatcher;
365aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.database.Cursor;
375aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.database.MatrixCursor;
385aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.net.Uri;
395aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.os.Binder;
40c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.os.Bundle;
41c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.os.RemoteException;
42469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blankimport android.provider.ContactsContract;
435aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankimport android.provider.ContactsContract.CommonDataKinds;
44d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email;
45d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone;
46d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
47c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.provider.ContactsContract.Contacts;
48d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.provider.ContactsContract.Contacts.Data;
49c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.provider.ContactsContract.Directory;
50c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blankimport android.provider.ContactsContract.RawContacts;
51d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport android.text.TextUtils;
52d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
53d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport java.util.HashMap;
54d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikovimport java.util.List;
555aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
565aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank/**
575aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * ExchangeDirectoryProvider provides real-time data from the Exchange server; at the moment, it is
585aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank * used solely to provide GAL (Global Address Lookup) service to email address adapters
595aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank */
605aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blankpublic class ExchangeDirectoryProvider extends ContentProvider {
61eb9cccf5c94b043baecb03d06738f7eedef03378Marc Blank    public static final String EXCHANGE_GAL_AUTHORITY = "com.android.exchange.directory.provider";
625aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
63d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov    private static final int DEFAULT_CONTACT_ID = 1;
64469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank    private static final int DEFAULT_LOOKUP_LIMIT = 20;
65d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
665aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    private static final int GAL_BASE = 0;
671f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov    private static final int GAL_DIRECTORIES = GAL_BASE;
681f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov    private static final int GAL_FILTER = GAL_BASE + 1;
691f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov    private static final int GAL_CONTACT = GAL_BASE + 2;
701f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov    private static final int GAL_CONTACT_WITH_ID = GAL_BASE + 3;
71f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov    private static final int GAL_EMAIL_FILTER = GAL_BASE + 4;
725aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
735aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
747307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank    /*package*/ final HashMap<String, Long> mAccountIdMap = new HashMap<String, Long>();
755aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
765aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    static {
771f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov        sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "directories", GAL_DIRECTORIES);
785aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/filter/*", GAL_FILTER);
791f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov        sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/lookup/*/entities", GAL_CONTACT);
80d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "contacts/lookup/*/#/entities",
81d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GAL_CONTACT_WITH_ID);
82f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov        sURIMatcher.addURI(EXCHANGE_GAL_AUTHORITY, "data/emails/filter/*", GAL_EMAIL_FILTER);
835aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
845aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
855aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    @Override
865aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    public boolean onCreate() {
875aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        return true;
885aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
895aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
90d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov    static class GalProjection {
91d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        final int size;
92d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        final HashMap<String, Integer> columnMap = new HashMap<String, Integer>();
93d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
94d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        GalProjection(String[] projection) {
95d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            size = projection.length;
96d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            for (int i = 0; i < projection.length; i++) {
97d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                columnMap.put(projection[i], i);
98d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
99d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
100d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov    }
101d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
102d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov    static class GalContactRow {
103d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        private final GalProjection mProjection;
104d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        private Object[] row;
105d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        static long dataId = 1;
106d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
107d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        GalContactRow(GalProjection projection, long contactId, String lookupKey,
108d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                String accountName, String displayName) {
109d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            this.mProjection = projection;
110d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            row = new Object[projection.size];
111d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
112d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(Contacts.Entity.CONTACT_ID, contactId);
113d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
114d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            // We only have one raw contact per aggregate, so they can have the same ID
115d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(Contacts.Entity.RAW_CONTACT_ID, contactId);
116d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(Contacts.Entity.DATA_ID, dataId++);
117d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
118d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(Contacts.DISPLAY_NAME, displayName);
119d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
120d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            // TODO alternative display name
121d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(Contacts.DISPLAY_NAME_ALTERNATIVE, displayName);
122d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
123c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank            put(RawContacts.ACCOUNT_TYPE, Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE);
124d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(RawContacts.ACCOUNT_NAME, accountName);
125d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(RawContacts.RAW_CONTACT_IS_READ_ONLY, 1);
126d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            put(Data.IS_READ_ONLY, 1);
127d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
128d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
129d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        Object[] getRow () {
130d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            return row;
131d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
132d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
133d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        void put(String columnName, Object value) {
134d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            Integer integer = mProjection.columnMap.get(columnName);
135d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (integer != null) {
136d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                row[integer] = value;
137d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            } else {
138d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                System.out.println("Unsupported column: " + columnName);
139d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
140d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
141d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
142d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        static void addEmailAddress(MatrixCursor cursor, GalProjection galProjection,
143d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                long contactId, String lookupKey, String accountName, String displayName,
144d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                String address) {
145d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (!TextUtils.isEmpty(address)) {
146d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow r = new GalContactRow(
147d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        galProjection, contactId, lookupKey, accountName, displayName);
148d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                r.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
149d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                r.put(Email.TYPE, Email.TYPE_WORK);
150d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                r.put(Email.ADDRESS, address);
151d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                cursor.addRow(r.getRow());
152d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
153d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
154d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
155d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        static void addPhoneRow(MatrixCursor cursor, GalProjection projection, long contactId,
156d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                String lookupKey, String accountName, String displayName, int type, String number) {
157d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (!TextUtils.isEmpty(number)) {
158d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow r = new GalContactRow(
159d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        projection, contactId, lookupKey, accountName, displayName);
160d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                r.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
161d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                r.put(Phone.TYPE, type);
162d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                r.put(Phone.NUMBER, number);
163d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                cursor.addRow(r.getRow());
164d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
165d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
166d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
167d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        public static void addNameRow(MatrixCursor cursor, GalProjection galProjection,
168d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                long contactId, String lookupKey, String accountName, String displayName,
169d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                String firstName, String lastName) {
170d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            GalContactRow r = new GalContactRow(
171d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                    galProjection, contactId, lookupKey, accountName, displayName);
172d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            r.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
173d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            r.put(StructuredName.GIVEN_NAME, firstName);
174d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            r.put(StructuredName.FAMILY_NAME, lastName);
175d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            r.put(StructuredName.DISPLAY_NAME, displayName);
176d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            cursor.addRow(r.getRow());
177d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        }
178d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov    }
179d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
1807307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank    /**
1817307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank     * Find the record id of an Account, given its name (email address)
1827307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank     * @param accountName the name of the account
1837307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank     * @return the record id of the Account, or -1 if not found
1847307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank     */
1857307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank    /*package*/ long getAccountIdByName(Context context, String accountName) {
1867307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank        Long accountId = mAccountIdMap.get(accountName);
1877307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank        if (accountId == null) {
1887307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank            accountId = Utility.getFirstRowLong(context, Account.CONTENT_URI,
1897307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    EmailContent.ID_PROJECTION, AccountColumns.EMAIL_ADDRESS + "=?",
1907307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    new String[] {accountName}, null, EmailContent.ID_PROJECTION_COLUMN , -1L);
1917307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank            if (accountId != -1) {
1927307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                mAccountIdMap.put(accountName, accountId);
1937307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank            }
1947307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank        }
1957307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank        return accountId;
1967307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank    }
1977307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank
1985aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    @Override
1995aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
2005aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            String sortOrder) {
2015aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        int match = sURIMatcher.match(uri);
202d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        MatrixCursor cursor;
203d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        Object[] row;
204d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        PackedString ps;
205d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        String lookupKey;
206d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
2075aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        switch (match) {
2081f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov            case GAL_DIRECTORIES: {
2091f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                // Assuming that GAL can be used with all exchange accounts
2101f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                android.accounts.Account[] accounts = AccountManager.get(getContext())
211c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                        .getAccountsByType(Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE);
2121f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                cursor = new MatrixCursor(projection);
2131f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                if (accounts != null) {
2141f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                    for (android.accounts.Account account : accounts) {
2151f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                        row = new Object[projection.length];
2161f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov
2171f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                        for (int i = 0; i < projection.length; i++) {
2181f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            String column = projection[i];
2191f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            if (column.equals(Directory.ACCOUNT_NAME)) {
2201f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                                row[i] = account.name;
2211f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            } else if (column.equals(Directory.ACCOUNT_TYPE)) {
2221f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                                row[i] = account.type;
2231f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            } else if (column.equals(Directory.TYPE_RESOURCE_ID)) {
224c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                Bundle bundle = null;
225d1771c4473a98c032c95ff66fa816043e08976f1Todd Kennedy                                String accountType = Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE;
226d1771c4473a98c032c95ff66fa816043e08976f1Todd Kennedy                                bundle = new AccountServiceProxy(getContext())
227d1771c4473a98c032c95ff66fa816043e08976f1Todd Kennedy                                    .getConfigurationData(accountType);
228c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                // Default to the alternative name, erring on the conservative side
229c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                int exchangeName = R.string.exchange_name_alternate;
230c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                if (bundle != null && !bundle.getBoolean(
231c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                        Configuration.EXCHANGE_CONFIGURATION_USE_ALTERNATE_STRINGS,
232c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                        true)) {
233c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                    exchangeName = R.string.exchange_name;
2341f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                                }
235c8e4352ea6cfa67f15140512e84af8ccede222d2Marc Blank                                row[i] = exchangeName;
2361f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            } else if (column.equals(Directory.DISPLAY_NAME)) {
237aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                // If the account name is an email address, extract
238aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                // the domain name and use it as the directory display name
239aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                final String accountName = account.name;
240aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                int atIndex = accountName.indexOf('@');
241aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                if (atIndex != -1 && atIndex < accountName.length() - 2) {
242aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                    final char firstLetter = Character.toUpperCase(
243aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                            accountName.charAt(atIndex + 1));
244aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                    row[i] = firstLetter + accountName.substring(atIndex + 2);
245aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                } else {
246aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                    row[i] = account.name;
247aa408e086ac013cd822c4f6b5f4ad91ae442d02fDmitri Plotnikov                                }
2481f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            } else if (column.equals(Directory.EXPORT_SUPPORT)) {
2491f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                                row[i] = Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY;
2501f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            } else if (column.equals(Directory.SHORTCUT_SUPPORT)) {
251831936a7ee4cbf93c847a66d7cd3062680676f22Dmitri Plotnikov                                row[i] = Directory.SHORTCUT_SUPPORT_NONE;
2521f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                            }
2531f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                        }
2541f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                        cursor.addRow(row);
2551f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                    }
2561f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                }
2571f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                return cursor;
2581f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov            }
2591f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov
260f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov            case GAL_FILTER:
261f6e831704c7df2b841760931469b1e995b957cd9Dmitri Plotnikov            case GAL_EMAIL_FILTER: {
2625aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                String filter = uri.getLastPathSegment();
2635aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                // We should have at least two characters before doing a GAL search
2645aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                if (filter == null || filter.length() < 2) {
2655aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                    return null;
2665aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                }
2671f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov
2681f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
2691f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                if (accountName == null) {
2701f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                    return null;
2711f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                }
2721f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov
273469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                // Enforce a limit on the number of lookup responses
274469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                String limitString = uri.getQueryParameter(ContactsContract.LIMIT_PARAM_KEY);
275469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                int limit = DEFAULT_LOOKUP_LIMIT;
276469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                if (limitString != null) {
277469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                    try {
278469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                        limit = Integer.parseInt(limitString);
279469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                    } catch (NumberFormatException e) {
280469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                        limit = 0;
281469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                    }
282469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                    if (limit <= 0) {
283469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                        throw new IllegalArgumentException("Limit not valid: " + limitString);
284469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                    }
285469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                }
286469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank
2875aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                long callingId = Binder.clearCallingIdentity();
2885aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                try {
2897307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    // Find the account id to pass along to EasSyncService
2907307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    long accountId = getAccountIdByName(getContext(), accountName);
2917307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    if (accountId == -1) {
2927307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                        // The account was deleted?
2937307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                        return null;
2947307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    }
2957307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank
2965aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                    // Get results from the Exchange account
2977307f7e5c2c4f85f6f3e0ebaf5775f65cba4b20cMarc Blank                    GalResult galResult = EasSyncService.searchGal(getContext(), accountId,
298469544cd1b9652c446c96b97f4abbdb65d7e06aaMarc Blank                            filter, limit);
2995aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                    if (galResult != null) {
3005aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                        return buildGalResultCursor(projection, galResult);
3015aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                    }
3025aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                } finally {
3035aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                    Binder.restoreCallingIdentity(callingId);
3045aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                }
3055aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                break;
306d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
307d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
308d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            case GAL_CONTACT:
309d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            case GAL_CONTACT_WITH_ID: {
3101f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                String accountName = uri.getQueryParameter(RawContacts.ACCOUNT_NAME);
3111f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                if (accountName == null) {
3121f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                    return null;
3131f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                }
3141f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov
315d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalProjection galProjection = new GalProjection(projection);
316d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                cursor = new MatrixCursor(projection);
317d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                // Handle the decomposition of the key into rows suitable for CP2
3181f4b000ebe72fe9e71082031f48d0133914bda2dDmitri Plotnikov                List<String> pathSegments = uri.getPathSegments();
319d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                lookupKey = pathSegments.get(2);
320d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                long contactId = (match == GAL_CONTACT_WITH_ID)
321d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        ? Long.parseLong(pathSegments.get(3))
322d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        : DEFAULT_CONTACT_ID;
323d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                ps = new PackedString(lookupKey);
324d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                String displayName = ps.get(GalData.DISPLAY_NAME);
325d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow.addEmailAddress(cursor, galProjection, contactId, lookupKey,
326d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        accountName, displayName, ps.get(GalData.EMAIL_ADDRESS));
327d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow.addPhoneRow(cursor, galProjection, contactId, accountName,
328d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        displayName, displayName, Phone.TYPE_HOME, ps.get(GalData.HOME_PHONE));
329d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow.addPhoneRow(cursor, galProjection, contactId, accountName,
330d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        displayName, displayName, Phone.TYPE_WORK, ps.get(GalData.WORK_PHONE));
331d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow.addPhoneRow(cursor, galProjection, contactId, accountName,
332d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        displayName, displayName, Phone.TYPE_MOBILE, ps.get(GalData.MOBILE_PHONE));
333d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                GalContactRow.addNameRow(cursor, galProjection, contactId, accountName, displayName,
334d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                        ps.get(GalData.FIRST_NAME), ps.get(GalData.LAST_NAME), displayName);
335d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                return cursor;
336d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
3375aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        }
3385aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
3395aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        return null;
3405aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
3415aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
3425aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    /*package*/ Cursor buildGalResultCursor(String[] projection, GalResult galResult) {
3435aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        int displayNameIndex = -1;
344d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        int alternateDisplayNameIndex = -1;;
3455aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        int emailIndex = -1;
346d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        int idIndex = -1;
347d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov        int lookupIndex = -1;
3485aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
3495aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        for (int i = 0; i < projection.length; i++) {
3505aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            String column = projection[i];
3515aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            if (Contacts.DISPLAY_NAME.equals(column) ||
3525aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                    Contacts.DISPLAY_NAME_PRIMARY.equals(column)) {
3535aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                displayNameIndex = i;
3545aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            } else if (Contacts.DISPLAY_NAME_ALTERNATIVE.equals(column)) {
355d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                alternateDisplayNameIndex = i;
3565aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            } else if (CommonDataKinds.Email.ADDRESS.equals(column)) {
3575aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                emailIndex = i;
358d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            } else if (Contacts._ID.equals(column)) {
359d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                idIndex = i;
360d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            } else if (Contacts.LOOKUP_KEY.equals(column)) {
361d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                lookupIndex = i;
3625aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            }
3635aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        }
3645aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
3655aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        Object[] row = new Object[projection.length];
3665aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
3675aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        /*
3685aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank         * ContactsProvider will ensure that every request has a non-null projection.
3695aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank         */
3705aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        MatrixCursor cursor = new MatrixCursor(projection);
3715aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        int count = galResult.galData.size();
3725aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        for (int i = 0; i < count; i++) {
3735aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            GalData galDataRow = galResult.galData.get(i);
374d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            String firstName = galDataRow.get(GalData.FIRST_NAME);
375d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            String lastName = galDataRow.get(GalData.LAST_NAME);
376d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            String displayName = galDataRow.get(GalData.DISPLAY_NAME);
377d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            // If we don't have a display name, try to create one using first and last name
378d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (displayName == null) {
379d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                if (firstName != null && lastName != null) {
380d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                    displayName = firstName + " " + lastName;
381d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                } else if (firstName != null) {
382d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                    displayName = firstName;
383d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                } else if (lastName != null) {
384d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                    displayName = lastName;
385d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                }
386d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
387d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            galDataRow.put(GalData.DISPLAY_NAME, displayName);
388d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov
3895aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            if (displayNameIndex != -1) {
390d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                row[displayNameIndex] = displayName;
391d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
392d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (alternateDisplayNameIndex != -1) {
393d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                // Try to create an alternate display name, using first and last name
394d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                // TODO: Check with Contacts team to make sure we're using this properly
395d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                if (firstName != null && lastName != null) {
396d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                    row[alternateDisplayNameIndex] = lastName + " " + firstName;
397d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                } else {
398d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                    row[alternateDisplayNameIndex] = displayName;
399d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                }
4005aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            }
4015aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            if (emailIndex != -1) {
402d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                row[emailIndex] = galDataRow.get(GalData.EMAIL_ADDRESS);
403d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
404d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (idIndex != -1) {
405d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                row[idIndex] = i + 1;  // Let's be 1 based
406d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            }
407d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov            if (lookupIndex != -1) {
408d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                // We use the packed string as our lookup key; it contains ALL of the gal data
409d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                // We do this because we are not able to provide a stable id to ContactsProvider
410d41eaba645dcb4573c5dc33077fc87799ef06195Dmitri Plotnikov                row[lookupIndex] = Uri.encode(galDataRow.toPackedString());
4115aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            }
4125aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            cursor.addRow(row);
4135aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        }
4145aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        return cursor;
4155aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
4165aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
4175aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    @Override
4185aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    public String getType(Uri uri) {
4195aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        int match = sURIMatcher.match(uri);
4205aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        switch (match) {
4215aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank            case GAL_FILTER:
4225aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank                return Contacts.CONTENT_ITEM_TYPE;
4235aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        }
4245aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        return null;
4255aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
4265aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
4275aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    @Override
4285aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    public int delete(Uri uri, String selection, String[] selectionArgs) {
4295aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        throw new UnsupportedOperationException();
4305aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
4315aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
4325aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    @Override
4335aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    public Uri insert(Uri uri, ContentValues values) {
4345aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        throw new UnsupportedOperationException();
4355aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
4365aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank
4375aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    @Override
4385aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
4395aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank        throw new UnsupportedOperationException();
4405aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank    }
4415aec61dc15c62cff0cf55a3d6cb483f9e338230aMarc Blank}
442