163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng/*
263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * Copyright (C) 2010 The Android Open Source Project
363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng *
463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * you may not use this file except in compliance with the License.
663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * You may obtain a copy of the License at
763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng *
863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng *
1063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * Unless required by applicable law or agreed to in writing, software
1163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
1263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * See the License for the specific language governing permissions and
1463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * limitations under the License.
1563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng */
1663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengpackage com.android.contacts.common.list;
1763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
1863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.content.ContentUris;
1963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.content.Context;
2063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.content.CursorLoader;
2163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.database.Cursor;
2263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.net.Uri;
2363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.net.Uri.Builder;
2463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract;
2563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract.CommonDataKinds.Callable;
2663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract.CommonDataKinds.Phone;
2763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract.CommonDataKinds.SipAddress;
2863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract.Contacts;
2963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract.Data;
3063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.provider.ContactsContract.Directory;
3141d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Leeimport android.text.TextUtils;
3263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.util.Log;
3363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.view.View;
3463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport android.view.ViewGroup;
3563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
36e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunnimport com.android.contacts.common.CallUtil;
3744192bbce136eda4305e8ffa2cafc7663b3e25d2Victor Changimport com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
38d19d35ef8347038f5296ed7020cab79396874937Victor Changimport com.android.contacts.common.ContactsUtils;
396af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albertimport com.android.contacts.common.GeoUtil;
4063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport com.android.contacts.common.R;
41cd0b29ddbf3648e48f048196c62245d545bc6122Ricky Waiimport com.android.contacts.common.compat.CallableCompat;
4292a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wangimport com.android.contacts.common.compat.CompatUtils;
43cd0b29ddbf3648e48f048196c62245d545bc6122Ricky Waiimport com.android.contacts.common.compat.DirectoryCompat;
44cd0b29ddbf3648e48f048196c62245d545bc6122Ricky Waiimport com.android.contacts.common.compat.PhoneCompat;
45ad582fa758c6a276c26c5cc52079613a653c81bfBen Giladimport com.android.contacts.common.extensions.ExtendedPhoneDirectoriesManager;
46ad582fa758c6a276c26c5cc52079613a653c81bfBen Giladimport com.android.contacts.common.extensions.ExtensionsFactory;
47495c732e471c1c68db91ca6e824440130fdb7146Yorke Leeimport com.android.contacts.common.preference.ContactsPreferences;
48b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albertimport com.android.contacts.common.util.Constants;
4963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
5092a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wangimport com.google.common.collect.Lists;
5192a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang
5263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport java.util.ArrayList;
5363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengimport java.util.List;
5463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
5563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng/**
5663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * A cursor adapter for the {@link Phone#CONTENT_ITEM_TYPE} and
5763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * {@link SipAddress#CONTENT_ITEM_TYPE}.
5863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng *
5963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * By default this adapter just handles phone numbers. When {@link #setUseCallableUri(boolean)} is
6063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * called with "true", this adapter starts handling SIP addresses too, by using {@link Callable}
6163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng * API instead of {@link Phone}.
6263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng */
6363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Chengpublic class PhoneNumberListAdapter extends ContactEntryListAdapter {
64ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
6563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    private static final String TAG = PhoneNumberListAdapter.class.getSimpleName();
6663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
67e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    public interface Listener {
68e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        void onVideoCallIconClicked(int position);
69e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    }
70e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
71ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    // A list of extended directories to add to the directories from the database
72ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    private final List<DirectoryPartition> mExtendedDirectories;
73ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
74e3cc993cb72230b0ca9465763d927b8a851da8fbWenyi Wang    // Extended directories will have ID's that are higher than any of the id's from the database,
75e3cc993cb72230b0ca9465763d927b8a851da8fbWenyi Wang    // so that we can identify them and set them up properly. If no extended directories
76ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    // exist, this will be Long.MAX_VALUE
77ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    private long mFirstExtendedDirectoryId = Long.MAX_VALUE;
78ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
79a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    public static class PhoneQuery {
806a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn
816a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        /**
826a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         * Optional key used as part of a JSON lookup key to specify an analytics category
836a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         * associated with the row.
846a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         */
856a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        public static final String ANALYTICS_CATEGORY = "analytics_category";
866a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn
876a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        /**
886a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         * Optional key used as part of a JSON lookup key to specify an analytics action associated
896a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         * with the row.
906a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         */
916a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        public static final String ANALYTICS_ACTION = "analytics_action";
926a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn
936a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        /**
946a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         * Optional key used as part of a JSON lookup key to specify an analytics value associated
956a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         * with the row.
966a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn         */
976a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        public static final String ANALYTICS_VALUE = "analytics_value";
986a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn
9992a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        public static final String[] PROJECTION_PRIMARY_INTERNAL = new String[] {
10063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone._ID,                          // 0
10163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.TYPE,                         // 1
10263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.LABEL,                        // 2
10363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.NUMBER,                       // 3
10463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.CONTACT_ID,                   // 4
10563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.LOOKUP_KEY,                   // 5
10663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.PHOTO_ID,                     // 6
10763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.DISPLAY_NAME_PRIMARY,         // 7
1087a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            Phone.PHOTO_THUMBNAIL_URI,          // 8
10963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        };
11063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
11192a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        public static final String[] PROJECTION_PRIMARY;
11292a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang
11392a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        static {
11492a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            final List<String> projectionList = Lists.newArrayList(PROJECTION_PRIMARY_INTERNAL);
11592a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            if (CompatUtils.isMarshmallowCompatible()) {
11692a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang                projectionList.add(Phone.CARRIER_PRESENCE); // 9
11792a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            }
11892a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            PROJECTION_PRIMARY = projectionList.toArray(new String[projectionList.size()]);
11992a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        }
12092a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang
12192a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        public static final String[] PROJECTION_ALTERNATIVE_INTERNAL = new String[] {
12263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone._ID,                          // 0
12363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.TYPE,                         // 1
12463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.LABEL,                        // 2
12563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.NUMBER,                       // 3
12663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.CONTACT_ID,                   // 4
12763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.LOOKUP_KEY,                   // 5
12863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.PHOTO_ID,                     // 6
12963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Phone.DISPLAY_NAME_ALTERNATIVE,     // 7
1307a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            Phone.PHOTO_THUMBNAIL_URI,          // 8
13163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        };
13263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
13392a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        public static final String[] PROJECTION_ALTERNATIVE;
13492a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang
13592a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        static {
13692a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            final List<String> projectionList = Lists.newArrayList(PROJECTION_ALTERNATIVE_INTERNAL);
13792a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            if (CompatUtils.isMarshmallowCompatible()) {
13892a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang                projectionList.add(Phone.CARRIER_PRESENCE); // 9
13992a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            }
14092a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            PROJECTION_ALTERNATIVE = projectionList.toArray(new String[projectionList.size()]);
14192a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        }
14292a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang
1437a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int PHONE_ID                = 0;
1447a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int PHONE_TYPE              = 1;
1457a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int PHONE_LABEL             = 2;
1467a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int PHONE_NUMBER            = 3;
1477a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int CONTACT_ID              = 4;
1487a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int LOOKUP_KEY              = 5;
1497a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int PHOTO_ID                = 6;
1507a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int DISPLAY_NAME            = 7;
1517a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        public static final int PHOTO_URI               = 8;
152e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        public static final int CARRIER_PRESENCE        = 9;
15363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
15463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
15541d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee    private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE =
15641d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            "length(" + Phone.NUMBER + ") < 1000";
15741d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee
15863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    private final CharSequence mUnknownNameText;
15962dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee    private final String mCountryIso;
16063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
16163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    private ContactListItemView.PhotoPosition mPhotoPosition;
16263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
16363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    private boolean mUseCallableUri;
16463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
165e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private Listener mListener;
166e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
167e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private boolean mIsVideoEnabled;
168e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    private boolean mIsPresenceEnabled;
169e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
17063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public PhoneNumberListAdapter(Context context) {
17163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        super(context);
17263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        setDefaultFilterHeaderText(R.string.list_filter_phones);
17363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        mUnknownNameText = context.getText(android.R.string.unknownName);
17462dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee        mCountryIso = GeoUtil.getCurrentCountryIso(context);
175ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
176ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        final ExtendedPhoneDirectoriesManager manager
177ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                = ExtensionsFactory.getExtendedPhoneDirectoriesManager();
178ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        if (manager != null) {
179ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            mExtendedDirectories = manager.getExtendedDirectories(mContext);
180ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        } else {
181a6057cf46a154666c6f2888702d4109504b4da29Alon Albert            // Empty list to avoid sticky NPE's
182a6057cf46a154666c6f2888702d4109504b4da29Alon Albert            mExtendedDirectories = new ArrayList<DirectoryPartition>();
183ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        }
184e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
185e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        int videoCapabilities = CallUtil.getVideoCallingAvailability(context);
186e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mIsVideoEnabled = (videoCapabilities & CallUtil.VIDEO_CALLING_ENABLED) != 0;
187e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mIsPresenceEnabled = (videoCapabilities & CallUtil.VIDEO_CALLING_PRESENCE) != 0;
18863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
18963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
19063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    protected CharSequence getUnknownNameText() {
19163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        return mUnknownNameText;
19263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
19363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
19463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    @Override
19563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public void configureLoader(CursorLoader loader, long directoryId) {
196ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        String query = getQueryString();
197ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        if (query == null) {
198ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            query = "";
199ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        }
200ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        if (isExtendedDirectory(directoryId)) {
201ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            final DirectoryPartition directory = getExtendedDirectoryFromId(directoryId);
202768324c2d917f9ce79747007c57efcefbc06b472Alon Albert            final String contentUri = directory.getContentUri();
203768324c2d917f9ce79747007c57efcefbc06b472Alon Albert            if (contentUri == null) {
204768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                throw new IllegalStateException("Extended directory must have a content URL: "
205768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                        + directory);
206768324c2d917f9ce79747007c57efcefbc06b472Alon Albert            }
207768324c2d917f9ce79747007c57efcefbc06b472Alon Albert            final Builder builder = Uri.parse(contentUri).buildUpon();
208ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            builder.appendPath(query);
209ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
210ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    String.valueOf(getDirectoryResultLimit(directory)));
211ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            loader.setUri(builder.build());
212ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
213ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        } else {
214bf0104458b0c59762f0fc9df8c9012fca33220abRicky Wai            final boolean isRemoteDirectoryQuery
215bf0104458b0c59762f0fc9df8c9012fca33220abRicky Wai                    = DirectoryCompat.isRemoteDirectoryId(directoryId);
216ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            final Builder builder;
217ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            if (isSearchMode()) {
218ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                final Uri baseUri;
219ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                if (isRemoteDirectoryQuery) {
220cd0b29ddbf3648e48f048196c62245d545bc6122Ricky Wai                    baseUri = PhoneCompat.getContentFilterUri();
221ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                } else if (mUseCallableUri) {
222cd0b29ddbf3648e48f048196c62245d545bc6122Ricky Wai                    baseUri = CallableCompat.getContentFilterUri();
223ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                } else {
224cd0b29ddbf3648e48f048196c62245d545bc6122Ricky Wai                    baseUri = PhoneCompat.getContentFilterUri();
225ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
226ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                builder = baseUri.buildUpon();
227ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                builder.appendPath(query);      // Builder will encode the query
228ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
229ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                        String.valueOf(directoryId));
230ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                if (isRemoteDirectoryQuery) {
231ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
232ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                            String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
233ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
2347a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            } else {
235e3cc993cb72230b0ca9465763d927b8a851da8fbWenyi Wang                Uri baseUri = mUseCallableUri ? Callable.CONTENT_URI : Phone.CONTENT_URI;
236ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                builder = baseUri.buildUpon().appendQueryParameter(
237ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                        ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT));
238ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                if (isSectionHeaderDisplayEnabled()) {
239d9ba7ce0739281fc903ece843b5c84e10344adb3Yorke Lee                    builder.appendQueryParameter(Phone.EXTRA_ADDRESS_BOOK_INDEX, "true");
240ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
241ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                applyFilter(loader, builder, directoryId, getFilter());
2427a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            }
243ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
24441d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            // Ignore invalid phone numbers that are too long. These can potentially cause freezes
24541d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            // in the UI and there is no reason to display them.
24641d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            final String prevSelection = loader.getSelection();
24741d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            final String newSelection;
24841d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            if (!TextUtils.isEmpty(prevSelection)) {
24941d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee                newSelection = prevSelection + " AND " + IGNORE_NUMBER_TOO_LONG_CLAUSE;
25041d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            } else {
25141d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee                newSelection = IGNORE_NUMBER_TOO_LONG_CLAUSE;
25241d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            }
25341d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee            loader.setSelection(newSelection);
25441d16000cdd94f5f69f5d5c7c6c1519d82bc15feYorke Lee
255ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            // Remove duplicates when it is possible.
256ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
257ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            loader.setUri(builder.build());
258ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
259ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            // TODO a projection that includes the search snippet
260495c732e471c1c68db91ca6e824440130fdb7146Yorke Lee            if (getContactNameDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_PRIMARY) {
261ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                loader.setProjection(PhoneQuery.PROJECTION_PRIMARY);
26263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            } else {
263ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                loader.setProjection(PhoneQuery.PROJECTION_ALTERNATIVE);
2647a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            }
265ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
266495c732e471c1c68db91ca6e824440130fdb7146Yorke Lee            if (getSortOrder() == ContactsPreferences.SORT_ORDER_PRIMARY) {
267ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                loader.setSortOrder(Phone.SORT_KEY_PRIMARY);
268ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            } else {
269ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                loader.setSortOrder(Phone.SORT_KEY_ALTERNATIVE);
27063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            }
27163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
272ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    }
27363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
2741a2b2a318d9d0dacf183d49fd2363cb79a9f2335Jay Shrauner    protected boolean isExtendedDirectory(long directoryId) {
275ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        return directoryId >= mFirstExtendedDirectoryId;
276ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    }
27763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
278ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    private DirectoryPartition getExtendedDirectoryFromId(long directoryId) {
279ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        final int directoryIndex = (int) (directoryId - mFirstExtendedDirectoryId);
280ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        return mExtendedDirectories.get(directoryIndex);
28163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
28263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
28363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    /**
28463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     * Configure {@code loader} and {@code uriBuilder} according to {@code directoryId} and {@code
28563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     * filter}.
28663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     */
28763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    private void applyFilter(CursorLoader loader, Uri.Builder uriBuilder, long directoryId,
28863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            ContactListFilter filter) {
28963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        if (filter == null || directoryId != Directory.DEFAULT) {
29063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            return;
29163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
29263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
29363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        final StringBuilder selection = new StringBuilder();
29463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        final List<String> selectionArgs = new ArrayList<String>();
29563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
29663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        switch (filter.filterType) {
29763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            case ContactListFilter.FILTER_TYPE_CUSTOM: {
29863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                selection.append(Contacts.IN_VISIBLE_GROUP + "=1");
29963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
30063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                break;
30163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            }
30263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            case ContactListFilter.FILTER_TYPE_ACCOUNT: {
30363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                filter.addAccountQueryParameterToUrl(uriBuilder);
30463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                break;
30563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            }
30663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS:
30763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            case ContactListFilter.FILTER_TYPE_DEFAULT:
30863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                break; // No selection needed.
30963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
31063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                break; // This adapter is always "phone only", so no selection needed either.
31163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            default:
31263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                Log.w(TAG, "Unsupported filter type came " +
31363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                        "(type: " + filter.filterType + ", toString: " + filter + ")" +
31463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                        " showing all contacts.");
31563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                // No selection.
31663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                break;
31763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
31863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        loader.setSelection(selection.toString());
31963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
32063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
32163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
32263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    @Override
32363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public String getContactDisplayName(int position) {
3247a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        return ((Cursor) getItem(position)).getString(PhoneQuery.DISPLAY_NAME);
3257a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    }
3267a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner
3277a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    public String getPhoneNumber(int position) {
3287a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        final Cursor item = (Cursor)getItem(position);
3297a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        return item != null ? item.getString(PhoneQuery.PHONE_NUMBER) : null;
33063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
33163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
33263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    /**
33363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     * Builds a {@link Data#CONTENT_URI} for the given cursor position.
33463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     *
33563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     * @return Uri for the data. may be null if the cursor is not ready.
33663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng     */
33763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public Uri getDataUri(int position) {
3387a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        final int partitionIndex = getPartitionForPosition(position);
3397a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        final Cursor item = (Cursor)getItem(position);
3407a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        return item != null ? getDataUri(partitionIndex, item) : null;
3417a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    }
3427a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner
3437a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    public Uri getDataUri(int partitionIndex, Cursor cursor) {
3446af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        final long directoryId =
3456af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert                ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
346bf0104458b0c59762f0fc9df8c9012fca33220abRicky Wai        if (DirectoryCompat.isRemoteDirectoryId(directoryId)) {
347d19d35ef8347038f5296ed7020cab79396874937Victor Chang            return null;
348d19d35ef8347038f5296ed7020cab79396874937Victor Chang        } else if (DirectoryCompat.isEnterpriseDirectoryId(directoryId)) {
349d19d35ef8347038f5296ed7020cab79396874937Victor Chang            /*
350d19d35ef8347038f5296ed7020cab79396874937Victor Chang             * ContentUris.withAppendedId(Data.CONTENT_URI, phoneId), is invalid if
351d19d35ef8347038f5296ed7020cab79396874937Victor Chang             * isEnterpriseDirectoryId returns true, because the uri itself will fail since the
352d19d35ef8347038f5296ed7020cab79396874937Victor Chang             * ContactsProvider in Android Framework currently doesn't support it. return null until
353d19d35ef8347038f5296ed7020cab79396874937Victor Chang             * Android framework has enterprise version of Data.CONTENT_URI
354d19d35ef8347038f5296ed7020cab79396874937Victor Chang             */
355d19d35ef8347038f5296ed7020cab79396874937Victor Chang            return null;
356d19d35ef8347038f5296ed7020cab79396874937Victor Chang        } else {
3577a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            final long phoneId = cursor.getLong(PhoneQuery.PHONE_ID);
3587a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            return ContentUris.withAppendedId(Data.CONTENT_URI, phoneId);
35963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
36063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
36163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
3626a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn    /**
3636a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn     * Retrieves the lookup key for the given cursor position.
3646a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn     *
3656a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn     * @param position The cursor position.
3666a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn     * @return The lookup key.
3676a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn     */
3686a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn    public String getLookupKey(int position) {
3696a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        final Cursor item = (Cursor)getItem(position);
3706a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn        return item != null ? item.getString(PhoneQuery.LOOKUP_KEY) : null;
3716a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn    }
3726a5cdf69228f23ecd0d13019ac7bcc16ccf375cdTyler Gunn
37363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    @Override
3741f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    protected ContactListItemView newView(
3751f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
3761f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        ContactListItemView view = super.newView(context, partition, cursor, position, parent);
37763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        view.setUnknownNameText(mUnknownNameText);
37863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        view.setQuickContactEnabled(isQuickContactEnabled());
37963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        view.setPhotoPosition(mPhotoPosition);
38063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        return view;
38163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
38263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
383a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    protected void setHighlight(ContactListItemView view, Cursor cursor) {
384a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        view.setHighlightedPrefix(isSearchMode() ? getUpperCaseQueryString() : null);
385a81953a2b1818066ef5e44817f374ac288bab343Christine Chen    }
386a81953a2b1818066ef5e44817f374ac288bab343Christine Chen
387f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    // Override default, which would return number of phone numbers, so we
388f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    // instead return number of contacts.
389f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    @Override
390f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    protected int getResultCount(Cursor cursor) {
391f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        if (cursor == null) {
392f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner            return 0;
393f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        }
394f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        cursor.moveToPosition(-1);
395f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        long curContactId = -1;
396f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        int numContacts = 0;
397f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        while(cursor.moveToNext()) {
398f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner            final long contactId = cursor.getLong(PhoneQuery.CONTACT_ID);
399f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner            if (contactId != curContactId) {
400f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner                curContactId = contactId;
401f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner                ++numContacts;
402f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner            }
403f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        }
404f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        return numContacts;
405f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    }
406f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner
40763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    @Override
40863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    protected void bindView(View itemView, int partition, Cursor cursor, int position) {
409aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell        super.bindView(itemView, partition, cursor, position);
41063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        ContactListItemView view = (ContactListItemView)itemView;
41163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
412a81953a2b1818066ef5e44817f374ac288bab343Christine Chen        setHighlight(view, cursor);
41363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
41463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        // Look at elements before and after this position, checking if contact IDs are same.
41563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        // If they have one same contact ID, it means they can be grouped.
41663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        //
41763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        // In one group, only the first entry will show its photo and its name, and the other
41863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        // entries in the group show just their data (e.g. phone number, email address).
41963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        cursor.moveToPosition(position);
42063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        boolean isFirstEntry = true;
42163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        boolean showBottomDivider = true;
4227a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        final long currentContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
42363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        if (cursor.moveToPrevious() && !cursor.isBeforeFirst()) {
4247a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            final long previousContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
42563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            if (currentContactId == previousContactId) {
42663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                isFirstEntry = false;
42763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            }
42863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
42963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        cursor.moveToPosition(position);
43063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        if (cursor.moveToNext() && !cursor.isAfterLast()) {
4317a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            final long nextContactId = cursor.getLong(PhoneQuery.CONTACT_ID);
43263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            if (currentContactId == nextContactId) {
43363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                // The following entry should be in the same group, which means we don't want a
43463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                // divider between them.
43563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                // TODO: we want a different divider than the divider between groups. Just hiding
43663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                // this divider won't be enough.
43763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng                showBottomDivider = false;
43863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            }
43963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
44063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        cursor.moveToPosition(position);
44163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
4424cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        bindViewId(view, cursor, PhoneQuery.PHONE_ID);
4434cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell
44463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        bindSectionHeaderAndDivider(view, position);
44563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        if (isFirstEntry) {
44663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            bindName(view, cursor);
44763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            if (isQuickContactEnabled()) {
4487a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner                bindQuickContact(view, partition, cursor, PhoneQuery.PHOTO_ID,
4497a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner                        PhoneQuery.PHOTO_URI, PhoneQuery.CONTACT_ID,
4506084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee                        PhoneQuery.LOOKUP_KEY, PhoneQuery.DISPLAY_NAME);
45163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            } else {
4527a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner                if (getDisplayPhotos()) {
4537a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner                    bindPhoto(view, partition, cursor);
4547a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner                }
45563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            }
45663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        } else {
45763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            unbindName(view);
45863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
45963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            view.removePhotoView(true, false);
46063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
4616af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert
4626af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
463e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        bindPhoneNumber(view, cursor, directory.isDisplayNumber(), position);
46463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
46563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
466e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    protected void bindPhoneNumber(ContactListItemView view, Cursor cursor, boolean displayNumber,
467e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn            int position) {
46863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        CharSequence label = null;
4696af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        if (displayNumber &&  !cursor.isNull(PhoneQuery.PHONE_TYPE)) {
47063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            final int type = cursor.getInt(PhoneQuery.PHONE_TYPE);
47163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            final String customLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
47263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
47363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            // TODO cache
47463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            label = Phone.getTypeLabel(getContext().getResources(), type, customLabel);
47563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
47663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        view.setLabel(label);
4776af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        final String text;
4786af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        if (displayNumber) {
4796af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert            text = cursor.getString(PhoneQuery.PHONE_NUMBER);
4806af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        } else {
4816af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert            // Display phone label. If that's null, display geocoded location for the number
4826af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert            final String phoneLabel = cursor.getString(PhoneQuery.PHONE_LABEL);
4836af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert            if (phoneLabel != null) {
4846af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert                text = phoneLabel;
4856af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert            } else {
4866af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert                final String phoneNumber = cursor.getString(PhoneQuery.PHONE_NUMBER);
4876af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert                text = GeoUtil.getGeocodedLocationFor(mContext, phoneNumber);
4886af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert            }
4896af66a800ccf7599ea37374c8fc99a1489ef8fcbAlon Albert        }
49062dbbf2f10e0e3bcb4d699d859a71a68c896f4a7Andrew Lee        view.setPhoneNumber(text, mCountryIso);
491e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
49292a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        if (CompatUtils.isVideoCompatible()) {
49392a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            // Determine if carrier presence indicates the number supports video calling.
49492a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            int carrierPresence = cursor.getInt(PhoneQuery.CARRIER_PRESENCE);
49592a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            boolean isPresent = (carrierPresence & Phone.CARRIER_PRESENCE_VT_CAPABLE) != 0;
496e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
49792a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            boolean isVideoIconShown = mIsVideoEnabled && (
49892a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang                    mIsPresenceEnabled && isPresent || !mIsPresenceEnabled);
49992a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang            view.setShowVideoCallIcon(isVideoIconShown, mListener, position);
50092a65fd6f8af0d357376f7a9c0d3eafad795e79cWenyi Wang        }
50163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
50263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
50363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
50463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        if (isSectionHeaderDisplayEnabled()) {
50563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            Placement placement = getItemPlacementInSection(position);
50663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
50763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        } else {
50863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng            view.setSectionHeader(null);
50963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
51063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
51163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
51263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    protected void bindName(final ContactListItemView view, Cursor cursor) {
5137a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        view.showDisplayName(cursor, PhoneQuery.DISPLAY_NAME, getContactNameDisplayOrder());
51463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        // Note: we don't show phonetic names any more (see issue 5265330)
51563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
51663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
51763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    protected void unbindName(final ContactListItemView view) {
51863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        view.hideDisplayName();
51963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
52063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
521ad8ca26bd5a5fa5ab7e872ef4438b09fc21d90f0Tony Mak    @Override
522ad8ca26bd5a5fa5ab7e872ef4438b09fc21d90f0Tony Mak    protected void bindWorkProfileIcon(final ContactListItemView view, int partition) {
523d19d35ef8347038f5296ed7020cab79396874937Victor Chang        final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
524d19d35ef8347038f5296ed7020cab79396874937Victor Chang        final long directoryId = directory.getDirectoryId();
525d19d35ef8347038f5296ed7020cab79396874937Victor Chang        final long userType = ContactsUtils.determineUserType(directoryId, null);
52686e847593405bf39333af825cfa58b2ac057d4dfVictor Chang        // Work directory must not be a extended directory. An extended directory is custom
52786e847593405bf39333af825cfa58b2ac057d4dfVictor Chang        // directory in the app, but not a directory provided by framework. So it can't be
52886e847593405bf39333af825cfa58b2ac057d4dfVictor Chang        // USER_TYPE_WORK.
52986e847593405bf39333af825cfa58b2ac057d4dfVictor Chang        view.setWorkProfileIconEnabled(
53086e847593405bf39333af825cfa58b2ac057d4dfVictor Chang                !isExtendedDirectory(directoryId) && userType == ContactsUtils.USER_TYPE_WORK);
531d19d35ef8347038f5296ed7020cab79396874937Victor Chang    }
532d19d35ef8347038f5296ed7020cab79396874937Victor Chang
5337a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner    protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
5347a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        if (!isPhotoSupported(partitionIndex)) {
5357a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            view.removePhotoView();
5367a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            return;
5377a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        }
5387a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner
53963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        long photoId = 0;
5407a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
5417a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
54263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        }
54363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
5447a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        if (photoId != 0) {
5453f9c2f426058413055fa54c08c69ad9461717658Yorke Lee            getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
5463f9c2f426058413055fa54c08c69ad9461717658Yorke Lee                    getCircularPhotos(), null);
5477a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        } else {
5487a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
5497a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner            final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
5506084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee
5516084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            DefaultImageRequest request = null;
5526084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            if (photoUri == null) {
5536084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee                final String displayName = cursor.getString(PhoneQuery.DISPLAY_NAME);
5546084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee                final String lookupKey = cursor.getString(PhoneQuery.LOOKUP_KEY);
5551b1221ba8291599675cb1399713c966728ed3c52Brian Attwell                request = new DefaultImageRequest(displayName, lookupKey, getCircularPhotos());
5566084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            }
5573f9c2f426058413055fa54c08c69ad9461717658Yorke Lee            getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
5583f9c2f426058413055fa54c08c69ad9461717658Yorke Lee                    getCircularPhotos(), request);
5597a160466a38bb631da02b7e93ab907eb2b3a2558Jay Shrauner        }
56063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
56163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
56263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public void setPhotoPosition(ContactListItemView.PhotoPosition photoPosition) {
56363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        mPhotoPosition = photoPosition;
56463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
56563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
56663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public ContactListItemView.PhotoPosition getPhotoPosition() {
56763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        return mPhotoPosition;
56863ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
56963ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
57063ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public void setUseCallableUri(boolean useCallableUri) {
57163ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        mUseCallableUri = useCallableUri;
57263ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
57363ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng
57463ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    public boolean usesCallableUri() {
57563ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng        return mUseCallableUri;
57663ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng    }
577ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
578ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    /**
579ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     * Override base implementation to inject extended directories between local & remote
580ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     * directories. This is done in the following steps:
581ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     * 1. Call base implementation to add directories from the cursor.
582ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     * 2. Iterate all base directories and establish the following information:
583ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     *   a. The highest directory id so that we can assign unused id's to the extended directories.
584ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     *   b. The index of the last non-remote directory. This is where we will insert extended
585ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     *      directories.
586ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     * 3. Iterate the extended directories and for each one, assign an ID and insert it in the
587ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     *    proper location.
588ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad     */
589ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    @Override
590ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    public void changeDirectories(Cursor cursor) {
591ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        super.changeDirectories(cursor);
592ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        if (getDirectorySearchMode() == DirectoryListLoader.SEARCH_MODE_NONE) {
593ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            return;
594ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        }
595ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        final int numExtendedDirectories = mExtendedDirectories.size();
596ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        if (getPartitionCount() == cursor.getCount() + numExtendedDirectories) {
597ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            // already added all directories;
598ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            return;
599ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        }
600ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        //
601ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        mFirstExtendedDirectoryId = Long.MAX_VALUE;
602ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        if (numExtendedDirectories > 0) {
603ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            // The Directory.LOCAL_INVISIBLE is not in the cursor but we can't reuse it's
604ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            // "special" ID.
605ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            long maxId = Directory.LOCAL_INVISIBLE;
606ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            int insertIndex = 0;
607ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            for (int i = 0, n = getPartitionCount(); i < n; i++) {
608ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                final DirectoryPartition partition = (DirectoryPartition) getPartition(i);
609ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                final long id = partition.getDirectoryId();
610ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                if (id > maxId) {
611ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    maxId = id;
612ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
613bf0104458b0c59762f0fc9df8c9012fca33220abRicky Wai                if (!DirectoryCompat.isRemoteDirectoryId(id)) {
614ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    // assuming remote directories come after local, we will end up with the index
615ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    // where we should insert extended directories. This also works if there are no
616ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    // remote directories at all.
617ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    insertIndex = i + 1;
618ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
619ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            }
620ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            // Extended directories ID's cannot collide with base directories
621ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            mFirstExtendedDirectoryId = maxId + 1;
622ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            for (int i = 0; i < numExtendedDirectories; i++) {
623ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                final long id = mFirstExtendedDirectoryId + i;
624ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                final DirectoryPartition directory = mExtendedDirectories.get(i);
625ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                if (getPartitionByDirectoryId(id) == -1) {
626ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    addPartition(insertIndex, directory);
627ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    directory.setDirectoryId(id);
628ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
629ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            }
630ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        }
631ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    }
632b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert
63344192bbce136eda4305e8ffa2cafc7663b3e25d2Victor Chang    @Override
634b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert    protected Uri getContactUri(int partitionIndex, Cursor cursor,
635b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert            int contactIdColumn, int lookUpKeyColumn) {
636b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert        final DirectoryPartition directory = (DirectoryPartition) getPartition(partitionIndex);
637b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert        final long directoryId = directory.getDirectoryId();
638b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert        if (!isExtendedDirectory(directoryId)) {
639b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert            return super.getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn);
640b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert        }
641b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert        return Contacts.CONTENT_LOOKUP_URI.buildUpon()
642b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert                .appendPath(Constants.LOOKUP_URI_ENCODED)
643b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert                .appendQueryParameter(Directory.DISPLAY_NAME, directory.getLabel())
644b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert                .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
645b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert                        String.valueOf(directoryId))
646a63fbce25ea8cdcd7f44a4d65e9bdf4aa81560dbYorke Lee                .encodedFragment(cursor.getString(lookUpKeyColumn))
647b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert                .build();
648b5632a6ebe19ba1627f0e850b00e0e9de0fcd3abAlon Albert    }
649e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
650e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    public Listener getListener() {
651e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        return mListener;
652e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    }
653e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn
654e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    public void setListener(Listener listener) {
655e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn        mListener = listener;
656e31b0ea8b61d5744921ff7491d5dbe1a8273c05fTyler Gunn    }
65763ac534dcf60e9a6c651ef2434557bec922b9a7dChiao Cheng}
658