ContactEditorFragment.java revision cf718aa47c11453925bb20f7970ca7c897f6e376
1cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann/*
2ef3f8f045ed4150caa64749742227acd0e6b85d8Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project
3cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
4cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * you may not use this file except in compliance with the License.
6cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * You may obtain a copy of the License at
7cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
8cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
10cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * See the License for the specific language governing permissions and
14cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * limitations under the License
15cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */
16cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
19f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account;
20cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity;
21bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.AlertDialog;
22bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.Dialog;
23bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.DialogFragment;
24222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager;
25222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
26d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwellimport android.content.ActivityNotFoundException;
27cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
28cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
29e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader;
30bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface;
31cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
32cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader;
33f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor;
34f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
35d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwellimport android.media.RingtoneManager;
36cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
37cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
389767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock;
39cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
40362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Event;
41362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Organization;
42cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
4391004b37683c15650eccde68ff04defcf94a1c84Maurice Chuimport android.provider.ContactsContract.CommonDataKinds.Photo;
44362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
45be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuanimport android.provider.ContactsContract.Groups;
462013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmannimport android.provider.ContactsContract.Intents;
47f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
48688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Leeimport android.text.TextUtils;
49cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log;
50cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater;
51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu;
52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater;
53cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem;
54cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View;
55cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup;
56d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.AdapterView;
576c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.AdapterView.OnItemClickListener;
586c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.BaseAdapter;
5980d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
60d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.ListPopupWindow;
61cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
62cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
63e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.ContactSaveService;
64e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.GroupMetaDataLoader;
65e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
66e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ContactEditorAccountsChangedActivity;
67e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ContactEditorActivity;
683f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
6944cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.AccountTypeManager;
7092101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.Contact;
7192101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.ContactLoader;
7292101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContact;
7392101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContactDelta;
7492101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContactDeltaList;
7592101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContactModifier;
7644cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.ValuesDelta;
7744cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.AccountType;
7844cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.AccountWithDataSet;
7944cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.util.AccountsListAdapter;
8044cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
81e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.detail.PhotoSelectionHandler;
82e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
83e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.Editor.EditorListener;
84c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwellimport com.android.contacts.list.UiIntentActions;
85e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ContactPhotoUtils;
86e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.HelpUtils;
87d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwellimport com.android.contacts.util.PhoneCapabilityTester;
8886625158bdc52855c37e96bf098ba7a213c810d7Chiao Chengimport com.android.contacts.util.UiClosables;
8992101e77238e450dedb56814cec80edc0adf79c0Walter Jang
90851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.google.common.collect.ImmutableList;
9144cfc56d1701629070384364416c1311b780535dChiao Chengimport com.google.common.collect.Lists;
92e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
93637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Leeimport java.io.FileNotFoundException;
94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
95daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwellimport java.util.HashMap;
96f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
97f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
983f990ba4e35a99078d831c041290e574a320caa5Walter Jang/**
993f990ba4e35a99078d831c041290e574a320caa5Walter Jang * Contact editor with all fields displayed.
1003f990ba4e35a99078d831c041290e574a320caa5Walter Jang */
1013f990ba4e35a99078d831c041290e574a320caa5Walter Jangpublic class ContactEditorFragment extends ContactEditorBaseFragment implements
1023f990ba4e35a99078d831c041290e574a320caa5Walter Jang        ContactEditor, SplitContactConfirmationDialogFragment.Listener,
103fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
1042b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann        RawContactReadOnlyEditorView.Listener {
105cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
106f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int LOADER_DATA = 1;
107e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private static final int LOADER_GROUPS = 2;
108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
109d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_ACTION = "action";
110cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_URI = "uri";
111cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_DISABLE_DELETE_MENU_OPTION = "disableDeleteMenuOption";
112cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_NEW_LOCAL_PROFILE = "newLocalProfile";
113cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
114f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
115cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
116cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_RAW_CONTACTS = "rawContacts";
117cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
118cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_EDIT_STATE = "state";
119ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov    private static final String KEY_STATUS = "status";
120cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
12144cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_HAS_NEW_CONTACT = "hasNewContact";
12244cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_NEW_CONTACT_READY = "newContactDataReady";
123cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
124cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_IS_EDIT = "isEdit";
12544cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_EXISTING_CONTACT_READY = "existingContactDataReady";
126cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
127cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Phone option menus
128bd127671f7fbcefb87a1b383140dee89cdb7039cBrian Attwell    private static final String KEY_SEND_TO_VOICE_MAIL_STATE = "sendToVoicemailState";
129bd127671f7fbcefb87a1b383140dee89cdb7039cBrian Attwell    private static final String KEY_ARE_PHONE_OPTIONS_CHANGEABLE = "arePhoneOptionsChangable";
130cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CUSTOM_RINGTONE = "customRingtone";
131cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
132cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Joins
133cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
134cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
135cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
136daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    private static final String KEY_EXPANDED_EDITORS = "expandedEditors";
137f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
138cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_IS_USER_PROFILE = "isUserProfile";
139cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
140cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_ENABLED = "enabled";
141cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
142cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Photos
143cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
144cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CURRENT_PHOTO_URI = "currentphotouri";
145cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_UPDATED_PHOTOS = "updatedPhotos";
146cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
147cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Aggregations
148cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID =
149cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            "aggregationSuggestionsRawContactId";
150cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
151a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
152a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
15315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    /**
1547d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * An intent extra that forces the editor to add the edited contact
1557d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * to the default group (e.g. "My Contacts").
1567d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     */
1577d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
1587d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
159ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    public static final String INTENT_EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
160ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson
161f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos    public static final String INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION =
162f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            "disableDeleteMenuOption";
163f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos
164a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_JOIN = 0;
1656fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private static final int REQUEST_CODE_ACCOUNTS_CHANGED = 1;
166d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private static final int REQUEST_CODE_PICK_RINGTONE = 2;
167f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
168fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Context mContext;
169fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Listener mListener;
170e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
171fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private LinearLayout mContent;
172cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
173fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
174fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Parameters passed in on {@link #load}
175fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
176f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mAction;
177b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann    private Uri mLookupUri;
178f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Bundle mIntentExtras;
179fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mAutoAddToDefaultGroup;
180fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mDisableDeleteMenuOption = false;
181fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mNewLocalProfile = false;
182cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
183fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
184fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Helpers
185fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
1860353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private ContactEditorUtils mEditorUtils;
187fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private RawContactDeltaComparator mComparator;
188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
189fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private AggregationSuggestionEngine mAggregationSuggestionEngine;
190cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
191fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
192fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Loaded data
193fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
194fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Used to temporarily store existing contact data during a rebind call (i.e. account switch)
195fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private ImmutableList<RawContact> mRawContacts;
196fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Cursor mGroupMetaData;
1979767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann
198fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
199fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Contact editor state
200fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
201fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private RawContactDeltaList mState;
202825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private int mStatus;
203825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
20444cfc56d1701629070384364416c1311b780535dChiao Cheng    // Whether to show the new contact blank form and if it's corresponding delta is ready.
20544cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mHasNewContact = false;
20644cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mNewContactDataReady = false;
20744cfc56d1701629070384364416c1311b780535dChiao Cheng
20844cfc56d1701629070384364416c1311b780535dChiao Cheng    // Whether it's an edit of existing contact and if it's corresponding delta is ready.
20944cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mIsEdit = false;
21044cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mExistingContactDataReady = false;
21144cfc56d1701629070384364416c1311b780535dChiao Cheng
212cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Phone specific option menus
213d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private boolean mSendToVoicemailState;
214d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private boolean mArePhoneOptionsChangable;
215d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private String mCustomRingtone;
216d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
217fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Joins
218fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private long mContactIdForJoin;
219fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mContactWritableForJoin;
220fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
221fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Used to store which raw contact editors have been expanded. Keyed on raw contact ids.
222fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private HashMap<Long, Boolean> mExpandedEditors = new HashMap<Long, Boolean>();
223fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
224fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mIsUserProfile = false;
225fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
226fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Whether editors and options menu items are enabled
227fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mEnabled = true;
228fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
229fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Whether the name editor should receive focus after being bound
230fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mRequestFocus;
231fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
23244cfc56d1701629070384364416c1311b780535dChiao Cheng    // This is used to pre-populate the editor with a display name when a user edits a read-only
23344cfc56d1701629070384364416c1311b780535dChiao Cheng    // contact.
23444cfc56d1701629070384364416c1311b780535dChiao Cheng    private String mDefaultDisplayName;
23544cfc56d1701629070384364416c1311b780535dChiao Cheng
236fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Photos
237fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    /**
238fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * The raw contact for which we started "take photo" or "choose photo from gallery" most
239fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * recently.  Used to restore {@link #mCurrentPhotoHandler} after orientation change.
240fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     */
241fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private long mRawContactIdRequestingPhoto;
24244cfc56d1701629070384364416c1311b780535dChiao Cheng
243fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    /**
244fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * The {@link PhotoHandler} for the photo editor for the {@link #mRawContactIdRequestingPhoto}
245fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * raw contact.
246fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     *
247fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * A {@link PhotoHandler} is created for each photo editor in {@link #bindPhotoHandler}, but
248fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * the only "active" one should get the activity result.  This member represents the active
249fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * one.
250fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     */
251fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private PhotoHandler mCurrentPhotoHandler;
252fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Uri mCurrentPhotoUri;
253fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Bundle mUpdatedPhotos = new Bundle();
254daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
255fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Aggregations
2569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private long mAggregationSuggestionsRawContactId;
2579302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private View mAggregationSuggestionView;
2586c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private ListPopupWindow mAggregationSuggestionPopup;
2596c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2606c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private static final class AggregationSuggestionAdapter extends BaseAdapter {
2616c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final Activity mActivity;
2626c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final boolean mSetNewContact;
2636c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final AggregationSuggestionView.Listener mListener;
2646c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final List<Suggestion> mSuggestions;
2656c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2666c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public AggregationSuggestionAdapter(Activity activity, boolean setNewContact,
2676c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) {
2686c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mActivity = activity;
2696c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSetNewContact = setNewContact;
2706c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mListener = listener;
2716c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSuggestions = suggestions;
2726c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2736c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2746c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2756c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public View getView(int position, View convertView, ViewGroup parent) {
2766c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            Suggestion suggestion = (Suggestion) getItem(position);
2776c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            LayoutInflater inflater = mActivity.getLayoutInflater();
2786c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            AggregationSuggestionView suggestionView =
2796c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                    (AggregationSuggestionView) inflater.inflate(
2806c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                            R.layout.aggregation_suggestions_item, null);
2816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setNewContact(mSetNewContact);
2826c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setListener(mListener);
2836c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.bindSuggestion(suggestion);
2846c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return suggestionView;
2856c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2866c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2876c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2886c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public long getItemId(int position) {
2896c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return position;
2906c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2916c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2926c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2936c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public Object getItem(int position) {
2946c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.get(position);
2956c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2966c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2976c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2986c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public int getCount() {
2996c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.size();
3006c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
3016c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    }
3026c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
3036c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private OnItemClickListener mAggregationSuggestionItemClickListener =
3046c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            new OnItemClickListener() {
3056c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
3066c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
3076c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view;
3086c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.handleItemClickEvent();
30986625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng            UiClosables.closeQuietly(mAggregationSuggestionPopup);
3106c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mAggregationSuggestionPopup = null;
3116c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
3126c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    };
3136c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
314cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
315cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
316cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
31702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public void setEnabled(boolean enabled) {
31802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mEnabled != enabled) {
31902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = enabled;
32002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (mContent != null) {
32102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                int count = mContent.getChildCount();
32202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                for (int i = 0; i < count; i++) {
32302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                    mContent.getChildAt(i).setEnabled(enabled);
32402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                }
32502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
326a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            setAggregationSuggestionViewEnabled(enabled);
32702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            final Activity activity = getActivity();
32802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (activity != null) activity.invalidateOptionsMenu();
32902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
33002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
33102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
332cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
333cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public void onAttach(Activity activity) {
334cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        super.onAttach(activity);
335cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        mContext = activity;
3360353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        mEditorUtils = ContactEditorUtils.getInstance(mContext);
33792101e77238e450dedb56814cec80edc0adf79c0Walter Jang        mComparator = new RawContactDeltaComparator(mContext);
338cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
339cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
340cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
341f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onStop() {
342f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super.onStop();
34386625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng
34486625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng        UiClosables.closeQuietly(mAggregationSuggestionPopup);
34586625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng
346825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If anything was left unsaved, save it now but keep the editor open.
347f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
348623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            save(SaveMode.RELOAD);
349825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
350f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
351f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
352f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
35336184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    public void onDestroy() {
35436184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        super.onDestroy();
35536184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        if (mAggregationSuggestionEngine != null) {
35636184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee            mAggregationSuggestionEngine.quit();
35736184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        }
35836184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    }
35936184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee
36036184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    @Override
361cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
362cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
363cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
364f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
365e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
3663648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
367cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
368cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
369cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
370cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
371222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
372222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    public void onActivityCreated(Bundle savedInstanceState) {
373222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        super.onActivityCreated(savedInstanceState);
374222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
375098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        validateAction(mAction);
376098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
37744cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
378098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // The delta list may not have finished loading before orientation change happens.
379098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // In this case, there will be a saved state but deltas will be missing.  Reload from
380098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // database.
381825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            if (Intent.ACTION_EDIT.equals(mAction)) {
382098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // Either...
383098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // 1) orientation change but load never finished.
384098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // or
385098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // 2) not an orientation change.  data needs to be loaded for first time.
386825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
387098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            }
388098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        } else {
389098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // Orientation change, we already have mState, it was loaded by onCreate
390098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            bindEditors();
391098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        }
392098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
39344cfc56d1701629070384364416c1311b780535dChiao Cheng        // Handle initial actions only when existing state missing
39444cfc56d1701629070384364416c1311b780535dChiao Cheng        if (savedInstanceState == null) {
39544cfc56d1701629070384364416c1311b780535dChiao Cheng            if (Intent.ACTION_EDIT.equals(mAction)) {
39644cfc56d1701629070384364416c1311b780535dChiao Cheng                mIsEdit = true;
39744cfc56d1701629070384364416c1311b780535dChiao Cheng            } else if (Intent.ACTION_INSERT.equals(mAction)) {
39844cfc56d1701629070384364416c1311b780535dChiao Cheng                mHasNewContact = true;
3992013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                final Account account = mIntentExtras == null ? null :
4004a1c574cd62eb7ca1e0fcc3a61e5378e5e0787feBrian Attwell                        (Account) mIntentExtras.getParcelable(Intents.Insert.EXTRA_ACCOUNT);
4012b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                final String dataSet = mIntentExtras == null ? null :
4024a1c574cd62eb7ca1e0fcc3a61e5378e5e0787feBrian Attwell                        mIntentExtras.getString(Intents.Insert.EXTRA_DATA_SET);
4032013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann
4042013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                if (account != null) {
4052013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // Account specified in Intent
4062b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    createContact(new AccountWithDataSet(account.name, account.type, dataSet));
4072013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                } else {
4082013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // No Account specified. Let the user choose
40940bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    // Load Accounts async so that we can present them
4100353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    selectAccountAndCreateContact();
4112013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                }
412098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            }
413098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        }
414098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng    }
415098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
416098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng    /**
417098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     * Checks if the requested action is valid.
418098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     *
419098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     * @param action The action to test.
420098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     * @throws IllegalArgumentException when the action is invalid.
421098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     */
422098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng    private void validateAction(String action) {
423e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng        if (Intent.ACTION_EDIT.equals(action) || Intent.ACTION_INSERT.equals(action) ||
424e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng                ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(action)) {
425e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng            return;
426825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
427098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        throw new IllegalArgumentException("Unknown Action String " + mAction +
428e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng                ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT + " or " +
429e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng                ContactEditorActivity.ACTION_SAVE_COMPLETED);
430222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    }
431222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
432e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    @Override
433e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    public void onStart() {
434e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
435e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        super.onStart();
436e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
437e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
4383f990ba4e35a99078d831c041290e574a320caa5Walter Jang    @Override
4391015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov    public void load(String action, Uri lookupUri, Bundle intentExtras) {
440f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mAction = action;
441b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        mLookupUri = lookupUri;
442f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mIntentExtras = intentExtras;
4437d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov        mAutoAddToDefaultGroup = mIntentExtras != null
444fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang                &&  mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
445ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        mNewLocalProfile = mIntentExtras != null
44636d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                && mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
447f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos        mDisableDeleteMenuOption = mIntentExtras != null
448f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos                && mIntentExtras.getBoolean(INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION);
449f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
450f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
4513f990ba4e35a99078d831c041290e574a320caa5Walter Jang    @Override
452f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void setListener(Listener value) {
453f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mListener = value;
454cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
455cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
456cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
457f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
458d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        if (savedState != null) {
459d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // Restore mUri before calling super.onCreate so that onInitializeLoaders
460d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // would already have a uri and an action to work with
461d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mAction = savedState.getString(KEY_ACTION);
462cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mLookupUri = savedState.getParcelable(KEY_URI);
463d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        }
464d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
465f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
466f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
467f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (savedState == null) {
468f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // If savedState is non-null, onRestoreInstanceState() will restore the generator.
469f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = new ViewIdGenerator();
470f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
471cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
472cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
473cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mDisableDeleteMenuOption = savedState.getBoolean(KEY_DISABLE_DELETE_MENU_OPTION);
474cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mNewLocalProfile = savedState.getBoolean(KEY_NEW_LOCAL_PROFILE);
475cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
476cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mRawContacts = ImmutableList.copyOf(savedState.<RawContact>getParcelableArrayList(
477cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                    KEY_RAW_CONTACTS));
478cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // NOTE: mGroupMetaData is not saved/restored
479cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
480825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            // Read state from savedState. No loading involved here
481851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            mState = savedState.<RawContactDeltaList> getParcelable(KEY_EDIT_STATE);
482ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov            mStatus = savedState.getInt(KEY_STATUS);
483cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
48444cfc56d1701629070384364416c1311b780535dChiao Cheng            mHasNewContact = savedState.getBoolean(KEY_HAS_NEW_CONTACT);
48544cfc56d1701629070384364416c1311b780535dChiao Cheng            mNewContactDataReady = savedState.getBoolean(KEY_NEW_CONTACT_READY);
486cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
487cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mIsEdit = savedState.getBoolean(KEY_IS_EDIT);
48844cfc56d1701629070384364416c1311b780535dChiao Cheng            mExistingContactDataReady = savedState.getBoolean(KEY_EXISTING_CONTACT_READY);
489cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
490cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Phone specific options menus
491bd127671f7fbcefb87a1b383140dee89cdb7039cBrian Attwell            mSendToVoicemailState = savedState.getBoolean(KEY_SEND_TO_VOICE_MAIL_STATE);
492cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mArePhoneOptionsChangable = savedState.getBoolean(KEY_ARE_PHONE_OPTIONS_CHANGEABLE);
493bd127671f7fbcefb87a1b383140dee89cdb7039cBrian Attwell            mCustomRingtone =  savedState.getString(KEY_CUSTOM_RINGTONE);
494cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
495cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Joins
496cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
497cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
498cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
499daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            mExpandedEditors = (HashMap<Long, Boolean>)
500daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                    savedState.getSerializable(KEY_EXPANDED_EDITORS);
501cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
502cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
503cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
504cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mEnabled = savedState.getBoolean(KEY_ENABLED);
505cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
506cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // NOTE: mRequestFocus and mDefaultDisplayName are not saved/restored
507cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
508cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Photos
509cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mRawContactIdRequestingPhoto = savedState.getLong(
510cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
511cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI);
512cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
513cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
514cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Aggregations
515cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mAggregationSuggestionsRawContactId = savedState.getLong(
516cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                    KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID);
51744cfc56d1701629070384364416c1311b780535dChiao Cheng        }
51844cfc56d1701629070384364416c1311b780535dChiao Cheng
51944cfc56d1701629070384364416c1311b780535dChiao Cheng        // mState can still be null because it may not have have finished loading before
52044cfc56d1701629070384364416c1311b780535dChiao Cheng        // onSaveInstanceState was called.
52144cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState == null) {
52244cfc56d1701629070384364416c1311b780535dChiao Cheng            mState = new RawContactDeltaList();
523cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
524cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
525cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
52644cfc56d1701629070384364416c1311b780535dChiao Cheng    public void setData(Contact contact) {
52744cfc56d1701629070384364416c1311b780535dChiao Cheng
528d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        // If we have already loaded data, we do not want to change it here to not confuse the user
52944cfc56d1701629070384364416c1311b780535dChiao Cheng        if (!mState.isEmpty()) {
530d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            Log.v(TAG, "Ignoring background change. This will have to be rebased later");
531d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            return;
532d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        }
533d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann
534fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        // See if this edit operation needs to be redirected to a custom editor
53544cfc56d1701629070384364416c1311b780535dChiao Cheng        mRawContacts = contact.getRawContacts();
53644cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mRawContacts.size() == 1) {
53744cfc56d1701629070384364416c1311b780535dChiao Cheng            RawContact rawContact = mRawContacts.get(0);
538851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            String type = rawContact.getAccountTypeString();
539851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            String dataSet = rawContact.getDataSet();
54047b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng            AccountType accountType = rawContact.getAccountType(mContext);
5412b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann            if (accountType.getEditContactActivityClassName() != null &&
5422b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann                    !accountType.areContactsWritable()) {
543fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                if (mListener != null) {
544851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    String name = rawContact.getAccountName();
545851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    long rawContactId = rawContact.getId();
5462b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    mListener.onCustomEditContactActivityRequested(
5472b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                            new AccountWithDataSet(name, type, dataSet),
548fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
549fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            mIntentExtras, true);
550fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                }
551fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                return;
552fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
553fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
554fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
555688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee        String displayName = null;
55644cfc56d1701629070384364416c1311b780535dChiao Cheng        // Check for writable raw contacts.  If there are none, then we need to create one so user
55744cfc56d1701629070384364416c1311b780535dChiao Cheng        // can edit.  For the user profile case, there is already an editable contact.
55844cfc56d1701629070384364416c1311b780535dChiao Cheng        if (!contact.isUserProfile() && !contact.isWritableContact(mContext)) {
55944cfc56d1701629070384364416c1311b780535dChiao Cheng            mHasNewContact = true;
56044cfc56d1701629070384364416c1311b780535dChiao Cheng
56144cfc56d1701629070384364416c1311b780535dChiao Cheng            // This is potentially an asynchronous call and will add deltas to list.
56244cfc56d1701629070384364416c1311b780535dChiao Cheng            selectAccountAndCreateContact();
563688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee            displayName = contact.getDisplayName();
56444cfc56d1701629070384364416c1311b780535dChiao Cheng        }
56544cfc56d1701629070384364416c1311b780535dChiao Cheng
56644cfc56d1701629070384364416c1311b780535dChiao Cheng        // This also adds deltas to list
567688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee        // If displayName is null at this point it is simply ignored later on by the editor.
568688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee        bindEditorsForExistingContact(displayName, contact.isUserProfile(),
56944cfc56d1701629070384364416c1311b780535dChiao Cheng                mRawContacts);
570d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
571d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        bindMenuItemsForPhone(contact);
572fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
573fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
574fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    @Override
5752b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    public void onExternalEditorRequest(AccountWithDataSet account, Uri uri) {
576fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        mListener.onCustomEditContactActivityRequested(account, uri, null, false);
577fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
578fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
579daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    @Override
580daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    public void onEditorExpansionChanged() {
581daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        updatedExpandedEditorsMap();
582daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    }
583daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
58444cfc56d1701629070384364416c1311b780535dChiao Cheng    private void bindEditorsForExistingContact(String displayName, boolean isUserProfile,
58544cfc56d1701629070384364416c1311b780535dChiao Cheng            ImmutableList<RawContact> rawContacts) {
58602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        setEnabled(true);
58744cfc56d1701629070384364416c1311b780535dChiao Cheng        mDefaultDisplayName = displayName;
58802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
58944cfc56d1701629070384364416c1311b780535dChiao Cheng        mState.addAll(rawContacts.iterator());
5901ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        setIntentExtras(mIntentExtras);
5911ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        mIntentExtras = null;
592e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov
593ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // For user profile, change the contacts query URI
59444cfc56d1701629070384364416c1311b780535dChiao Cheng        mIsUserProfile = isUserProfile;
59548ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson        boolean localProfileExists = false;
59648ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson
597ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (mIsUserProfile) {
598851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (RawContactDelta state : mState) {
59948ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                // For profile contacts, we need a different query URI
600ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson                state.setProfileQueryUri();
60148ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                // Try to find a local profile contact
60248ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                if (state.getValues().getAsString(RawContacts.ACCOUNT_TYPE) == null) {
60348ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                    localProfileExists = true;
60448ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                }
60548ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson            }
60648ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson            // Editor should always present a local profile for editing
60748ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson            if (!localProfileExists) {
60847b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final RawContact rawContact = new RawContact();
609851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                rawContact.setAccountToLocal();
610851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu
611851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactDelta insert = new RawContactDelta(ValuesDelta.fromAfter(
612851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                        rawContact.getValues()));
61348ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                insert.setProfileQueryUri();
61448ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                mState.add(insert);
615ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            }
616ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        }
617eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
61844cfc56d1701629070384364416c1311b780535dChiao Cheng        mExistingContactDataReady = true;
6191ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        bindEditors();
6201ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    }
6211ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov
622d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private void bindMenuItemsForPhone(Contact contact) {
623d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        mSendToVoicemailState = contact.isSendToVoicemail();
624d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        mCustomRingtone = contact.getCustomRingtone();
625d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        mArePhoneOptionsChangable = arePhoneOptionsChangable(contact);
626d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    }
627d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
628d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private boolean arePhoneOptionsChangable(Contact contact) {
629d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        return contact != null && !contact.isDirectoryEntry()
630d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                && PhoneCapabilityTester.isPhone(mContext);
631d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    }
632d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
6331ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    /**
6341ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     * Merges extras from the intent.
6351ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     */
6361ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    public void setIntentExtras(Bundle extras) {
6371ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        if (extras == null || extras.size() == 0) {
6381ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            return;
639bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
640916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
641a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
642851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContactDelta state : mState) {
643851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = state.getAccountType(accountTypes);
64496e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (type.areContactsWritable()) {
6451ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                // Apply extras to the first writable raw contact only
646851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactModifier.parseExtras(mContext, type, state, extras);
6471ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                break;
6481ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            }
6491ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        }
650f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
651cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
6520353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private void selectAccountAndCreateContact() {
6530353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // If this is a local profile, then skip the logic about showing the accounts changed
6540353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // activity and create a phone-local contact.
6550353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (mNewLocalProfile) {
6560353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            createContact(null);
6570353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
6580353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
6590353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
6600353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // If there is no default account or the accounts have changed such that we need to
6610353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // prompt the user again, then launch the account prompt.
6620353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (mEditorUtils.shouldShowAccountChangedNotification()) {
6630353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            Intent intent = new Intent(mContext, ContactEditorAccountsChangedActivity.class);
6640353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            mStatus = Status.SUB_ACTIVITY;
6650353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            startActivityForResult(intent, REQUEST_CODE_ACCOUNTS_CHANGED);
6660353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        } else {
6670353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            // Otherwise, there should be a default account. Then either create a local contact
6680353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            // (if default account is null) or create a contact with the specified account.
6690353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            AccountWithDataSet defaultAccount = mEditorUtils.getDefaultAccount();
67067e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner            createContact(defaultAccount);
6710353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
6720353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    }
6730353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
674d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
6750353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan     * Create a contact by automatically selecting the first account. If there's no available
6760353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan     * account, a device-local contact should be created.
677d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
678d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void createContact() {
6792b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final List<AccountWithDataSet> accounts =
680a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov                AccountTypeManager.getInstance(mContext).getAccounts(true);
6810353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // No Accounts available. Create a phone-local contact.
6820353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (accounts.isEmpty()) {
68340bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov            createContact(null);
6840353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
685f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
686cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
687d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // We have an account switcher in "create-account" screen, so don't need to ask a user to
688d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // select an account here.
689d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        createContact(accounts.get(0));
690cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
691cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
692cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    /**
693d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Shows account creation screen associated with a given account.
694d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
695d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param account may be null to signal a device-local contact should be created.
696cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann     */
6972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void createContact(AccountWithDataSet account) {
698a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
69967e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner        final AccountType accountType = accountTypes.getAccountTypeForAccount(account);
700fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
701b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        if (accountType.getCreateContactActivityClassName() != null) {
702fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (mListener != null) {
703fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                mListener.onCustomCreateContactActivityRequested(account, mIntentExtras);
704fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
705fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        } else {
706b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            bindEditorsForNewContact(account, accountType);
707fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
708fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
709fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
710d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
711d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
712d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Some of old data are reused with new restriction enforced by the new account.
713d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
7142b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro     * @param oldState Old data being edited.
715d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param oldAccount Old account associated with oldState.
716d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param newAccount New account to be used.
717d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
718d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void rebindEditorsForNewContact(
719851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDelta oldState, AccountWithDataSet oldAccount,
720851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            AccountWithDataSet newAccount) {
721d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
72267e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner        AccountType oldAccountType = accountTypes.getAccountTypeForAccount(oldAccount);
72367e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner        AccountType newAccountType = accountTypes.getAccountTypeForAccount(newAccount);
724d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
725d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccountType.getCreateContactActivityClassName() != null) {
726d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            Log.w(TAG, "external activity called in rebind situation");
727d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            if (mListener != null) {
728d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
729d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
730d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
73144cfc56d1701629070384364416c1311b780535dChiao Cheng            mExistingContactDataReady = false;
73244cfc56d1701629070384364416c1311b780535dChiao Cheng            mNewContactDataReady = false;
73344cfc56d1701629070384364416c1311b780535dChiao Cheng            mState = new RawContactDeltaList();
734d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType);
73544cfc56d1701629070384364416c1311b780535dChiao Cheng            if (mIsEdit) {
73644cfc56d1701629070384364416c1311b780535dChiao Cheng                bindEditorsForExistingContact(mDefaultDisplayName, mIsUserProfile, mRawContacts);
73744cfc56d1701629070384364416c1311b780535dChiao Cheng            }
738d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
739d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
740d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
7412b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void bindEditorsForNewContact(AccountWithDataSet account,
7422b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType accountType) {
743d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        bindEditorsForNewContact(account, accountType, null, null);
744d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
745d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
7462b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void bindEditorsForNewContact(AccountWithDataSet newAccount,
747851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType newAccountType, RawContactDelta oldState,
748851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            AccountType oldAccountType) {
749a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        mStatus = Status.EDITING;
750a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
75147b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng        final RawContact rawContact = new RawContact();
75267e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner        rawContact.setAccount(newAccount);
753cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
75444cfc56d1701629070384364416c1311b780535dChiao Cheng        final ValuesDelta valuesDelta = ValuesDelta.fromAfter(rawContact.getValues());
75544cfc56d1701629070384364416c1311b780535dChiao Cheng        final RawContactDelta insert = new RawContactDelta(valuesDelta);
756d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (oldState == null) {
757d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            // Parse any values from incoming intent
758851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
759d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
760851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactModifier.migrateStateForNewContact(mContext, oldState, insert,
761d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    oldAccountType, newAccountType);
762d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
763f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
76469f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        // Ensure we have some default fields (if the account type does not support a field,
765362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmann        // ensureKind will not add it, so it is safe to add e.g. Event)
766851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
767851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
768851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
769851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
770851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType,
771851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                StructuredPostal.CONTENT_ITEM_TYPE);
772f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
773ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // Set the correct URI for saving the contact as a profile
774ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (mNewLocalProfile) {
775ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            insert.setProfileQueryUri();
776ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        }
777ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson
77844cfc56d1701629070384364416c1311b780535dChiao Cheng        mState.add(insert);
779f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
780eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
781eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
78244cfc56d1701629070384364416c1311b780535dChiao Cheng        mNewContactDataReady = true;
783f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
784cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
785cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
786f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void bindEditors() {
7875671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        // bindEditors() can only bind views if there is data in mState, so immediately return
7885671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        // if mState is null
78944cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
79044cfc56d1701629070384364416c1311b780535dChiao Cheng            return;
79144cfc56d1701629070384364416c1311b780535dChiao Cheng        }
79244cfc56d1701629070384364416c1311b780535dChiao Cheng
79344cfc56d1701629070384364416c1311b780535dChiao Cheng        // Check if delta list is ready.  Delta list is populated from existing data and when
79444cfc56d1701629070384364416c1311b780535dChiao Cheng        // editing an read-only contact, it's also populated with newly created data for the
79544cfc56d1701629070384364416c1311b780535dChiao Cheng        // blank form.  When the data is not ready, skip. This method will be called multiple times.
79644cfc56d1701629070384364416c1311b780535dChiao Cheng        if ((mIsEdit && !mExistingContactDataReady) || (mHasNewContact && !mNewContactDataReady)) {
7975671c7e7718c3285dc0391807401083986fcfd51Maurice Chu            return;
7985671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        }
7995671c7e7718c3285dc0391807401083986fcfd51Maurice Chu
800f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
801f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
802cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
803f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
804f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
805cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
806f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
807f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
808a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
809a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        int numRawContacts = mState.size();
81044cfc56d1701629070384364416c1311b780535dChiao Cheng
811a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        for (int i = 0; i < numRawContacts; i++) {
812f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
813851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta rawContactDelta = mState.get(i);
814851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if (!rawContactDelta.isVisible()) continue;
815f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
816851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = rawContactDelta.getAccountType(accountTypes);
817851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final long rawContactId = rawContactDelta.getRawContactId();
818f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
81972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            final BaseRawContactEditorView editor;
8202b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann            if (!type.areContactsWritable()) {
821fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                editor = (BaseRawContactEditorView) inflater.inflate(
8222b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann                        R.layout.raw_contact_readonly_editor_view, mContent, false);
823fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            } else {
824fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view,
825fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                        mContent, false);
826cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
827daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            editor.setListener(this);
828daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(mContext)
829daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                    .getAccounts(true);
830daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            if (mHasNewContact && !mNewLocalProfile && accounts.size() > 1) {
831daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                addAccountSwitcher(mState.get(0), editor);
832d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
833a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan
83402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            editor.setEnabled(mEnabled);
835cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
836daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            if (mExpandedEditors.containsKey(rawContactId)) {
837daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                editor.setCollapsed(mExpandedEditors.get(rawContactId));
838daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            } else {
839daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                // By default, only the first editor will be expanded.
840daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                editor.setCollapsed(i != 0);
841daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            }
842daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
843f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
8447d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
845851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile());
846daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            editor.setCollapsible(numRawContacts > 1);
847f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
8486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            // Set up the photo handler.
8496fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            bindPhotoHandler(editor, type, mState);
8506fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
851c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            // If a new photo was chosen but not yet saved, we need to update the UI to
852c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            // reflect this.
853c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            final Uri photoUri = updatedPhotoUriForRawContact(rawContactId);
854c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            if (photoUri != null) editor.setFullSizedPhoto(photoUri);
85528eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
85672af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (editor instanceof RawContactEditorView) {
8572828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                final Activity activity = getActivity();
85872af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
8595ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                EditorListener listener = new EditorListener() {
860f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
861f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
862f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    public void onRequest(int request) {
8632828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                        if (activity.isFinishing()) { // Make sure activity is still running.
8642828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                            return;
8652828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                        }
8662bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson                        if (request == EditorListener.FIELD_CHANGED && !isEditingUserProfile()) {
8672828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                            acquireAggregationSuggestions(activity, rawContactEditor);
868d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                        } else if (request == EditorListener.EDITOR_FOCUS_CHANGED) {
869d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                            adjustNameFieldsHintDarkness(rawContactEditor);
87011bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                        }
871f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
872f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
873f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
8742293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                    public void onDeleteRequested(Editor removedEditor) {
875f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
8765ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                };
8775ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov
87844cfc56d1701629070384364416c1311b780535dChiao Cheng                final StructuredNameEditorView nameEditor = rawContactEditor.getNameEditor();
8795ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                if (mRequestFocus) {
8805ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    nameEditor.requestFocus();
8815ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    mRequestFocus = false;
8825ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                }
8835ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                nameEditor.setEditorListener(listener);
884688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                if (!TextUtils.isEmpty(mDefaultDisplayName)) {
885688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                    nameEditor.setDisplayName(mDefaultDisplayName);
886688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                }
887f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
8885ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView phoneticNameEditor =
8895ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                        rawContactEditor.getPhoneticNameEditor();
8905ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                phoneticNameEditor.setEditorListener(listener);
8917d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
8927d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
893d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                final TextFieldsEditorView nickNameEditor =
894d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                        rawContactEditor.getNickNameEditor();
895d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                nickNameEditor.setEditorListener(listener);
896d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell
8979302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (rawContactId == mAggregationSuggestionsRawContactId) {
8982828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                    acquireAggregationSuggestions(activity, rawContactEditor);
899f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
900d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell
901d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                adjustNameFieldsHintDarkness(rawContactEditor);
902f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
903cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
904f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
905eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = false;
906eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
907e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        bindGroupMetaData();
908e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
909f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
910f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
911a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
912a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        // Refresh Action Bar as the visibility of the join command
913825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Activity can be null if we have been detached from the Activity
914825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        final Activity activity = getActivity();
915825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (activity != null) activity.invalidateOptionsMenu();
916daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
917daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        updatedExpandedEditorsMap();
918daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    }
919daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
920daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    /**
921d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     * Adjust how dark the hint text should be on all the names' text fields.
922d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     *
923d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     * @param rawContactEditor editor to update
924d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     */
925d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell    private void adjustNameFieldsHintDarkness(RawContactEditorView rawContactEditor) {
926d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        // Check whether fields contain focus by calling findFocus() instead of hasFocus().
927d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        // The hasFocus() value is not necessarily up to date.
928d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        final boolean nameFieldsAreNotFocused
929d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                = rawContactEditor.getNameEditor().findFocus() == null
930d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                && rawContactEditor.getPhoneticNameEditor().findFocus() == null
931d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                && rawContactEditor.getNickNameEditor().findFocus() == null;
932d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        rawContactEditor.getNameEditor().setHintColorDark(!nameFieldsAreNotFocused);
933d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        rawContactEditor.getPhoneticNameEditor().setHintColorDark(!nameFieldsAreNotFocused);
934d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        rawContactEditor.getNickNameEditor().setHintColorDark(!nameFieldsAreNotFocused);
935d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell    }
936d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell
937d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell    /**
938daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell     * Update the values in {@link #mExpandedEditors}.
939daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell     */
940daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    private void updatedExpandedEditorsMap() {
941daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        for (int i = 0; i < mContent.getChildCount(); i++) {
942daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            final View childView = mContent.getChildAt(i);
943daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            if (childView instanceof BaseRawContactEditorView) {
944daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                BaseRawContactEditorView childEditor = (BaseRawContactEditorView) childView;
945daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                mExpandedEditors.put(childEditor.getRawContactId(), childEditor.isCollapsed());
946daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            }
947daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        }
9486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    }
949eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
95028eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    /**
951c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell     * If we've stashed a temporary file containing a contact's new photo, return its URI.
95228eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus     * @param rawContactId identifies the raw-contact whose Bitmap we'll try to return.
953c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell     * @return Uru of photo for specified raw-contact, or null
954c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell     */
955c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell    private Uri updatedPhotoUriForRawContact(long rawContactId) {
956c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell        return (Uri) mUpdatedPhotos.get(String.valueOf(rawContactId));
95728eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    }
95828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
9596fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private void bindPhotoHandler(BaseRawContactEditorView editor, AccountType type,
960851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDeltaList state) {
9616fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        final int mode;
9627e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell        final boolean showIsPrimaryOption;
9636fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        if (type.areContactsWritable()) {
9646fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            if (editor.hasSetPhoto()) {
9657e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                mode = PhotoActionPopup.Modes.WRITE_ABLE_PHOTO;
9667e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                showIsPrimaryOption = hasMoreThanOnePhoto();
9676fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            } else {
968ced983d7a816256d93fdea1f81e63e4598c18875Josh Gargus                mode = PhotoActionPopup.Modes.NO_PHOTO;
9697e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                showIsPrimaryOption = false;
9706fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
9717e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell        } else if (editor.hasSetPhoto() && hasMoreThanOnePhoto()) {
9727e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            mode = PhotoActionPopup.Modes.READ_ONLY_PHOTO;
9737e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            showIsPrimaryOption = true;
9746fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        } else {
9757e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            // Read-only and either no photo or the only photo ==> no options
9767e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            editor.getPhotoEditor().setEditorListener(null);
9777e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            editor.getPhotoEditor().setShowPrimary(false);
9787e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            return;
9796fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        }
98091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        final PhotoHandler photoHandler = new PhotoHandler(mContext, editor, mode, state);
9816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        editor.getPhotoEditor().setEditorListener(
98291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                (PhotoHandler.PhotoEditorListener) photoHandler.getListener());
9837e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell        editor.getPhotoEditor().setShowPrimary(showIsPrimaryOption);
9844bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki
9854bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        // Note a newly created raw contact gets some random negative ID, so any value is valid
9864bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        // here. (i.e. don't check against -1 or anything.)
9874bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        if (mRawContactIdRequestingPhoto == editor.getRawContactId()) {
9884bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mCurrentPhotoHandler = photoHandler;
9894bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        }
990cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
991cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
992e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private void bindGroupMetaData() {
993e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        if (mGroupMetaData == null) {
994e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            return;
995e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
996e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
997e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        int editorCount = mContent.getChildCount();
998e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        for (int i = 0; i < editorCount; i++) {
99972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i);
1000e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            editor.setGroupMetaData(mGroupMetaData);
1001e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
1002e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
1003e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
10040353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private void saveDefaultAccountIfNecessary() {
10050353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Verify that this is a newly created contact, that the contact is composed of only
10060353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // 1 raw contact, and that the contact is not a user profile.
10070353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (!Intent.ACTION_INSERT.equals(mAction) && mState.size() == 1 &&
10080353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                !isEditingUserProfile()) {
10090353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
10100353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
10110353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
10120353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Find the associated account for this contact (retrieve it here because there are
10130353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // multiple paths to creating a contact and this ensures we always have the correct
10140353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // account).
1015851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta rawContactDelta = mState.get(0);
1016851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String name = rawContactDelta.getAccountName();
1017851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String type = rawContactDelta.getAccountType();
1018851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String dataSet = rawContactDelta.getDataSet();
10190353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
10200353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        AccountWithDataSet account = (name == null || type == null) ? null :
10210353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                new AccountWithDataSet(name, type, dataSet);
10220353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        mEditorUtils.saveDefaultAndAllAccounts(account);
10230353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    }
10240353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
1025d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void addAccountSwitcher(
1026851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta currentState, BaseRawContactEditorView editor) {
10272b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final AccountWithDataSet currentAccount = new AccountWithDataSet(
1028851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getAccountName(),
1029851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getAccountType(),
1030851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getDataSet());
1031d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final View accountView = editor.findViewById(R.id.account);
1032daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        final View anchorView = editor.findViewById(R.id.account_selector_container);
1033daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        if (accountView == null) {
1034daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            return;
1035daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        }
1036daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        anchorView.setVisibility(View.VISIBLE);
1037d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        accountView.setOnClickListener(new View.OnClickListener() {
1038d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            @Override
1039d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            public void onClick(View v) {
1040d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                final ListPopupWindow popup = new ListPopupWindow(mContext, null);
1041a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                final AccountsListAdapter adapter =
10426f74c0f3313cbb08ee8a8fbb79bfefc5b03fe215Makoto Onuki                        new AccountsListAdapter(mContext,
10436f74c0f3313cbb08ee8a8fbb79bfefc5b03fe215Makoto Onuki                        AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, currentAccount);
1044d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setWidth(anchorView.getWidth());
1045d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAnchorView(anchorView);
1046d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAdapter(adapter);
1047d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setModal(true);
1048d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
1049d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
1050d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    @Override
1051d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    public void onItemClick(AdapterView<?> parent, View view, int position,
1052d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            long id) {
105386625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng                        UiClosables.closeQuietly(popup);
10542b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        AccountWithDataSet newAccount = adapter.getItem(position);
1055d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        if (!newAccount.equals(currentAccount)) {
1056d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            rebindEditorsForNewContact(currentState, currentAccount, newAccount);
1057d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        }
1058d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    }
1059d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                });
1060d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.show();
1061d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
1062d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        });
1063d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
1064d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
1065b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
1066eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
1067c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        inflater.inflate(R.menu.edit_contact, menu);
1068cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
1069cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1070b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
1071eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onPrepareOptionsMenu(Menu menu) {
10729b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
10739b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // because the custom action bar contains the "save" button now (not the overflow menu).
10749b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
1075692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem doneMenu = menu.findItem(R.id.menu_done);
1076692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem splitMenu = menu.findItem(R.id.menu_split);
1077692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem joinMenu = menu.findItem(R.id.menu_join);
1078692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem helpMenu = menu.findItem(R.id.menu_help);
1079f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee        final MenuItem discardMenu = menu.findItem(R.id.menu_discard);
1080d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        final MenuItem sendToVoiceMailMenu = menu.findItem(R.id.menu_send_to_voicemail);
1081d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        final MenuItem ringToneMenu = menu.findItem(R.id.menu_set_ringtone);
1082a513f720d2a15be6a00894c9a2812355d0643fcfBrian Attwell        final MenuItem deleteMenu = menu.findItem(R.id.menu_delete);
10835d2e262ab3658118a12fbf6d0edab76484368c24Walter Jang        deleteMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
108447b17c83b981172bda672314385eb8920753ba25Brian Attwell        deleteMenu.setIcon(R.drawable.ic_delete_white_24dp);
1085692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu
1086692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        // Set visibility of menus
1087692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        doneMenu.setVisible(false);
10889b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
1089f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee        // Discard menu is only available if at least one raw contact is editable
1090f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee        discardMenu.setVisible(mState != null &&
1091f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee                mState.getFirstWritableRawContact(mContext) != null);
1092f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee
1093692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        // help menu depending on whether this is inserting or editing
1094692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        if (Intent.ACTION_INSERT.equals(mAction)) {
1095ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus            HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add);
1096b8671d271e6a7c48aca785b867ef9a86c5012a85Brian Attwell            splitMenu.setVisible(false);
1097b8671d271e6a7c48aca785b867ef9a86c5012a85Brian Attwell            joinMenu.setVisible(false);
1098a513f720d2a15be6a00894c9a2812355d0643fcfBrian Attwell            deleteMenu.setVisible(false);
1099692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        } else if (Intent.ACTION_EDIT.equals(mAction)) {
1100ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus            HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit);
1101b8671d271e6a7c48aca785b867ef9a86c5012a85Brian Attwell            // Split only if more than one raw profile and not a user profile
1102b8671d271e6a7c48aca785b867ef9a86c5012a85Brian Attwell            splitMenu.setVisible(mState.size() > 1 && !isEditingUserProfile());
1103b8671d271e6a7c48aca785b867ef9a86c5012a85Brian Attwell            // Cannot join a user profile
1104b8671d271e6a7c48aca785b867ef9a86c5012a85Brian Attwell            joinMenu.setVisible(!isEditingUserProfile());
1105f19dda97bfdef84e3f39ba069a981004a5c797b1Paul Soulos            deleteMenu.setVisible(!mDisableDeleteMenuOption);
1106692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        } else {
1107692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu            // something else, so don't show the help menu
1108692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu            helpMenu.setVisible(false);
1109692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        }
111003587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson
1111d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // Hide telephony-related settings (ringtone, send to voicemail)
1112d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // if we don't have a telephone or are editing a new contact.
1113d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        sendToVoiceMailMenu.setChecked(mSendToVoicemailState);
1114d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        sendToVoiceMailMenu.setVisible(mArePhoneOptionsChangable);
1115d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        ringToneMenu.setVisible(mArePhoneOptionsChangable);
1116d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
111702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        int size = menu.size();
111802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        for (int i = 0; i < size; i++) {
111902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            menu.getItem(i).setEnabled(mEnabled);
112002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
1121cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
1122cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1123b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
1124cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public boolean onOptionsItemSelected(MenuItem item) {
1125cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (item.getItemId()) {
11262b24602f1b6661a669762cfc810cc76f51db6e16Brian Attwell            case android.R.id.home:
1127f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_done:
11289df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                return save(SaveMode.CLOSE);
1129f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_discard:
1130d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                return revert();
1131a513f720d2a15be6a00894c9a2812355d0643fcfBrian Attwell            case R.id.menu_delete:
1132a513f720d2a15be6a00894c9a2812355d0643fcfBrian Attwell                if (mListener != null) mListener.onDeleteRequested(mLookupUri);
1133a513f720d2a15be6a00894c9a2812355d0643fcfBrian Attwell                return true;
1134f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_split:
1135f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSplitContactAction();
1136f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_join:
1137f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doJoinContactAction();
1138d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            case R.id.menu_set_ringtone:
1139d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                doPickRingtone();
1140d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                return true;
1141d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            case R.id.menu_send_to_voicemail:
1142d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                // Update state and save
1143d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                mSendToVoicemailState = !mSendToVoicemailState;
1144d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                item.setChecked(mSendToVoicemailState);
1145d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                final Intent intent = ContactSaveService.createSetSendToVoicemail(
1146d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                        mContext, mLookupUri, mSendToVoicemailState);
1147d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                mContext.startService(intent);
1148d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                return true;
1149f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1150d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1151f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
1152f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1153cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1154f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSplitContactAction() {
1155f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
1156f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1157a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        final SplitContactConfirmationDialogFragment dialog =
11584a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                new SplitContactConfirmationDialogFragment();
11594a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.setTargetFragment(this, 0);
11604a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG);
1161f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
1162f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1163f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1164f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doJoinContactAction() {
11654c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        if (!hasValidState()) {
11664c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov            return false;
11674c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
11684c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
11694c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // If we just started creating a new contact and haven't added any data, it's too
11704c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // early to do a join
1171764637aba745612a9fdc07adb99c615263916fa8Josh Gargus        if (mState.size() == 1 && mState.get(0).isContactInsert() && !hasPendingChanges()) {
1172ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus            Toast.makeText(mContext, R.string.toast_join_with_empty_contact,
1173a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                            Toast.LENGTH_LONG).show();
1174a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            return true;
11754c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
11764c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
11779df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        return save(SaveMode.JOIN);
1178f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1179f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1180f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1181f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Check if our internal {@link #mState} is valid, usually checked before
1182f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * performing user actions.
1183f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1184f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean hasValidState() {
118544cfc56d1701629070384364416c1311b780535dChiao Cheng        return mState.size() > 0;
1186f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1187f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1189764637aba745612a9fdc07adb99c615263916fa8Josh Gargus     * Return true if there are any edits to the current contact which need to
1190764637aba745612a9fdc07adb99c615263916fa8Josh Gargus     * be saved.
1191764637aba745612a9fdc07adb99c615263916fa8Josh Gargus     */
1192764637aba745612a9fdc07adb99c615263916fa8Josh Gargus    private boolean hasPendingChanges() {
1193764637aba745612a9fdc07adb99c615263916fa8Josh Gargus        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1194851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        return RawContactModifier.hasChanges(mState, accountTypes);
1195764637aba745612a9fdc07adb99c615263916fa8Josh Gargus    }
1196764637aba745612a9fdc07adb99c615263916fa8Josh Gargus
11973f990ba4e35a99078d831c041290e574a320caa5Walter Jang    @Override
11989df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public boolean save(int saveMode) {
1199a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
1201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
12038c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        // If we are about to close the editor - there is no need to refresh the data
1204a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
12059d2bcfb40d0ee107886eb99eba13a840e944ba43Dianne Hackborn            getLoaderManager().destroyLoader(LOADER_DATA);
12068c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        }
12078c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov
1208825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.SAVING;
12096cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
1210764637aba745612a9fdc07adb99c615263916fa8Josh Gargus        if (!hasPendingChanges()) {
1211ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann            if (mLookupUri == null && saveMode == SaveMode.RELOAD) {
1212ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                // We don't have anything to save and there isn't even an existing contact yet.
1213ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                // Nothing to do, simply go back to editing mode
1214ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                mStatus = Status.EDITING;
1215ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                return true;
1216ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann            }
121736d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            onSaveCompleted(false, saveMode, mLookupUri != null, mLookupUri);
12186cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov            return true;
12196cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov        }
12206cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
1221a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        setEnabled(false);
1222f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
12230353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Store account as default account, only if this is a new contact
12240353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        saveDefaultAccountIfNecessary();
12250353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
12260353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Save contact
1227ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus        Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
1228ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
1229ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
1230ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                mUpdatedPhotos);
1231ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus        mContext.startService(intent);
123287270e1b58e669354bb1571ced686421c56deb7aJosh Gargus
123387270e1b58e669354bb1571ced686421c56deb7aJosh Gargus        // Don't try to save the same photos twice.
123487270e1b58e669354bb1571ced686421c56deb7aJosh Gargus        mUpdatedPhotos = new Bundle();
123587270e1b58e669354bb1571ced686421c56deb7aJosh Gargus
1236f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
1237f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1238f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1239d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private void doPickRingtone() {
1240d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1241d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        final Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
1242d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // Allow user to pick 'Default'
1243d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true);
1244d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // Show only ringtones
1245d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE);
1246d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // Allow the user to pick a silent ringtone
1247d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, true);
1248d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1249d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        final Uri ringtoneUri;
1250d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        if (mCustomRingtone != null) {
1251d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            ringtoneUri = Uri.parse(mCustomRingtone);
1252d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        } else {
1253d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            // Otherwise pick default ringtone Uri so that something is selected.
1254d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
1255d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        }
1256d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1257d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // Put checkmark next to the current ringtone for this contact
1258d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUri);
1259d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1260d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        // Launch!
1261d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        try {
1262d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            startActivityForResult(intent, REQUEST_CODE_PICK_RINGTONE);
1263d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        } catch (ActivityNotFoundException ex) {
1264d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            Toast.makeText(mContext, R.string.missing_app, Toast.LENGTH_SHORT).show();
1265d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        }
1266d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    }
1267d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1268d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    private void handleRingtonePicked(Uri pickedUri) {
1269d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        if (pickedUri == null || RingtoneManager.isDefault(pickedUri)) {
1270d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            mCustomRingtone = null;
1271d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        } else {
1272d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            mCustomRingtone = pickedUri.toString();
1273d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        }
1274d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        Intent intent = ContactSaveService.createSetRingtone(
1275d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                mContext, mLookupUri, mCustomRingtone);
1276d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell        mContext.startService(intent);
1277d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell    }
1278d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell
1279d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    public static class CancelEditDialogFragment extends DialogFragment {
1280d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1281d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public static void show(ContactEditorFragment fragment) {
1282d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment dialog = new CancelEditDialogFragment();
1283d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.setTargetFragment(fragment, 0);
1284d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.show(fragment.getFragmentManager(), "cancelEditor");
1285d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1286d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1287d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        @Override
1288d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1289d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            AlertDialog dialog = new AlertDialog.Builder(getActivity())
12904292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1291d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setMessage(R.string.cancel_confirmation_dialog_message)
12921ba8b6fea4c3f82ded19305874e72a326612aed1Katherine Kuan                    .setPositiveButton(android.R.string.ok,
1293d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1294d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            @Override
1295f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            public void onClick(DialogInterface dialogInterface, int whichButton) {
1296d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                                ((ContactEditorFragment)getTargetFragment()).doRevertAction();
1297d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            }
1298d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        }
1299d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    )
1300d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setNegativeButton(android.R.string.cancel, null)
1301d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .create();
1302d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            return dialog;
1303d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1304d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
1305d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1306d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private boolean revert() {
130744cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty() || !hasPendingChanges()) {
1308d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            doRevertAction();
1309d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        } else {
1310d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment.show(this);
1311d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1312d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        return true;
1313d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
1314d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1315d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private void doRevertAction() {
1316825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // When this Fragment is closed we don't want it to auto-save
1317825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.CLOSING;
131822fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        if (mListener != null) mListener.onReverted();
1319f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1320f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
13219b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    public void doSaveAction() {
13229b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        save(SaveMode.CLOSE);
13239b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    }
13249b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
13252b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    public void onJoinCompleted(Uri uri) {
132636d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri);
13272b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    }
13282b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov
132936d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro    public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
133036d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            Uri contactLookupUri) {
1331a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (hadChanges) {
133236d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            if (saveSucceeded) {
1333a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                if (saveMode != SaveMode.JOIN) {
1334a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                    Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
1335a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                }
1336a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else {
1337a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
1338a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            }
1339a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        }
1340f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
134115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.CLOSE:
13429df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            case SaveMode.HOME:
1343f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
134436d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                if (saveSucceeded && contactLookupUri != null) {
13453f990ba4e35a99078d831c041290e574a320caa5Walter Jang                    final Uri lookupUri = maybeConvertToLegacyLookupUri(
13463f990ba4e35a99078d831c041290e574a320caa5Walter Jang                            mContext, contactLookupUri, mLookupUri);
13473f990ba4e35a99078d831c041290e574a320caa5Walter Jang                    resultIntent = composeQuickContactsIntent(mContext, lookupUri);
1348f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
1349f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
1350f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1351825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                // It is already saved, so prevent that it is saved again
1352825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                mStatus = Status.CLOSING;
13535649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                if (mListener != null) mListener.onSaveFinished(resultIntent);
1354f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1355a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
135615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.RELOAD:
1357dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov            case SaveMode.JOIN:
135836d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                if (saveSucceeded && contactLookupUri != null) {
1359623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    // If it was a JOIN, we are now ready to bring up the join activity.
1360e813f5e56ddc6395c5e08e9245e2c5ad41e91724Daniel Lehmann                    if (saveMode == SaveMode.JOIN && hasValidState()) {
1361623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                        showJoinAggregateActivity(contactLookupUri);
1362623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    }
1363623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann
136415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If this was in INSERT, we are changing into an EDIT now.
136515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If it already was an EDIT, we are changing to the new Uri now
136644cfc56d1701629070384364416c1311b780535dChiao Cheng                    mState = new RawContactDeltaList();
13671015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov                    load(Intent.ACTION_EDIT, contactLookupUri, null);
1368825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    mStatus = Status.LOADING;
136915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
137015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                }
137115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                break;
1372a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
137315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.SPLIT:
1374a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                mStatus = Status.CLOSING;
1375a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                if (mListener != null) {
13768c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov                    mListener.onContactSplit(contactLookupUri);
1377a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                } else {
1378a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
1379a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                }
1380f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1381f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1382f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1383f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1384f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1385f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
1386f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
1387f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
1388f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1389f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
139073a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov        if (contactLookupUri == null || !isAdded()) {
1391f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
1392f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1393f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1394f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
1395623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        mContactWritableForJoin = isContactWritable();
1396c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell        final Intent intent = new Intent(UiIntentActions.PICK_JOIN_CONTACT_ACTION);
1397c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell        intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, mContactIdForJoin);
1398a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        startActivityForResult(intent, REQUEST_CODE_JOIN);
1399f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1400f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1401f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1402f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
1403f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1404f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
14052b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
1406623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                contactId, mContactWritableForJoin,
14072b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
14082b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        mContext.startService(intent);
1409f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1410f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1411f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1412ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     * Returns true if there is at least one writable raw contact in the current contact.
1413ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     */
1414ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    private boolean isContactWritable() {
1415a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1416ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        int size = mState.size();
1417ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        for (int i = 0; i < size; i++) {
1418851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDelta entity = mState.get(i);
1419851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = entity.getAccountType(accountTypes);
142096e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (type.areContactsWritable()) {
1421ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov                return true;
1422ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            }
1423ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        }
1424ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        return false;
1425ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    }
1426ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov
14272bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson    private boolean isEditingUserProfile() {
14282bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson        return mNewLocalProfile || mIsUserProfile;
14292bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson    }
14302bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson
1431f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1432f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
1433f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1434f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected long getContactId() {
143544cfc56d1701629070384364416c1311b780535dChiao Cheng        for (RawContactDelta rawContact : mState) {
143644cfc56d1701629070384364416c1311b780535dChiao Cheng            Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
143744cfc56d1701629070384364416c1311b780535dChiao Cheng            if (contactId != null) {
143844cfc56d1701629070384364416c1311b780535dChiao Cheng                return contactId;
1439f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
1440f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1441f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return 0;
1442f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1443f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1444f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1445f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Triggers an asynchronous search for aggregation suggestions.
1446f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
14472828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki    private void acquireAggregationSuggestions(Context context,
14482828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki            RawContactEditorView rawContactEditor) {
14499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        long rawContactId = rawContactEditor.getRawContactId();
14509302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (mAggregationSuggestionsRawContactId != rawContactId
14519302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                && mAggregationSuggestionView != null) {
14529302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
14539302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView = null;
14549302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionEngine.reset();
14559302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
14569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
14579302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionsRawContactId = rawContactId;
14589302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1459f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine == null) {
14602828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki            mAggregationSuggestionEngine = new AggregationSuggestionEngine(context);
1461f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.setListener(this);
1462f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.start();
1463f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1464f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1465916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        mAggregationSuggestionEngine.setContactId(getContactId());
1466916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
1467392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        LabeledEditorView nameEditor = rawContactEditor.getNameEditor();
1468f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mAggregationSuggestionEngine.onNameChange(nameEditor.getValues());
1469f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1470f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1471f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
1472f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onAggregationSuggestionChange() {
1473288532cddfccdc3793dd748d1c75750e2f46cb53Yorke Lee        Activity activity = getActivity();
1474288532cddfccdc3793dd748d1c75750e2f46cb53Yorke Lee        if ((activity != null && activity.isFinishing())
147544cfc56d1701629070384364416c1311b780535dChiao Cheng                || !isVisible() ||  mState.isEmpty() || mStatus != Status.EDITING) {
147602cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov            return;
147702cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov        }
147802cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov
147986625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng        UiClosables.closeQuietly(mAggregationSuggestionPopup);
1480f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
14816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) {
1482f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
1483f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1484f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
14856c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final RawContactEditorView rawContactView =
14866c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
148702a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        if (rawContactView == null) {
148802a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki            return; // Raw contact deleted?
148902a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        }
14906c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final View anchorView = rawContactView.findViewById(R.id.anchor_view);
14916c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup = new ListPopupWindow(mContext, null);
14926c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAnchorView(anchorView);
14936c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setWidth(anchorView.getWidth());
14946c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
14956c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAdapter(
14966c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                new AggregationSuggestionAdapter(getActivity(),
14976c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        mState.size() == 1 && mState.get(0).isContactInsert(),
14986c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        this, mAggregationSuggestionEngine.getSuggestions()));
14996c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setOnItemClickListener(mAggregationSuggestionItemClickListener);
15006c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.show();
1501bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1502bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1503bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1504bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
1505bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        long rawContactIds[] = new long[rawContactIdList.size()];
1506bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        for (int i = 0; i < rawContactIds.length; i++) {
1507bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            rawContactIds[i] = rawContactIdList.get(i);
1508bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1509bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        JoinSuggestedContactDialogFragment dialog =
1510bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new JoinSuggestedContactDialogFragment();
1511bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1512bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putLongArray("rawContactIds", rawContactIds);
1513bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1514bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
151574f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        try {
151674f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            dialog.show(getFragmentManager(), "join");
151774f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        } catch (Exception ex) {
151874f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            // No problem - the activity is no longer available to display the dialog
151974f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        }
1520bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1521bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1522bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
1523bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1524bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1525bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1526bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
15274292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1528bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
1529bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1530bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1531f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            @Override
1532bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1533bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1534bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1535bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                long rawContactIds[] =
1536bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getLongArray("rawContactIds");
1537bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doJoinSuggestedContact(rawContactIds);
1538bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1539bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1540bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1541bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1542bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1543bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1544bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1545bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1546bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1547bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Joins the suggested contact (specified by the id's of constituent raw
1548bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * contacts), save all changes, and stay in the editor.
1549bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1550bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doJoinSuggestedContact(long[] rawContactIds) {
1551cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1552cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov            return;
1553cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        }
1554cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov
1555bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mState.setJoinWithRawContacts(rawContactIds);
15569df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.RELOAD);
1557bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1558bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1559bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1560bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onEditAction(Uri contactLookupUri) {
1561bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        SuggestionEditConfirmationDialogFragment dialog =
1562bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new SuggestionEditConfirmationDialogFragment();
1563bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1564bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putParcelable("contactUri", contactLookupUri);
1565bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1566bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
1567bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.show(getFragmentManager(), "edit");
1568bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1569bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1570bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
1571bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1572bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1573bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1574bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
15754292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1576bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
1577bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1578bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1579f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            @Override
1580bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1581bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1582bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1583bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                Uri contactUri =
1584bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getParcelable("contactUri");
1585bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doEditSuggestedContact(contactUri);
1586bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1587bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1588bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1589bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1590bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1591bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1592bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1593bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1594bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1595bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Abandons the currently edited contact and switches to editing the suggested
1596bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * one, transferring all the data there
1597bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1598bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doEditSuggestedContact(Uri contactUri) {
1599bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        if (mListener != null) {
1600a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            // make sure we don't save this contact when closing down
1601a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            mStatus = Status.CLOSING;
1602bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            mListener.onEditOtherContactRequested(
1603bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    contactUri, mState.get(0).getContentValues());
1604bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1605bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1606bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1607a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    public void setAggregationSuggestionViewEnabled(boolean enabled) {
1608a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (mAggregationSuggestionView == null) {
1609a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            return;
1610a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1611a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1612a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
1613a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov                R.id.aggregation_suggestions);
1614a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        int count = itemList.getChildCount();
1615a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        for (int i = 0; i < count; i++) {
1616a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            itemList.getChildAt(i).setEnabled(enabled);
1617a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1618a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    }
1619a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1620f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
1621f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
1622d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putString(KEY_ACTION, mAction);
1623cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelable(KEY_URI, mLookupUri);
1624cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_DISABLE_DELETE_MENU_OPTION, mDisableDeleteMenuOption);
1625cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_NEW_LOCAL_PROFILE, mNewLocalProfile);
1626cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1627cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
1628cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1629cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelableArrayList(KEY_RAW_CONTACTS, mRawContacts == null
1630cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                ? Lists.<RawContact>newArrayList() : Lists.newArrayList(mRawContacts));
1631d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
1632f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (hasValidState()) {
1633f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Store entities with modifications
1634f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putParcelable(KEY_EDIT_STATE, mState);
1635f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1636ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov        outState.putInt(KEY_STATUS, mStatus);
1637cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
163844cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_HAS_NEW_CONTACT, mHasNewContact);
163944cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_NEW_CONTACT_READY, mNewContactDataReady);
1640cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1641cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_IS_EDIT, mIsEdit);
164244cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_EXISTING_CONTACT_READY, mExistingContactDataReady);
1643cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1644cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Phone specific options
1645bd127671f7fbcefb87a1b383140dee89cdb7039cBrian Attwell        outState.putBoolean(KEY_SEND_TO_VOICE_MAIL_STATE, mSendToVoicemailState);
1646bd127671f7fbcefb87a1b383140dee89cdb7039cBrian Attwell        outState.putBoolean(KEY_ARE_PHONE_OPTIONS_CHANGEABLE, mArePhoneOptionsChangable);
1647cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putString(KEY_CUSTOM_RINGTONE, mCustomRingtone);
1648cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1649cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Joins
1650cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
1651cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
1652cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1653daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        outState.putSerializable(KEY_EXPANDED_EDITORS, mExpandedEditors);
165428eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
1655cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
1656cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1657cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_ENABLED, mEnabled);
1658cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1659cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Photos
1660cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
1661cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelable(KEY_CURRENT_PHOTO_URI, mCurrentPhotoUri);
1662cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
1663cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1664cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Aggregations
1665cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putLong(KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID,
1666cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                mAggregationSuggestionsRawContactId);
1667cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
1668f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
1669f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1670f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1671d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
1672f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
1673f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (mStatus == Status.SUB_ACTIVITY) {
1674f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.EDITING;
1675f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        }
1676f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
16776fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        // See if the photo selection handler handles this result.
167891004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        if (mCurrentPhotoHandler != null && mCurrentPhotoHandler.handlePhotoActivityResult(
16796fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                requestCode, resultCode, data)) {
16806fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            return;
16816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        }
1682f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
16836fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        switch (requestCode) {
1684a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_JOIN: {
16850353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // Ignore failed requests
16860353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (resultCode != Activity.RESULT_OK) return;
1687f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
1688f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
1689f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
1690f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
16914a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                break;
1692f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
16930353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            case REQUEST_CODE_ACCOUNTS_CHANGED: {
16940353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // Bail if the account selector was not successful.
16950353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (resultCode != Activity.RESULT_OK) {
16960353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    mListener.onReverted();
16970353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    return;
16980353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                }
16990353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // If there's an account specified, use it.
17000353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (data != null) {
17014a1c574cd62eb7ca1e0fcc3a61e5378e5e0787feBrian Attwell                    AccountWithDataSet account = data.getParcelableExtra(
17024a1c574cd62eb7ca1e0fcc3a61e5378e5e0787feBrian Attwell                            Intents.Insert.EXTRA_ACCOUNT);
17030353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    if (account != null) {
17040353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                        createContact(account);
17050353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                        return;
17060353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    }
17070353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                }
17080353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // If there isn't an account specified, then this is likely a phone-local
17090353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // contact, so we should continue setting up the editor by automatically selecting
17100353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // the most appropriate account.
17110353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                createContact();
17120353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                break;
17130353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            }
1714d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            case REQUEST_CODE_PICK_RINGTONE: {
1715d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                if (data != null) {
1716d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                    final Uri pickedUri = data.getParcelableExtra(
1717d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                            RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
1718d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                    handleRingtonePicked(pickedUri);
1719d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                }
1720d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                break;
1721d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            }
1722f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1723cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
17249cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
1725c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    /**
1726c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
1727c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     */
1728637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee    private void setPhoto(long rawContact, Bitmap photo, Uri photoUri) {
1729bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
1730e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
1731e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus        if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) {
1732e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus            // This is unexpected.
1733e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus            Log.w(TAG, "Invalid bitmap passed to setPhoto()");
1734e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus        }
1735e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
17369302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestingEditor != null) {
1737c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            requestingEditor.setPhotoEntry(photo);
17387e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            // Immediately set all other photos as non-primary. Otherwise the UI can display
17397e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            // multiple photos as "Primary photo".
17407e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            for (int i = 0; i < mContent.getChildCount(); i++) {
17417e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                final View childView = mContent.getChildAt(i);
17427e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                if (childView instanceof BaseRawContactEditorView
17437e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                        && childView != requestingEditor) {
17447e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                    final BaseRawContactEditorView rawContactEditor
17457e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                            = (BaseRawContactEditorView) childView;
17467e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                    rawContactEditor.getPhotoEditor().setSuperPrimary(false);
17477e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                }
17487e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            }
17499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        } else {
17509302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            Log.w(TAG, "The contact that requested the photo is no longer present.");
17519302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1752e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
1753637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        mUpdatedPhotos.putParcelable(String.valueOf(rawContact), photoUri);
17549302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
17559302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
17569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    /**
17579302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     * Finds raw contact editor view for the given rawContactId.
17589302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     */
1759bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
1760c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        for (int i = 0; i < mContent.getChildCount(); i++) {
1761c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            final View childView = mContent.getChildAt(i);
176272af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
176372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
17649302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (editor.getRawContactId() == rawContactId) {
17659302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    return editor;
1766c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                }
1767c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1768c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        }
17699302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return null;
1770c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    }
1771c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1772fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
1773fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     * Returns true if there is currently more than one photo on screen.
1774fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1775fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    private boolean hasMoreThanOnePhoto() {
1776fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int countWithPicture = 0;
177791004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        final int numEntities = mState.size();
177891004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        for (int i = 0; i < numEntities; i++) {
1779851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta entity = mState.get(i);
1780851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if (entity.isVisible()) {
178191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                final ValuesDelta primary = entity.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
1782851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                if (primary != null && primary.getPhoto() != null) {
1783fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    countWithPicture++;
178491004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                } else {
1785851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final long rawContactId = entity.getRawContactId();
1786637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                    final Uri uri = mUpdatedPhotos.getParcelable(String.valueOf(rawContactId));
1787637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                    if (uri != null) {
1788637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                        try {
1789637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                            mContext.getContentResolver().openInputStream(uri);
179091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                            countWithPicture++;
1791637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                        } catch (FileNotFoundException e) {
179291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                        }
179391004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                    }
179491004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                }
179591004b37683c15650eccde68ff04defcf94a1c84Maurice Chu
179691004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                if (countWithPicture > 1) {
179791004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                    return true;
1798fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
1799fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1800fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1801fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        return false;
18029cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1803222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1804222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    /**
1805222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     * The listener for the data loader
1806222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     */
1807851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private final LoaderManager.LoaderCallbacks<Contact> mDataLoaderListener =
1808851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
1809fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
1810fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang        private long mLoaderStartTime;
1811fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
1812222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1813851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
1814222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            mLoaderStartTime = SystemClock.elapsedRealtime();
181545ee872fe7be69c6b3f0c59167eecd11af467812Makoto Onuki            return new ContactLoader(mContext, mLookupUri, true);
1816222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1817222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1818222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1819851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
1820222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long loaderCurrentTime = SystemClock.elapsedRealtime();
1821222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
18222621c5bb7049401c8bce740005fa60bf1b304b86Makoto Onuki            if (!data.isLoaded()) {
1823b4154e46dd98bcb4d85eb6fb210a048c8a7ff7aaBrian Attwell                // Item has been deleted. Close activity without saving again.
1824222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                Log.i(TAG, "No contact found. Closing activity");
1825b4154e46dd98bcb4d85eb6fb210a048c8a7ff7aaBrian Attwell                mStatus = Status.CLOSING;
182622fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann                if (mListener != null) mListener.onContactNotFound();
1827222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                return;
1828222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            }
1829222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1830825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            mStatus = Status.EDITING;
18316caccaeeed943db323be89853a108f422e670760Dmitri Plotnikov            mLookupUri = data.getLookupUri();
1832222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataStartTime = SystemClock.elapsedRealtime();
1833222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            setData(data);
1834222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataEndTime = SystemClock.elapsedRealtime();
1835c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1836222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
1837222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
18384ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
1839623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        @Override
1840851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
18414ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1842222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    };
1843a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
1844e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    /**
1845be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan     * The listener for the group meta data loader for all groups.
1846e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov     */
1847e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
1848e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            new LoaderCallbacks<Cursor>() {
1849e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1850e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1851e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public CursorLoader onCreateLoader(int id, Bundle args) {
1852be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan            return new GroupMetaDataLoader(mContext, Groups.CONTENT_URI);
1853e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
1854e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1855e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1856e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1857e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            mGroupMetaData = data;
1858e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            bindGroupMetaData();
1859e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
18604ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
1861f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann        @Override
18624ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<Cursor> loader) {
18634ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1864e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    };
1865e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1866a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    @Override
1867a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    public void onSplitContactConfirmed() {
186844cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
1869b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // This may happen when this Fragment is recreated by the system during users
1870b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // confirming the split action (and thus this method is called just before onCreate()),
1871b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // for example.
1872b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            Log.e(TAG, "mState became null during the user's confirming split action. " +
1873b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa                    "Cannot perform the save action.");
1874b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            return;
1875b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa        }
1876b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa
1877a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        mState.markRawContactsForSplitting();
18789df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.SPLIT);
1879a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    }
1880a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
18816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    /**
18826fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * Custom photo handler for the editor.  The inner listener that this creates also has a
18836fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * reference to the editor and acts as an {@link EditorListener}, and uses that editor to hold
18846fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * state information in several of the listener methods.
18856fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     */
18866fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private final class PhotoHandler extends PhotoSelectionHandler {
188728eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
188828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus        final long mRawContactId;
1889e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        private final BaseRawContactEditorView mEditor;
18904bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        private final PhotoActionListener mPhotoEditorListener;
189128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
18926fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode,
1893851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactDeltaList state) {
18947e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            super(context, editor.getPhotoEditor().getChangeAnchorView(), photoMode, false, state);
1895e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            mEditor = editor;
189628eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            mRawContactId = editor.getRawContactId();
18979a409d474b2b4f2e4261657f864eeb866fcb8816Daniel Lehmann            mPhotoEditorListener = new PhotoEditorListener();
1898e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        }
1899e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus
1900e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        @Override
1901e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        public PhotoActionListener getListener() {
19029a409d474b2b4f2e4261657f864eeb866fcb8816Daniel Lehmann            return mPhotoEditorListener;
1903e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        }
1904e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus
1905e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        @Override
1906637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        public void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) {
19074bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
190891004b37683c15650eccde68ff04defcf94a1c84Maurice Chu            mCurrentPhotoHandler = this;
1909e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            mStatus = Status.SUB_ACTIVITY;
1910637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            mCurrentPhotoUri = photoUri;
1911e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            ContactEditorFragment.this.startActivityForResult(intent, requestCode);
19129442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
19139442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
19146fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        private final class PhotoEditorListener extends PhotoSelectionHandler.PhotoActionListener
19156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                implements EditorListener {
1916fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
19176fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onRequest(int request) {
19196fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (!hasValidState()) return;
1920a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
19216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (request == EditorListener.REQUEST_PICK_PHOTO) {
19226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    onClick(mEditor.getPhotoEditor());
19239442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                }
19247e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                if (request == EditorListener.REQUEST_PICK_PRIMARY_PHOTO) {
19257e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                    useAsPrimaryChosen();
19267e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                }
19279442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
1928a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
19296fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19306fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onDeleteRequested(Editor removedEditor) {
19316fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // The picture cannot be deleted, it can only be removed, which is handled by
19326fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // onRemovePictureChosen()
19336fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
1934a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
19356fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            /**
19366fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             * User has chosen to set the selected photo as the (super) primary photo
19376fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             */
19387e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            public void useAsPrimaryChosen() {
19396fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Set the IsSuperPrimary for each editor
19406fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                int count = mContent.getChildCount();
19416fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                for (int i = 0; i < count; i++) {
19426fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    final View childView = mContent.getChildAt(i);
19436fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    if (childView instanceof BaseRawContactEditorView) {
19446fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        final BaseRawContactEditorView editor =
19456fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                                (BaseRawContactEditorView) childView;
19466fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        final PhotoEditorView photoEditor = editor.getPhotoEditor();
19476fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        photoEditor.setSuperPrimary(editor == mEditor);
19486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    }
19496fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                }
195091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
19516fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19529442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
19536fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            /**
19546fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             * User has chosen to remove a picture
19556fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             */
19566fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19576fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onRemovePictureChosen() {
1958c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell                mEditor.setPhotoEntry(null);
195928eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
196028eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                // Prevent bitmap from being restored if rotate the device.
196128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                // (only if we first chose a new photo before removing it)
196228eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                mUpdatedPhotos.remove(String.valueOf(mRawContactId));
196391004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
19646fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19656fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
19666fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
1967637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            public void onPhotoSelected(Uri uri) throws FileNotFoundException {
1968637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(mContext, uri);
1969637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                setPhoto(mRawContactId, bitmap, uri);
197091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                mCurrentPhotoHandler = null;
197191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
19726fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19736fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
19746fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
1975637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            public Uri getCurrentPhotoUri() {
1976637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                return mCurrentPhotoUri;
19776fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19786fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
19796fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19806fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onPhotoSelectionDismissed() {
19816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Nothing to do.
19829442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
19834a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        }
19844a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann    }
19852ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1986