137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan/*
237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * Copyright (C) 2011 The Android Open Source Project
337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan *
437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * Licensed under the Apache License, Version 2.0 (the "License");
537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * you may not use this file except in compliance with the License.
637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * You may obtain a copy of the License at
737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan *
837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan *      http://www.apache.org/licenses/LICENSE-2.0
937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan *
1037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * Unless required by applicable law or agreed to in writing, software
1137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * distributed under the License is distributed on an "AS IS" BASIS,
1237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * See the License for the specific language governing permissions and
1437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * limitations under the License
1537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan */
1637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
1737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanpackage com.android.contacts.activities;
1837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
1937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.app.Activity;
2037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.app.Dialog;
2137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.app.ProgressDialog;
2237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.AsyncQueryHandler;
2337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.ContentProviderOperation;
2437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.ContentProviderResult;
2537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.ContentResolver;
2637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.ContentUris;
2737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.Context;
2837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.Intent;
2937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.content.OperationApplicationException;
3037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.database.Cursor;
3137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.graphics.Bitmap;
3237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.graphics.BitmapFactory;
3337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.net.Uri;
3437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.net.Uri.Builder;
3537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.os.AsyncTask;
3637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.os.Bundle;
3737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.os.RemoteException;
3837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract;
3937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Email;
4037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Im;
4137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Nickname;
4237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Phone;
4337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.Photo;
44ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onukiimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
4537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
4637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.Contacts;
4737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.Data;
4837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.provider.ContactsContract.RawContacts;
49c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoroimport android.provider.ContactsContract.RawContactsEntity;
5037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.telephony.PhoneNumberUtils;
5137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.text.TextUtils;
5237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.util.Log;
5337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.view.LayoutInflater;
5437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.view.View;
5537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.view.View.OnClickListener;
5637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.view.ViewGroup;
5737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.widget.ImageView;
5837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.widget.TextView;
5937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport android.widget.Toast;
6037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
61e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
62e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.Editor;
63e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.ViewIdGenerator;
64e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.model.AccountTypeManager;
65851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContact;
66851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDelta;
67851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDelta.ValuesDelta;
68851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDeltaList;
69851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactModifier;
70851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.account.AccountType;
71851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.account.AccountWithDataSet;
72851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.dataitem.DataKind;
73e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.DialogManager;
74e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.EmptyService;
75e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
7637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport java.lang.ref.WeakReference;
7737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport java.util.ArrayList;
7837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanimport java.util.HashMap;
79ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onukiimport java.util.List;
8037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
8137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan/**
8237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * This is a dialog-themed activity for confirming the addition of a detail to an existing contact
8337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * (once the user has selected this contact from a list of all contacts). The incoming intent
8437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan * must have an extra with max 1 phone or email specified, using
85a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki * {@link android.provider.ContactsContract.Intents.Insert#PHONE} with type
86a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki * {@link android.provider.ContactsContract.Intents.Insert#PHONE_TYPE} or
87a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki * {@link android.provider.ContactsContract.Intents.Insert#EMAIL} with type
88a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki * {@link android.provider.ContactsContract.Intents.Insert#EMAIL_TYPE} intent keys.
89ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki *
90ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * If the selected contact doesn't contain editable raw_contacts, it'll create a new raw_contact
91ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * on the first editable account found, and the data will be added to this raw_contact.  The newly
92ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * created raw_contact will be joined with the selected contact with aggregation-exceptions.
93ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki *
94ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * TODO: Don't open this activity if there's no editable accounts.
95ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * If there's no editable accounts on the system, we'll set {@link #mIsReadOnly} and the dialog
96ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * just says "contact is not editable".  It's slightly misleading because this really means
97ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * "there's no editable accounts", but in this case we shouldn't show the contact picker in the
98ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * first place.
99ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * Note when there's no accounts, it *is* okay to show the picker / dialog, because the local-only
100ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki * contacts are writable.
10137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan */
10237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuanpublic class ConfirmAddDetailActivity extends Activity implements
10337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        DialogManager.DialogShowingViewActivity {
10437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
105a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private static final String TAG = "ConfirmAdd"; // The class name is too long to be a tag.
106a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private static final boolean VERBOSE_LOGGING = Log.isLoggable(TAG, Log.VERBOSE);
10737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
10837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private LayoutInflater mInflater;
10937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private View mRootView;
11037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private TextView mDisplayNameView;
11137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private TextView mReadOnlyWarningView;
11237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private ImageView mPhotoView;
11337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private ViewGroup mEditorContainerView;
114fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    private static WeakReference<ProgressDialog> sProgressDialog;
11537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
11637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private AccountTypeManager mAccountTypeManager;
11737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private ContentResolver mContentResolver;
11837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
11937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private AccountType mEditableAccountType;
12037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private Uri mContactUri;
12137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private long mContactId;
12237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private String mDisplayName;
123a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private boolean mIsReadOnly;
12437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
12537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private QueryHandler mQueryHandler;
126a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki
127851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    /** {@link RawContactDeltaList} for the entire selected contact. */
128851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private RawContactDeltaList mEntityDeltaList;
12937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
130851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    /** {@link RawContactDeltaList} for the editable account */
131851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private RawContactDelta mRawContactDelta;
132a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki
13337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private String mMimetype = Phone.CONTENT_ITEM_TYPE;
13437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
13537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
13637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * DialogManager may be needed if the user wants to apply a "custom" label to the contact detail
13737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
13837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private final DialogManager mDialogManager = new DialogManager(this);
13937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
14037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
14137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * PhotoQuery contains the projection used for retrieving the name and photo
14237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * ID of a contact.
14337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
14437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private interface ContactQuery {
14537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final String[] COLUMNS = new String[] {
14637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Contacts._ID,
14737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Contacts.LOOKUP_KEY,
14837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Contacts.PHOTO_ID,
14937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Contacts.DISPLAY_NAME,
15037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        };
15137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int _ID = 0;
15237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int LOOKUP_KEY = 1;
15337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int PHOTO_ID = 2;
15437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int DISPLAY_NAME = 3;
15537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
15637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
15737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
15837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * PhotoQuery contains the projection used for retrieving the raw bytes of
15937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * the contact photo.
16037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
16137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private interface PhotoQuery {
16237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final String[] COLUMNS = new String[] {
16337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Photo.PHOTO
16437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        };
16537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
16637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int PHOTO = 0;
16737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
16837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
16937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
17037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * ExtraInfoQuery contains the projection used for retrieving the extra info
17137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * on a contact (only needed if someone else exists with the same name as
17237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * this contact).
17337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
17437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private interface ExtraInfoQuery {
17537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final String[] COLUMNS = new String[] {
17637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            RawContacts.CONTACT_ID,
17737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Data.MIMETYPE,
17837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Data.DATA1,
17937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        };
18037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int CONTACT_ID = 0;
18137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int MIMETYPE = 1;
18237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final int DATA1 = 2;
18337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
18437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
18537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
18637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * List of mimetypes to use in order of priority to display for a contact in
18737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * a disambiguation case. For example, if the contact does not have a
18837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * nickname, use the email field, and etc.
18937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
190a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private static final String[] MIME_TYPE_PRIORITY_LIST = new String[] {
191a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            Nickname.CONTENT_ITEM_TYPE, Email.CONTENT_ITEM_TYPE, Im.CONTENT_ITEM_TYPE,
192a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            StructuredPostal.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE };
19337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
19437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private static final int TOKEN_CONTACT_INFO = 0;
19537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private static final int TOKEN_PHOTO_QUERY = 1;
19637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private static final int TOKEN_DISAMBIGUATION_QUERY = 2;
19737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private static final int TOKEN_EXTRA_INFO_QUERY = 3;
19837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
19937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private final OnClickListener mDetailsButtonClickListener = new OnClickListener() {
20037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
20137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        public void onClick(View v) {
202a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            if (mIsReadOnly) {
20337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                onSaveCompleted(true);
20437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } else {
20537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                doSaveAction();
20637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
20737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
20837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    };
20937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
21037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private final OnClickListener mDoneButtonClickListener = new OnClickListener() {
21137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
21237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        public void onClick(View v) {
21337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            doSaveAction();
21437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
21537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    };
21637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
21737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private final OnClickListener mCancelButtonClickListener = new OnClickListener() {
21837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
21937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        public void onClick(View v) {
22037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            setResult(RESULT_CANCELED);
22137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            finish();
22237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
22337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    };
22437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
22537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    @Override
22637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    protected void onCreate(Bundle icicle) {
22737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        super.onCreate(icicle);
22837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
22937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
23037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mContentResolver = getContentResolver();
23137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
23237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final Intent intent = getIntent();
23337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mContactUri = intent.getData();
23437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
23537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        if (mContactUri == null) {
23637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            setResult(RESULT_CANCELED);
23737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            finish();
23837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
23937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
24037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        Bundle extras = intent.getExtras();
24137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        if (extras != null) {
24237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            if (extras.containsKey(ContactsContract.Intents.Insert.PHONE)) {
24337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                mMimetype = Phone.CONTENT_ITEM_TYPE;
24437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } else if (extras.containsKey(ContactsContract.Intents.Insert.EMAIL)) {
24537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                mMimetype = Email.CONTENT_ITEM_TYPE;
24637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } else {
24737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                throw new IllegalStateException("Error: No valid mimetype found in intent extras");
24837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
24937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
25037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
25137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mAccountTypeManager = AccountTypeManager.getInstance(this);
25237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
25337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        setContentView(R.layout.confirm_add_detail_activity);
25437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
25537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mRootView = findViewById(R.id.root_view);
25637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mReadOnlyWarningView = (TextView) findViewById(R.id.read_only_warning);
25737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
25837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Setup "header" (containing contact info) to save the detail and then go to the editor
25937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        findViewById(R.id.open_details_push_layer).setOnClickListener(mDetailsButtonClickListener);
26037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
26137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Setup "done" button to save the detail to the contact and exit.
26237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        findViewById(R.id.btn_done).setOnClickListener(mDoneButtonClickListener);
26337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
26437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Setup "cancel" button to return to previous activity.
26537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        findViewById(R.id.btn_cancel).setOnClickListener(mCancelButtonClickListener);
26637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
26737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Retrieve references to all the Views in the dialog activity.
26837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mDisplayNameView = (TextView) findViewById(R.id.name);
26937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mPhotoView = (ImageView) findViewById(R.id.photo);
27037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mEditorContainerView = (ViewGroup) findViewById(R.id.editor_container);
27137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
272a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        resetAsyncQueryHandler();
273a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        startContactQuery(mContactUri);
27437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
27537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        new QueryEntitiesTask(this).execute(intent);
27637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
27737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
27837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    @Override
27937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    public DialogManager getDialogManager() {
28037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        return mDialogManager;
28137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
28237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
28337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    @Override
28437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    protected Dialog onCreateDialog(int id, Bundle args) {
28537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        if (DialogManager.isManagedId(id)) return mDialogManager.onCreateDialog(id, args);
28637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
28737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Nobody knows about the Dialog
28837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        Log.w(TAG, "Unknown dialog requested, id: " + id + ", args: " + args);
28937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        return null;
29037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
29137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
29237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
29337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Reset the query handler by creating a new QueryHandler instance.
29437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
29537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void resetAsyncQueryHandler() {
29637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // the api AsyncQueryHandler.cancelOperation() doesn't really work. Since we really
29737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // need the old async queries to be cancelled, let's do it the hard way.
29837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mQueryHandler = new QueryHandler(mContentResolver);
29937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
30037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
30137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
30237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Internal method to query contact by Uri.
30337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     *
30437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * @param contactUri the contact uri
30537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
306a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private void startContactQuery(Uri contactUri) {
30737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mQueryHandler.startQuery(TOKEN_CONTACT_INFO, contactUri, contactUri, ContactQuery.COLUMNS,
30837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                null, null, null);
30937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
31037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
31137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
31237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Internal method to query contact photo by photo id and uri.
31337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     *
31437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * @param photoId the photo id.
31537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * @param lookupKey the lookup uri.
31637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
317a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private void startPhotoQuery(long photoId, Uri lookupKey) {
31837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mQueryHandler.startQuery(TOKEN_PHOTO_QUERY, lookupKey,
31937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                ContentUris.withAppendedId(Data.CONTENT_URI, photoId),
32037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                PhotoQuery.COLUMNS, null, null, null);
32137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
32237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
32337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
32437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Internal method to query for contacts with a given display name.
32537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     *
32637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * @param contactDisplayName the display name to look for.
32737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
32837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void startDisambiguationQuery(String contactDisplayName) {
32937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Apply a limit of 1 result to the query because we only need to
33037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // determine whether or not at least one other contact has the same
33137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // name. We don't need to find ALL other contacts with the same name.
3321d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        final Builder builder = Contacts.CONTENT_URI.buildUpon();
33337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        builder.appendQueryParameter("limit", String.valueOf(1));
3341d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        final Uri uri = builder.build();
3351d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan
3361d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        final String displayNameSelection;
3371d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        final String[] selectionArgs;
3381d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        if (TextUtils.isEmpty(contactDisplayName)) {
3391d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan            displayNameSelection = Contacts.DISPLAY_NAME_PRIMARY + " IS NULL";
3401d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan            selectionArgs = new String[] { String.valueOf(mContactId) };
3411d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        } else {
3421d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan            displayNameSelection = Contacts.DISPLAY_NAME_PRIMARY + " = ?";
3431d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan            selectionArgs = new String[] { contactDisplayName, String.valueOf(mContactId) };
3441d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan        }
34537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mQueryHandler.startQuery(TOKEN_DISAMBIGUATION_QUERY, null, uri,
34637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                new String[] { Contacts._ID } /* unused projection but a valid one was needed */,
3471d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan                displayNameSelection + " AND " + Contacts.PHOTO_ID + " IS NULL AND "
3481d5fdfb2cec7d082c007b5f7ede20be44c24dc1aKatherine Kuan                + Contacts._ID + " <> ?", selectionArgs, null);
34937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
35037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
35137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
35237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Internal method to query for extra data fields for this contact.
35337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
35437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void startExtraInfoQuery() {
35537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mQueryHandler.startQuery(TOKEN_EXTRA_INFO_QUERY, null, Data.CONTENT_URI,
35637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                ExtraInfoQuery.COLUMNS, RawContacts.CONTACT_ID + " = ?",
35737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                new String[] { String.valueOf(mContactId) }, null);
35837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
35937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
360851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private static class QueryEntitiesTask extends AsyncTask<Intent, Void, RawContactDeltaList> {
36137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
36237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private ConfirmAddDetailActivity activityTarget;
36337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private String mSelection;
36437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
36537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        public QueryEntitiesTask(ConfirmAddDetailActivity target) {
36637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            activityTarget = target;
36737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
36837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
36937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
370851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        protected RawContactDeltaList doInBackground(Intent... params) {
37137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
37237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final Intent intent = params[0];
37337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
37437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final ContentResolver resolver = activityTarget.getContentResolver();
37537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
37637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Handle both legacy and new authorities
37737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final Uri data = intent.getData();
37837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final String authority = data.getAuthority();
37937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final String mimeType = intent.resolveType(resolver);
38037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
38137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            mSelection = "0";
38237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            String selectionArg = null;
38337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            if (ContactsContract.AUTHORITY.equals(authority)) {
38437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (Contacts.CONTENT_ITEM_TYPE.equals(mimeType)) {
38537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    // Handle selected aggregate
38637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    final long contactId = ContentUris.parseId(data);
38737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    selectionArg = String.valueOf(contactId);
38837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    mSelection = RawContacts.CONTACT_ID + "=?";
38937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                } else if (RawContacts.CONTENT_ITEM_TYPE.equals(mimeType)) {
39037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    final long rawContactId = ContentUris.parseId(data);
39137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    final long contactId = queryForContactId(resolver, rawContactId);
39237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    selectionArg = String.valueOf(contactId);
39337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    mSelection = RawContacts.CONTACT_ID + "=?";
39437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
39537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } else if (android.provider.Contacts.AUTHORITY.equals(authority)) {
39637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                final long rawContactId = ContentUris.parseId(data);
39737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                selectionArg = String.valueOf(rawContactId);
39837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                mSelection = Data.RAW_CONTACT_ID + "=?";
39937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
40037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
401c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro            // Note that this query does not need to concern itself with whether the contact is
402c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro            // the user's profile, since the profile does not show up in the picker.
403851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            return RawContactDeltaList.fromQuery(RawContactsEntity.CONTENT_URI,
404c90f95e63684363d10ffe5ef8f08f2159fb5bfc0Dave Santoro                    activityTarget.getContentResolver(), mSelection,
40537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    new String[] { selectionArg }, null);
40637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
40737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
40837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private static long queryForContactId(ContentResolver resolver, long rawContactId) {
40937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Cursor contactIdCursor = null;
41037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            long contactId = -1;
41137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            try {
41237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                contactIdCursor = resolver.query(RawContacts.CONTENT_URI,
41337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        new String[] { RawContacts.CONTACT_ID },
41437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        RawContacts._ID + "=?", new String[] { String.valueOf(rawContactId) },
41537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        null);
41637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (contactIdCursor != null && contactIdCursor.moveToFirst()) {
41737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    contactId = contactIdCursor.getLong(0);
41837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
41937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } finally {
42037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (contactIdCursor != null) {
42137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    contactIdCursor.close();
42237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
42337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
42437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            return contactId;
42537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
42637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
42737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
428851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        protected void onPostExecute(RawContactDeltaList entityList) {
42937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            if (activityTarget.isFinishing()) {
43037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                return;
43137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
432ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            if ((entityList == null) || (entityList.size() == 0)) {
433ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                Log.e(TAG, "Contact not found.");
434ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                activityTarget.finish();
435ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                return;
436ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            }
437ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
43837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            activityTarget.setEntityDeltaList(entityList);
43937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
44037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
44137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
44237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private class QueryHandler extends AsyncQueryHandler {
44337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
44437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        public QueryHandler(ContentResolver cr) {
44537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            super(cr);
44637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
44737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
44837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
44937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
45037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            try {
45137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (this != mQueryHandler) {
45237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    Log.d(TAG, "onQueryComplete: discard result, the query handler is reset!");
45337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    return;
45437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
45537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (ConfirmAddDetailActivity.this.isFinishing()) {
45637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    return;
45737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
45837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
45937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                switch (token) {
46037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    case TOKEN_PHOTO_QUERY: {
46137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // Set the photo
46237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        Bitmap photoBitmap = null;
46337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        if (cursor != null && cursor.moveToFirst()
46437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                && !cursor.isNull(PhotoQuery.PHOTO)) {
46537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            byte[] photoData = cursor.getBlob(PhotoQuery.PHOTO);
46637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            photoBitmap = BitmapFactory.decodeByteArray(photoData, 0,
46737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    photoData.length, null);
46837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        }
46937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
47037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        if (photoBitmap != null) {
47137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            mPhotoView.setImageBitmap(photoBitmap);
47237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        }
47337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
47437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        break;
47537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    }
47637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    case TOKEN_CONTACT_INFO: {
47737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // Set the contact's name
47837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        if (cursor != null && cursor.moveToFirst()) {
47937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // Get the cursor values
48037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            mDisplayName = cursor.getString(ContactQuery.DISPLAY_NAME);
48137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            final long photoId = cursor.getLong(ContactQuery.PHOTO_ID);
48237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
48337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // If there is no photo ID, then do a disambiguation
48437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // query because other contacts could have the same
48537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // name as this contact.
48637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            if (photoId == 0) {
48737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                mContactId = cursor.getLong(ContactQuery._ID);
48837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                startDisambiguationQuery(mDisplayName);
48937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            } else {
49037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                // Otherwise do the photo query.
49137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                Uri lookupUri = Contacts.getLookupUri(mContactId,
49237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                        cursor.getString(ContactQuery.LOOKUP_KEY));
493a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki                                startPhotoQuery(photoId, lookupUri);
49437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                // Display the name because there is no
49537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                // disambiguation query.
49637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                setDisplayName();
497a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki                                showDialogContent();
49837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            }
49937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        }
50037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        break;
50137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    }
50237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    case TOKEN_DISAMBIGUATION_QUERY: {
50337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // If a cursor was returned with more than 0 results,
50437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // then at least one other contact exists with the same
50537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // name as this contact. Extra info on this contact must
50637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // be displayed to disambiguate the contact, so retrieve
50737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // those additional fields. Otherwise, no other contacts
50837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // with this name exists, so do nothing further.
50937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        if (cursor != null && cursor.getCount() > 0) {
51037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            startExtraInfoQuery();
51137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        } else {
51237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // If there are no other contacts with this name,
51337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // then display the name.
51437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            setDisplayName();
515a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki                            showDialogContent();
51637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        }
51737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        break;
51837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    }
51937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    case TOKEN_EXTRA_INFO_QUERY: {
52037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // This case should only occur if there are one or more
52137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        // other contacts with the same contact name.
52237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        if (cursor != null && cursor.moveToFirst()) {
52337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            HashMap<String, String> hashMapCursorData = new
52437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    HashMap<String, String>();
52537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
52637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // Convert the cursor data into a hashmap of
52737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // (mimetype, data value) pairs. If a contact has
52837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // multiple values with the same mimetype, it's fine
52937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // to override that hashmap entry because we only
53037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // need one value of that type.
53137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            while (!cursor.isAfterLast()) {
53237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                final String mimeType = cursor.getString(ExtraInfoQuery.MIMETYPE);
53337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                if (!TextUtils.isEmpty(mimeType)) {
53437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    String value = cursor.getString(ExtraInfoQuery.DATA1);
53537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    if (!TextUtils.isEmpty(value)) {
53637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                        // As a special case, phone numbers
53737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                        // should be formatted in a specific way.
53837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                        if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
53937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                            value = PhoneNumberUtils.formatNumber(value);
54037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                        }
54137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                        hashMapCursorData.put(mimeType, value);
54237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    }
54337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                }
54437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                cursor.moveToNext();
54537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            }
54637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
54737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // Find the first non-empty field according to the
54837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // mimetype priority list and display this under the
54937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            // contact's display name to disambiguate the contact.
550a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki                            for (String mimeType : MIME_TYPE_PRIORITY_LIST) {
55137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                if (hashMapCursorData.containsKey(mimeType)) {
55237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    setDisplayName();
55337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    setExtraInfoField(hashMapCursorData.get(mimeType));
55437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                    break;
55537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                                }
55637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                            }
557a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki                            showDialogContent();
55837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        }
55937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        break;
56037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    }
56137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
56237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } finally {
56337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                if (cursor != null) {
56437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    cursor.close();
56537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
56637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
56737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
56837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
56937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
570851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private void setEntityDeltaList(RawContactDeltaList entityList) {
571a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        if (entityList == null) {
572a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            throw new IllegalStateException();
573a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        }
574a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        if (VERBOSE_LOGGING) {
575a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            Log.v(TAG, "setEntityDeltaList: " + entityList);
576a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        }
577a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki
57837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mEntityDeltaList = entityList;
57937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
580ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        // Find the editable raw_contact.
581851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        mRawContactDelta = mEntityDeltaList.getFirstWritableRawContact(this);
582ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
583ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        // If no editable raw_contacts are found, create one.
584851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        if (mRawContactDelta == null) {
585851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            mRawContactDelta = addEditableRawContact(this, mEntityDeltaList);
586ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
587851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if ((mRawContactDelta != null) && VERBOSE_LOGGING) {
588ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                Log.v(TAG, "setEntityDeltaList: created editable raw_contact " + entityList);
589ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            }
590ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        }
591ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
592851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        if (mRawContactDelta == null) {
593ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            // Selected contact is read-only, and there's no editable account.
594a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            mIsReadOnly = true;
595a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            mEditableAccountType = null;
596a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        } else {
597a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            mIsReadOnly = false;
59837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
599851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            mEditableAccountType = mRawContactDelta.getRawContactAccountType(this);
600a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki
601a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            // Handle any incoming values that should be inserted
602a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            final Bundle extras = getIntent().getExtras();
603a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            if (extras != null && extras.size() > 0) {
604851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                // If there are any intent extras, add them as additional fields in the
605851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                // RawContactDelta.
606851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactModifier.parseExtras(this, mEditableAccountType, mRawContactDelta,
607851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                        extras);
608a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            }
60937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
610a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki
611a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        bindEditor();
61237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
61337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
61437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
615851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu     * Create an {@link RawContactDelta} for a raw_contact on the first editable account found, and add
616ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki     * to the list.  Also copy the structured name from an existing (read-only) raw_contact to the
617ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki     * new one, if any of the read-only contacts has a name.
618ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki     */
619851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private static RawContactDelta addEditableRawContact(Context context,
620851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDeltaList entityDeltaList) {
621ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        // First, see if there's an editable account.
622ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        final AccountTypeManager accounts = AccountTypeManager.getInstance(context);
623ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        final List<AccountWithDataSet> editableAccounts = accounts.getAccounts(true);
624ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        if (editableAccounts.size() == 0) {
625ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            // No editable account type found.  The dialog will be read-only mode.
626ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            return null;
627ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        }
628ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        final AccountWithDataSet editableAccount = editableAccounts.get(0);
629ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        final AccountType accountType = accounts.getAccountType(
630ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                editableAccount.type, editableAccount.dataSet);
631ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
632851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        // Create a new RawContactDelta for the new raw_contact.
633851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContact rawContact = new RawContact(context);
634851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        rawContact.setAccount(editableAccount);
635ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
636851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta entityDelta = new RawContactDelta(ValuesDelta.fromAfter(
637851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                rawContact.getValues()));
638ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
639ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        // Then, copy the structure name from an existing (read-only) raw_contact.
640851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContactDelta entity : entityDeltaList) {
641ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            final ArrayList<ValuesDelta> readOnlyNames =
642ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                    entity.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
643ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            if ((readOnlyNames != null) && (readOnlyNames.size() > 0)) {
644ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                final ValuesDelta readOnlyName = readOnlyNames.get(0);
645851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                final ValuesDelta newName = RawContactModifier.ensureKindExists(entityDelta,
646ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                        accountType, StructuredName.CONTENT_ITEM_TYPE);
647ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
648ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                // Copy all the data fields.
649851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                newName.copyStructuredNameFieldsFrom(readOnlyName);
650ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                break;
651ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki            }
652ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        }
653ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
654851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        // Add the new RawContactDelta to the list.
655ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        entityDeltaList.add(entityDelta);
656ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
657ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki        return entityDelta;
658ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki    }
659ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki
660ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki    /**
66137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Rebuild the editor to match our underlying {@link #mEntityDeltaList} object.
66237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
66337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void bindEditor() {
66437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        if (mEntityDeltaList == null) {
665a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            throw new IllegalStateException();
66637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
66737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
66837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // If no valid raw contact (to insert the data) was found, we won't have an editable
66937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // account type to use. In this case, display an error message and hide the "OK" button.
670a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki        if (mIsReadOnly) {
67137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            mReadOnlyWarningView.setText(getString(R.string.contact_read_only));
67237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            mReadOnlyWarningView.setVisibility(View.VISIBLE);
67337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            mEditorContainerView.setVisibility(View.GONE);
67437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            findViewById(R.id.btn_done).setVisibility(View.GONE);
67537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Nothing more to be done, just show the UI
676a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki            showDialogContent();
67737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            return;
67837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
67937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
68037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // Otherwise display an editor that allows the user to add the data to this raw contact.
68137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        for (DataKind kind : mEditableAccountType.getSortedDataKinds()) {
68237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Skip kind that are not editable
68337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            if (!kind.editable) continue;
68437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            if (mMimetype.equals(kind.mimeType)) {
685851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                for (ValuesDelta valuesDelta : mRawContactDelta.getMimeEntries(mMimetype)) {
68637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    // Skip entries that aren't visible
68737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    if (!valuesDelta.isVisible()) continue;
68837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    if (valuesDelta.isInsert()) {
689851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                        inflateEditorView(kind, valuesDelta, mRawContactDelta);
69037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                        return;
69137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    }
69237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
69337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
69437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
69537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
69637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
69737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
69837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Creates an EditorView for the given entry. This function must be used while constructing
69937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * the views corresponding to the the object-model. The resulting EditorView is also added
70037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * to the end of mEditors
70137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
702851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private void inflateEditorView(DataKind dataKind, ValuesDelta valuesDelta, RawContactDelta state) {
70337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final View view = mInflater.inflate(dataKind.editorLayoutResourceId, mEditorContainerView,
70437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                false);
70537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
70637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        if (view instanceof Editor) {
70737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Editor editor = (Editor) view;
70837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Don't allow deletion of the field because there is only 1 detail in this editor.
70937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            editor.setDeletable(false);
71037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            editor.setValues(dataKind, valuesDelta, state, false, new ViewIdGenerator());
71137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
71237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
71337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mEditorContainerView.addView(view);
71437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
71537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
71637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
71737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Set the display name to the correct TextView. Don't do this until it is
71837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * certain there is no need for a disambiguation field (otherwise the screen
71937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * will flicker because the name will be centered and then moved upwards).
72037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
72137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void setDisplayName() {
72237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mDisplayNameView.setText(mDisplayName);
72337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
72437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
72537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
72637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Set the TextView (for extra contact info) with the given value and make the
72737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * TextView visible.
72837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
72937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void setExtraInfoField(String value) {
73037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        TextView extraTextView = (TextView) findViewById(R.id.extra_info);
73137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        extraTextView.setVisibility(View.VISIBLE);
73237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        extraTextView.setText(value);
73337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
73437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
73537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
73637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Shows all the contents of the dialog to the user at one time. This should only be called
73737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * once all the queries have completed, otherwise the screen will flash as additional data
73837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * comes in.
73937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
740a84cf9274905479f09eb01dd3e7c6fbc2c5c6145Makoto Onuki    private void showDialogContent() {
74137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        mRootView.setVisibility(View.VISIBLE);
74237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
74337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
74437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
74537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Saves or creates the contact based on the mode, and if successful
74637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * finishes the activity.
74737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
74837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void doSaveAction() {
74937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        final PersistTask task = new PersistTask(this, mAccountTypeManager);
75037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        task.execute(mEntityDeltaList);
75137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
75237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
75337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
75437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * Background task for persisting edited contact data, using the changes
755851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu     * defined by a set of {@link RawContactDelta}. This task starts
75637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * {@link EmptyService} to make sure the background thread can finish
75737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * persisting in cases where the system wants to reclaim our process.
75837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
759851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private static class PersistTask extends AsyncTask<RawContactDeltaList, Void, Integer> {
76037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // In the future, use ContactSaver instead of WeakAsyncTask because of
76137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        // the danger of the activity being null during a save action
76237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private static final int PERSIST_TRIES = 3;
76337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
76437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private static final int RESULT_UNCHANGED = 0;
76537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private static final int RESULT_SUCCESS = 1;
76637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private static final int RESULT_FAILURE = 2;
76737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
76837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private ConfirmAddDetailActivity activityTarget;
76937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
77037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        private AccountTypeManager mAccountTypeManager;
77137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
77237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        public PersistTask(ConfirmAddDetailActivity target, AccountTypeManager accountTypeManager) {
77337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            activityTarget = target;
77437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            mAccountTypeManager = accountTypeManager;
77537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
77637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
77737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
77837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        protected void onPreExecute() {
779fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan            sProgressDialog = new WeakReference<ProgressDialog>(ProgressDialog.show(activityTarget,
780fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan                    null, activityTarget.getText(R.string.savingContact)));
78137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
78237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Before starting this task, start an empty service to protect our
78337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // process from being reclaimed by the system.
78437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final Context context = activityTarget;
78537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            context.startService(new Intent(context, EmptyService.class));
78637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
78737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
78837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
789851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        protected Integer doInBackground(RawContactDeltaList... params) {
79037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final Context context = activityTarget;
79137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final ContentResolver resolver = context.getContentResolver();
79237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
793851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDeltaList state = params[0];
79437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
795e491b1f517f26b059778bd997f03f4f33fc8c15eKatherine Kuan            if (state == null) {
796e491b1f517f26b059778bd997f03f4f33fc8c15eKatherine Kuan                return RESULT_FAILURE;
797e491b1f517f26b059778bd997f03f4f33fc8c15eKatherine Kuan            }
798e491b1f517f26b059778bd997f03f4f33fc8c15eKatherine Kuan
79937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Trim any empty fields, and RawContacts, before persisting
800851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactModifier.trimEmpty(state, mAccountTypeManager);
80137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
80237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Attempt to persist changes
80337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            int tries = 0;
80437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Integer result = RESULT_FAILURE;
80537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            while (tries++ < PERSIST_TRIES) {
80637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                try {
80737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    // Build operations and try applying
808ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                    // Note: In case we've created a new raw_contact because the selected contact
809ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                    // is read-only, buildDiff() will create aggregation exceptions to join
810ac71b5305d49614f5560519509fa41ce9276a3f7Makoto Onuki                    // the new one to the existing contact.
81137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    final ArrayList<ContentProviderOperation> diff = state.buildDiff();
81237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    ContentProviderResult[] results = null;
81337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    if (!diff.isEmpty()) {
81437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                         results = resolver.applyBatch(ContactsContract.AUTHORITY, diff);
81537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    }
81637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
81737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    result = (diff.size() > 0) ? RESULT_SUCCESS : RESULT_UNCHANGED;
81837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    break;
81937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
82037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                } catch (RemoteException e) {
82137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    // Something went wrong, bail without success
82237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    Log.e(TAG, "Problem persisting user edits", e);
82337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    break;
82437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
82537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                } catch (OperationApplicationException e) {
82637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    // Version consistency failed, bail without success
82737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    Log.e(TAG, "Version consistency failed", e);
82837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                    break;
82937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                }
83037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
83137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
83237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            return result;
83337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
83437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
83537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        /** {@inheritDoc} */
83637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        @Override
83737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        protected void onPostExecute(Integer result) {
83837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            final Context context = activityTarget;
83937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
840fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan            dismissProgressDialog();
84137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
84237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Show a toast message based on the success or failure of the save action.
84337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            if (result == RESULT_SUCCESS) {
84437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                Toast.makeText(context, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
84537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            } else if (result == RESULT_FAILURE) {
84637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan                Toast.makeText(context, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
84737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            }
84837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
84937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            // Stop the service that was protecting us
85037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            context.stopService(new Intent(context, EmptyService.class));
85137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            activityTarget.onSaveCompleted(result != RESULT_FAILURE);
85237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
85337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
85437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan
855fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    @Override
856fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    protected void onStop() {
857fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        super.onStop();
858fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        // Dismiss the progress dialog here to prevent leaking the window on orientation change.
859fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        dismissProgressDialog();
860fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    }
861fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan
862fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    /**
863fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan     * Dismiss the progress dialog (check if it is null because it is a {@link WeakReference}).
864fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan     */
865fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    private static void dismissProgressDialog() {
866fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        ProgressDialog dialog = (sProgressDialog == null) ? null : sProgressDialog.get();
867fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        if (dialog != null) {
868fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan            dialog.dismiss();
869fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        }
870fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan        sProgressDialog = null;
871fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan    }
872fcfc522887202cbda6e7681ae4ec8f5252f23bacKatherine Kuan
87337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    /**
87437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * This method is intended to be executed after the background task for saving edited info has
87537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * finished. The method sets the activity result (and intent if applicable) and finishes the
87637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * activity.
87737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     * @param success is true if the save task completed successfully, or false otherwise.
87837bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan     */
87937bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    private void onSaveCompleted(boolean success) {
88037bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        if (success) {
88137bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            Intent intent = new Intent(Intent.ACTION_VIEW, mContactUri);
88237bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            setResult(RESULT_OK, intent);
88337bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        } else {
88437bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan            setResult(RESULT_CANCELED);
88537bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        }
88637bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan        finish();
88737bddc2fa266fa0378fcd85ac5047b1fb0af2dc0Katherine Kuan    }
888e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng}
889