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.Fragment;
25222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager;
26222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
27cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
28cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues;
29cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
30e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader;
31bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface;
32cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
33cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader;
34f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor;
35f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
3628eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargusimport android.graphics.BitmapFactory;
37cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
38cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
399767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock;
40cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
41362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Event;
42362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Organization;
43cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
4491004b37683c15650eccde68ff04defcf94a1c84Maurice Chuimport android.provider.ContactsContract.CommonDataKinds.Photo;
45362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
46f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
47be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuanimport android.provider.ContactsContract.Groups;
482013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmannimport android.provider.ContactsContract.Intents;
49f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
50688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Leeimport android.text.TextUtils;
51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log;
52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater;
53cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu;
54cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater;
55cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem;
56cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View;
57cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup;
58d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.AdapterView;
596c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.AdapterView.OnItemClickListener;
606c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.BaseAdapter;
6180d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
62d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.ListPopupWindow;
63cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
64cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
65e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.ContactSaveService;
66e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.GroupMetaDataLoader;
67e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
68e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ContactEditorAccountsChangedActivity;
69e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ContactEditorActivity;
70e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.JoinContactActivity;
7144cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.AccountTypeManager;
7244cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.ValuesDelta;
7344cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.AccountType;
7444cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.AccountWithDataSet;
7544cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.GoogleAccountType;
7644cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.util.AccountsListAdapter;
7744cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
78e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.detail.PhotoSelectionHandler;
79e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
80e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.Editor.EditorListener;
81851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.Contact;
82851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.ContactLoader;
83851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContact;
84851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDelta;
85851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactDeltaList;
86851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.RawContactModifier;
87e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ContactPhotoUtils;
88e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.HelpUtils;
8986625158bdc52855c37e96bf098ba7a213c810d7Chiao Chengimport com.android.contacts.util.UiClosables;
90851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.google.common.collect.ImmutableList;
9144cfc56d1701629070384364416c1311b780535dChiao Chengimport com.google.common.collect.Lists;
92e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
93f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File;
94637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Leeimport java.io.FileNotFoundException;
95cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList;
96f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
97f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator;
98f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
99f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
100a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmannpublic class ContactEditorFragment extends Fragment implements
101d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        SplitContactConfirmationDialogFragment.Listener,
102fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
1032b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann        RawContactReadOnlyEditorView.Listener {
104cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1052245870a1354df03512010e4968b144840894fb7Frank Sposaro    private static final String TAG = ContactEditorFragment.class.getSimpleName();
106cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int LOADER_DATA = 1;
108e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private static final int LOADER_GROUPS = 2;
109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
110d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_URI = "uri";
111d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_ACTION = "action";
112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_EDIT_STATE = "state";
1134bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
114f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
115637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee    private static final String KEY_CURRENT_PHOTO_URI = "currentphotouri";
116f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
117623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann    private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
1189302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions";
11902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private static final String KEY_ENABLED = "enabled";
120ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov    private static final String KEY_STATUS = "status";
121ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private static final String KEY_NEW_LOCAL_PROFILE = "newLocalProfile";
122ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private static final String KEY_IS_USER_PROFILE = "isUserProfile";
12328eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    private static final String KEY_UPDATED_PHOTOS = "updatedPhotos";
12444cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_IS_EDIT = "isEdit";
12544cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_HAS_NEW_CONTACT = "hasNewContact";
12644cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_NEW_CONTACT_READY = "newContactDataReady";
12744cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_EXISTING_CONTACT_READY = "existingContactDataReady";
12844cfc56d1701629070384364416c1311b780535dChiao Cheng    private static final String KEY_RAW_CONTACTS = "rawContacts";
129f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
130a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
131a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
132098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
13315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    /**
1347d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * An intent extra that forces the editor to add the edited contact
1357d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * to the default group (e.g. "My Contacts").
1367d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     */
1377d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
1387d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
139ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    public static final String INTENT_EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
140ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson
1417d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    /**
14215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     * Modes that specify what the AsyncTask has to perform after saving
14315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     */
1449df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public interface SaveMode {
14515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
14615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Close the editor after saving
14715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int CLOSE = 0;
14915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
15015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
15115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Reload the data so that the user can continue editing
15215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
15315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int RELOAD = 1;
15415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
15515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
15615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Split the contact after saving
15715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
15815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int SPLIT = 2;
15915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
16015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
16115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Join another contact after saving
16215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
16315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int JOIN = 3;
1649df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov
1659df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        /**
1669df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         * Navigate to Contacts Home activity after saving.
1679df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         */
1689df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        public static final int HOME = 4;
16915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    }
170a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
171825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private interface Status {
172825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
173825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * The loader is fetching data
174825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
175825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int LOADING = 0;
176825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
177825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
178825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * Not currently busy. We are waiting for the user to enter data
179825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
180825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int EDITING = 1;
181825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
182825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
183f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * The data is currently being saved. This is used to prevent more
184f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * auto-saves (they shouldn't overlap)
185825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
186825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int SAVING = 2;
187825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
188825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
189a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * Prevents any more saves. This is used if in the following cases:
190a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After Save/Close
191a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After Revert
192a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After the user has accepted an edit suggestion
193825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
194825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int CLOSING = 3;
195f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
196f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        /**
197f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * Prevents saving while running a child activity.
198f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         */
199f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        public static final int SUB_ACTIVITY = 4;
200825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    }
201825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
202a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_JOIN = 0;
2036fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private static final int REQUEST_CODE_ACCOUNTS_CHANGED = 1;
204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
2054bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki    /**
2064bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * The raw contact for which we started "take photo" or "choose photo from gallery" most
2074bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * recently.  Used to restore {@link #mCurrentPhotoHandler} after orientation change.
2084bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     */
2094bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki    private long mRawContactIdRequestingPhoto;
2104bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki    /**
2114bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * The {@link PhotoHandler} for the photo editor for the {@link #mRawContactIdRequestingPhoto}
2124bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * raw contact.
2134bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     *
2144bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * A {@link PhotoHandler} is created for each photo editor in {@link #bindPhotoHandler}, but
2154bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * the only "active" one should get the activity result.  This member represents the active
2164bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     * one.
2174bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki     */
21891004b37683c15650eccde68ff04defcf94a1c84Maurice Chu    private PhotoHandler mCurrentPhotoHandler;
219cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
220f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
221f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
222e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private Cursor mGroupMetaData;
223e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
224637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee    private Uri mCurrentPhotoUri;
22528eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    private Bundle mUpdatedPhotos = new Bundle();
226cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
227cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Context mContext;
228f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mAction;
229b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann    private Uri mLookupUri;
230f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Bundle mIntentExtras;
231cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Listener mListener;
232cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
233f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mContactIdForJoin;
234623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann    private boolean mContactWritableForJoin;
235cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2360353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private ContactEditorUtils mEditorUtils;
2370353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
238f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private LinearLayout mContent;
239851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private RawContactDeltaList mState;
240cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
241f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
242cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2439767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann    private long mLoaderStartTime;
2449767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann
245825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private int mStatus;
246825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
24744cfc56d1701629070384364416c1311b780535dChiao Cheng    // Whether to show the new contact blank form and if it's corresponding delta is ready.
24844cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mHasNewContact = false;
24944cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mNewContactDataReady = false;
25044cfc56d1701629070384364416c1311b780535dChiao Cheng
25144cfc56d1701629070384364416c1311b780535dChiao Cheng    // Whether it's an edit of existing contact and if it's corresponding delta is ready.
25244cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mIsEdit = false;
25344cfc56d1701629070384364416c1311b780535dChiao Cheng    private boolean mExistingContactDataReady = false;
25444cfc56d1701629070384364416c1311b780535dChiao Cheng
25544cfc56d1701629070384364416c1311b780535dChiao Cheng    // This is used to pre-populate the editor with a display name when a user edits a read-only
25644cfc56d1701629070384364416c1311b780535dChiao Cheng    // contact.
25744cfc56d1701629070384364416c1311b780535dChiao Cheng    private String mDefaultDisplayName;
25844cfc56d1701629070384364416c1311b780535dChiao Cheng
25944cfc56d1701629070384364416c1311b780535dChiao Cheng    // Used to temporarily store existing contact data during a rebind call (i.e. account switch)
26044cfc56d1701629070384364416c1311b780535dChiao Cheng    private ImmutableList<RawContact> mRawContacts;
26144cfc56d1701629070384364416c1311b780535dChiao Cheng
262f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private AggregationSuggestionEngine mAggregationSuggestionEngine;
2639302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private long mAggregationSuggestionsRawContactId;
2649302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private View mAggregationSuggestionView;
265f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
2666c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private ListPopupWindow mAggregationSuggestionPopup;
2676c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2686c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private static final class AggregationSuggestionAdapter extends BaseAdapter {
2696c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final Activity mActivity;
2706c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final boolean mSetNewContact;
2716c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final AggregationSuggestionView.Listener mListener;
2726c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final List<Suggestion> mSuggestions;
2736c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2746c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public AggregationSuggestionAdapter(Activity activity, boolean setNewContact,
2756c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) {
2766c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mActivity = activity;
2776c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSetNewContact = setNewContact;
2786c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mListener = listener;
2796c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSuggestions = suggestions;
2806c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2826c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2836c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public View getView(int position, View convertView, ViewGroup parent) {
2846c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            Suggestion suggestion = (Suggestion) getItem(position);
2856c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            LayoutInflater inflater = mActivity.getLayoutInflater();
2866c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            AggregationSuggestionView suggestionView =
2876c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                    (AggregationSuggestionView) inflater.inflate(
2886c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                            R.layout.aggregation_suggestions_item, null);
2896c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setNewContact(mSetNewContact);
2906c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setListener(mListener);
2916c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.bindSuggestion(suggestion);
2926c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return suggestionView;
2936c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2946c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2956c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2966c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public long getItemId(int position) {
2976c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return position;
2986c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2996c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
3006c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
3016c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public Object getItem(int position) {
3026c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.get(position);
3036c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
3046c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
3056c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
3066c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public int getCount() {
3076c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.size();
3086c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
3096c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    }
3106c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
3116c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private OnItemClickListener mAggregationSuggestionItemClickListener =
3126c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            new OnItemClickListener() {
3136c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
3146c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
3156c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view;
3166c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.handleItemClickEvent();
31786625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng            UiClosables.closeQuietly(mAggregationSuggestionPopup);
3186c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mAggregationSuggestionPopup = null;
3196c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
3206c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    };
3216c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
3227d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    private boolean mAutoAddToDefaultGroup;
3237d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
32402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private boolean mEnabled = true;
325eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov    private boolean mRequestFocus;
326ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private boolean mNewLocalProfile = false;
327ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private boolean mIsUserProfile = false;
32802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
329cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
330cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
331cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
33202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public void setEnabled(boolean enabled) {
33302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mEnabled != enabled) {
33402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = enabled;
33502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (mContent != null) {
33602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                int count = mContent.getChildCount();
33702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                for (int i = 0; i < count; i++) {
33802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                    mContent.getChildAt(i).setEnabled(enabled);
33902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                }
34002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
341a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            setAggregationSuggestionViewEnabled(enabled);
34202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            final Activity activity = getActivity();
34302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (activity != null) activity.invalidateOptionsMenu();
34402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
34502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
34602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
347cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
348cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public void onAttach(Activity activity) {
349cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        super.onAttach(activity);
350cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        mContext = activity;
3510353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        mEditorUtils = ContactEditorUtils.getInstance(mContext);
352cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
353cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
354cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
355f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onStop() {
356f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super.onStop();
35786625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng
35886625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng        UiClosables.closeQuietly(mAggregationSuggestionPopup);
35986625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng
360825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If anything was left unsaved, save it now but keep the editor open.
361f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
362623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            save(SaveMode.RELOAD);
363825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
364f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
365f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
366f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
36736184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    public void onDestroy() {
36836184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        super.onDestroy();
36936184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        if (mAggregationSuggestionEngine != null) {
37036184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee            mAggregationSuggestionEngine.quit();
37136184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        }
37236184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    }
37336184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee
37436184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    @Override
375cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
376cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
377cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
379e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
3803648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
381cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
382cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
383cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
384cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
385222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
386222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    public void onActivityCreated(Bundle savedInstanceState) {
387222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        super.onActivityCreated(savedInstanceState);
388222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
389098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        validateAction(mAction);
390098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
39144cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
392098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // The delta list may not have finished loading before orientation change happens.
393098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // In this case, there will be a saved state but deltas will be missing.  Reload from
394098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // database.
395825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            if (Intent.ACTION_EDIT.equals(mAction)) {
396098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // Either...
397098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // 1) orientation change but load never finished.
398098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // or
399098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng                // 2) not an orientation change.  data needs to be loaded for first time.
400825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
401098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            }
402098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        } else {
403098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            // Orientation change, we already have mState, it was loaded by onCreate
404098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            bindEditors();
405098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        }
406098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
40744cfc56d1701629070384364416c1311b780535dChiao Cheng        // Handle initial actions only when existing state missing
40844cfc56d1701629070384364416c1311b780535dChiao Cheng        if (savedInstanceState == null) {
40944cfc56d1701629070384364416c1311b780535dChiao Cheng            if (Intent.ACTION_EDIT.equals(mAction)) {
41044cfc56d1701629070384364416c1311b780535dChiao Cheng                mIsEdit = true;
41144cfc56d1701629070384364416c1311b780535dChiao Cheng            } else if (Intent.ACTION_INSERT.equals(mAction)) {
41244cfc56d1701629070384364416c1311b780535dChiao Cheng                mHasNewContact = true;
4132013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                final Account account = mIntentExtras == null ? null :
4142b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        (Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT);
4152b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                final String dataSet = mIntentExtras == null ? null :
4162b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        mIntentExtras.getString(Intents.Insert.DATA_SET);
4172013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann
4182013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                if (account != null) {
4192013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // Account specified in Intent
4202b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    createContact(new AccountWithDataSet(account.name, account.type, dataSet));
4212013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                } else {
4222013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // No Account specified. Let the user choose
42340bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    // Load Accounts async so that we can present them
4240353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    selectAccountAndCreateContact();
4252013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                }
426098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng            }
427098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        }
428098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng    }
429098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng
430098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng    /**
431098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     * Checks if the requested action is valid.
432098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     *
433098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     * @param action The action to test.
434098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     * @throws IllegalArgumentException when the action is invalid.
435098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng     */
436098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng    private void validateAction(String action) {
437e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng        if (Intent.ACTION_EDIT.equals(action) || Intent.ACTION_INSERT.equals(action) ||
438e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng                ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(action)) {
439e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng            return;
440825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
441098f630c3dd0d993a423425e138f95dba0d7612cChiao Cheng        throw new IllegalArgumentException("Unknown Action String " + mAction +
442e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng                ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT + " or " +
443e8e94423b463688951f806419dbd73e10e7bf7b4Chiao Cheng                ContactEditorActivity.ACTION_SAVE_COMPLETED);
444222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    }
445222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
446e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    @Override
447e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    public void onStart() {
448e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
449e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        super.onStart();
450e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
451e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
4521015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov    public void load(String action, Uri lookupUri, Bundle intentExtras) {
453f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mAction = action;
454b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        mLookupUri = lookupUri;
455f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mIntentExtras = intentExtras;
4567d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov        mAutoAddToDefaultGroup = mIntentExtras != null
4577d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                && mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
458ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        mNewLocalProfile = mIntentExtras != null
45936d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                && mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
461f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
462f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void setListener(Listener value) {
463f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mListener = value;
464cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
465cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
466cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
467f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
468d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        if (savedState != null) {
469d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // Restore mUri before calling super.onCreate so that onInitializeLoaders
470d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // would already have a uri and an action to work with
471b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            mLookupUri = savedState.getParcelable(KEY_URI);
472d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mAction = savedState.getString(KEY_ACTION);
473d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        }
474d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
475f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
476f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
477f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (savedState == null) {
478f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // If savedState is non-null, onRestoreInstanceState() will restore the generator.
479f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = new ViewIdGenerator();
480f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
481825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            // Read state from savedState. No loading involved here
482851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            mState = savedState.<RawContactDeltaList> getParcelable(KEY_EDIT_STATE);
4834bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mRawContactIdRequestingPhoto = savedState.getLong(
4844bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
485f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
486637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI);
487f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
488623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
4899302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS);
49002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = savedState.getBoolean(KEY_ENABLED);
491ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov            mStatus = savedState.getInt(KEY_STATUS);
492ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            mNewLocalProfile = savedState.getBoolean(KEY_NEW_LOCAL_PROFILE);
493ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
49428eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
49544cfc56d1701629070384364416c1311b780535dChiao Cheng            mIsEdit = savedState.getBoolean(KEY_IS_EDIT);
49644cfc56d1701629070384364416c1311b780535dChiao Cheng            mHasNewContact = savedState.getBoolean(KEY_HAS_NEW_CONTACT);
49744cfc56d1701629070384364416c1311b780535dChiao Cheng            mNewContactDataReady = savedState.getBoolean(KEY_NEW_CONTACT_READY);
49844cfc56d1701629070384364416c1311b780535dChiao Cheng            mExistingContactDataReady = savedState.getBoolean(KEY_EXISTING_CONTACT_READY);
49944cfc56d1701629070384364416c1311b780535dChiao Cheng            mRawContacts = ImmutableList.copyOf(savedState.<RawContact>getParcelableArrayList(
50044cfc56d1701629070384364416c1311b780535dChiao Cheng                    KEY_RAW_CONTACTS));
50144cfc56d1701629070384364416c1311b780535dChiao Cheng
50244cfc56d1701629070384364416c1311b780535dChiao Cheng        }
50344cfc56d1701629070384364416c1311b780535dChiao Cheng
50444cfc56d1701629070384364416c1311b780535dChiao Cheng        // mState can still be null because it may not have have finished loading before
50544cfc56d1701629070384364416c1311b780535dChiao Cheng        // onSaveInstanceState was called.
50644cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState == null) {
50744cfc56d1701629070384364416c1311b780535dChiao Cheng            mState = new RawContactDeltaList();
508cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
509cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
510cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
51144cfc56d1701629070384364416c1311b780535dChiao Cheng    public void setData(Contact contact) {
51244cfc56d1701629070384364416c1311b780535dChiao Cheng
513d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        // If we have already loaded data, we do not want to change it here to not confuse the user
51444cfc56d1701629070384364416c1311b780535dChiao Cheng        if (!mState.isEmpty()) {
515d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            Log.v(TAG, "Ignoring background change. This will have to be rebased later");
516d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            return;
517d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        }
518d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann
519fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        // See if this edit operation needs to be redirected to a custom editor
52044cfc56d1701629070384364416c1311b780535dChiao Cheng        mRawContacts = contact.getRawContacts();
52144cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mRawContacts.size() == 1) {
52244cfc56d1701629070384364416c1311b780535dChiao Cheng            RawContact rawContact = mRawContacts.get(0);
523851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            String type = rawContact.getAccountTypeString();
524851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            String dataSet = rawContact.getDataSet();
52547b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng            AccountType accountType = rawContact.getAccountType(mContext);
5262b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann            if (accountType.getEditContactActivityClassName() != null &&
5272b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann                    !accountType.areContactsWritable()) {
528fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                if (mListener != null) {
529851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    String name = rawContact.getAccountName();
530851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    long rawContactId = rawContact.getId();
5312b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    mListener.onCustomEditContactActivityRequested(
5322b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                            new AccountWithDataSet(name, type, dataSet),
533fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
534fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            mIntentExtras, true);
535fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                }
536fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                return;
537fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
538fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
539fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
540688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee        String displayName = null;
54144cfc56d1701629070384364416c1311b780535dChiao Cheng        // Check for writable raw contacts.  If there are none, then we need to create one so user
54244cfc56d1701629070384364416c1311b780535dChiao Cheng        // can edit.  For the user profile case, there is already an editable contact.
54344cfc56d1701629070384364416c1311b780535dChiao Cheng        if (!contact.isUserProfile() && !contact.isWritableContact(mContext)) {
54444cfc56d1701629070384364416c1311b780535dChiao Cheng            mHasNewContact = true;
54544cfc56d1701629070384364416c1311b780535dChiao Cheng
54644cfc56d1701629070384364416c1311b780535dChiao Cheng            // This is potentially an asynchronous call and will add deltas to list.
54744cfc56d1701629070384364416c1311b780535dChiao Cheng            selectAccountAndCreateContact();
548688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee            displayName = contact.getDisplayName();
54944cfc56d1701629070384364416c1311b780535dChiao Cheng        }
55044cfc56d1701629070384364416c1311b780535dChiao Cheng
55144cfc56d1701629070384364416c1311b780535dChiao Cheng        // This also adds deltas to list
552688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee        // If displayName is null at this point it is simply ignored later on by the editor.
553688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee        bindEditorsForExistingContact(displayName, contact.isUserProfile(),
55444cfc56d1701629070384364416c1311b780535dChiao Cheng                mRawContacts);
555fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
556fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
557fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    @Override
5582b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    public void onExternalEditorRequest(AccountWithDataSet account, Uri uri) {
559fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        mListener.onCustomEditContactActivityRequested(account, uri, null, false);
560fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
561fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
56244cfc56d1701629070384364416c1311b780535dChiao Cheng    private void bindEditorsForExistingContact(String displayName, boolean isUserProfile,
56344cfc56d1701629070384364416c1311b780535dChiao Cheng            ImmutableList<RawContact> rawContacts) {
56402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        setEnabled(true);
56544cfc56d1701629070384364416c1311b780535dChiao Cheng        mDefaultDisplayName = displayName;
56602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
56744cfc56d1701629070384364416c1311b780535dChiao Cheng        mState.addAll(rawContacts.iterator());
5681ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        setIntentExtras(mIntentExtras);
5691ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        mIntentExtras = null;
570e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov
571ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // For user profile, change the contacts query URI
57244cfc56d1701629070384364416c1311b780535dChiao Cheng        mIsUserProfile = isUserProfile;
57348ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson        boolean localProfileExists = false;
57448ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson
575ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (mIsUserProfile) {
576851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            for (RawContactDelta state : mState) {
57748ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                // For profile contacts, we need a different query URI
578ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson                state.setProfileQueryUri();
57948ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                // Try to find a local profile contact
58048ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                if (state.getValues().getAsString(RawContacts.ACCOUNT_TYPE) == null) {
58148ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                    localProfileExists = true;
58248ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                }
58348ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson            }
58448ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson            // Editor should always present a local profile for editing
58548ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson            if (!localProfileExists) {
58647b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng                final RawContact rawContact = new RawContact();
587851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                rawContact.setAccountToLocal();
588851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu
589851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactDelta insert = new RawContactDelta(ValuesDelta.fromAfter(
590851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                        rawContact.getValues()));
59148ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                insert.setProfileQueryUri();
59248ed982e078de00f6be49319ccf09bbb2aaadf5eIsaac Katzenelson                mState.add(insert);
593ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            }
594ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        }
595eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
59644cfc56d1701629070384364416c1311b780535dChiao Cheng        mExistingContactDataReady = true;
5971ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        bindEditors();
5981ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    }
5991ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov
6001ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    /**
6011ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     * Merges extras from the intent.
6021ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     */
6031ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    public void setIntentExtras(Bundle extras) {
6041ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        if (extras == null || extras.size() == 0) {
6051ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            return;
606bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
607916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
608a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
609851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContactDelta state : mState) {
610851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = state.getAccountType(accountTypes);
61196e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (type.areContactsWritable()) {
6121ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                // Apply extras to the first writable raw contact only
613851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactModifier.parseExtras(mContext, type, state, extras);
6141ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                break;
6151ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            }
6161ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        }
617f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
618cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
6190353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private void selectAccountAndCreateContact() {
6200353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // If this is a local profile, then skip the logic about showing the accounts changed
6210353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // activity and create a phone-local contact.
6220353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (mNewLocalProfile) {
6230353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            createContact(null);
6240353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
6250353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
6260353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
6270353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // If there is no default account or the accounts have changed such that we need to
6280353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // prompt the user again, then launch the account prompt.
6290353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (mEditorUtils.shouldShowAccountChangedNotification()) {
6300353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            Intent intent = new Intent(mContext, ContactEditorAccountsChangedActivity.class);
6310353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            mStatus = Status.SUB_ACTIVITY;
6320353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            startActivityForResult(intent, REQUEST_CODE_ACCOUNTS_CHANGED);
6330353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        } else {
6340353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            // Otherwise, there should be a default account. Then either create a local contact
6350353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            // (if default account is null) or create a contact with the specified account.
6360353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            AccountWithDataSet defaultAccount = mEditorUtils.getDefaultAccount();
6370353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            if (defaultAccount == null) {
6380353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                createContact(null);
6390353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            } else {
6400353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                createContact(defaultAccount);
6410353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            }
6420353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
6430353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    }
6440353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
645d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
6460353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan     * Create a contact by automatically selecting the first account. If there's no available
6470353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan     * account, a device-local contact should be created.
648d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
649d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void createContact() {
6502b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final List<AccountWithDataSet> accounts =
651a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov                AccountTypeManager.getInstance(mContext).getAccounts(true);
6520353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // No Accounts available. Create a phone-local contact.
6530353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (accounts.isEmpty()) {
65440bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov            createContact(null);
6550353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
656f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
657cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
658d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // We have an account switcher in "create-account" screen, so don't need to ask a user to
659d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // select an account here.
660d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        createContact(accounts.get(0));
661cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
662cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
663cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    /**
664d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Shows account creation screen associated with a given account.
665d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
666d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param account may be null to signal a device-local contact should be created.
667cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann     */
6682b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void createContact(AccountWithDataSet account) {
669a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
670b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        final AccountType accountType =
6712b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                accountTypes.getAccountType(account != null ? account.type : null,
6722b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        account != null ? account.dataSet : null);
673fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
674b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        if (accountType.getCreateContactActivityClassName() != null) {
675fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (mListener != null) {
676fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                mListener.onCustomCreateContactActivityRequested(account, mIntentExtras);
677fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
678fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        } else {
679b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            bindEditorsForNewContact(account, accountType);
680fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
681fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
682fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
683d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
684d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
685d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Some of old data are reused with new restriction enforced by the new account.
686d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
6872b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro     * @param oldState Old data being edited.
688d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param oldAccount Old account associated with oldState.
689d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param newAccount New account to be used.
690d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
691d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void rebindEditorsForNewContact(
692851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDelta oldState, AccountWithDataSet oldAccount,
693851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            AccountWithDataSet newAccount) {
694d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
6952b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        AccountType oldAccountType = accountTypes.getAccountType(
6962b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                oldAccount.type, oldAccount.dataSet);
6972b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        AccountType newAccountType = accountTypes.getAccountType(
6982b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                newAccount.type, newAccount.dataSet);
699d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
700d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccountType.getCreateContactActivityClassName() != null) {
701d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            Log.w(TAG, "external activity called in rebind situation");
702d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            if (mListener != null) {
703d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
704d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
705d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
70644cfc56d1701629070384364416c1311b780535dChiao Cheng            mExistingContactDataReady = false;
70744cfc56d1701629070384364416c1311b780535dChiao Cheng            mNewContactDataReady = false;
70844cfc56d1701629070384364416c1311b780535dChiao Cheng            mState = new RawContactDeltaList();
709d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType);
71044cfc56d1701629070384364416c1311b780535dChiao Cheng            if (mIsEdit) {
71144cfc56d1701629070384364416c1311b780535dChiao Cheng                bindEditorsForExistingContact(mDefaultDisplayName, mIsUserProfile, mRawContacts);
71244cfc56d1701629070384364416c1311b780535dChiao Cheng            }
713d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
714d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
715d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
7162b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void bindEditorsForNewContact(AccountWithDataSet account,
7172b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType accountType) {
718d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        bindEditorsForNewContact(account, accountType, null, null);
719d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
720d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
7212b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void bindEditorsForNewContact(AccountWithDataSet newAccount,
722851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType newAccountType, RawContactDelta oldState,
723851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            AccountType oldAccountType) {
724a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        mStatus = Status.EDITING;
725a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
72647b6f70eadb118d815b4aaf5426c070bd75a38fbChiao Cheng        final RawContact rawContact = new RawContact();
727d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccount != null) {
728851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            rawContact.setAccount(newAccount);
729f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
730851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            rawContact.setAccountToLocal();
731cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
732cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
73344cfc56d1701629070384364416c1311b780535dChiao Cheng        final ValuesDelta valuesDelta = ValuesDelta.fromAfter(rawContact.getValues());
73444cfc56d1701629070384364416c1311b780535dChiao Cheng        final RawContactDelta insert = new RawContactDelta(valuesDelta);
735d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (oldState == null) {
736d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            // Parse any values from incoming intent
737851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
738d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
739851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactModifier.migrateStateForNewContact(mContext, oldState, insert,
740d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    oldAccountType, newAccountType);
741d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
742f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
74369f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        // Ensure we have some default fields (if the account type does not support a field,
744362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmann        // ensureKind will not add it, so it is safe to add e.g. Event)
745851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
746851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
747851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
748851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
749851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        RawContactModifier.ensureKindExists(insert, newAccountType,
750851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                StructuredPostal.CONTENT_ITEM_TYPE);
751f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
752ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // Set the correct URI for saving the contact as a profile
753ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (mNewLocalProfile) {
754ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            insert.setProfileQueryUri();
755ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        }
756ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson
75744cfc56d1701629070384364416c1311b780535dChiao Cheng        mState.add(insert);
758f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
759eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
760eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
76144cfc56d1701629070384364416c1311b780535dChiao Cheng        mNewContactDataReady = true;
762f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
763cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
764cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
765f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void bindEditors() {
7665671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        // bindEditors() can only bind views if there is data in mState, so immediately return
7675671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        // if mState is null
76844cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
76944cfc56d1701629070384364416c1311b780535dChiao Cheng            return;
77044cfc56d1701629070384364416c1311b780535dChiao Cheng        }
77144cfc56d1701629070384364416c1311b780535dChiao Cheng
77244cfc56d1701629070384364416c1311b780535dChiao Cheng        // Check if delta list is ready.  Delta list is populated from existing data and when
77344cfc56d1701629070384364416c1311b780535dChiao Cheng        // editing an read-only contact, it's also populated with newly created data for the
77444cfc56d1701629070384364416c1311b780535dChiao Cheng        // blank form.  When the data is not ready, skip. This method will be called multiple times.
77544cfc56d1701629070384364416c1311b780535dChiao Cheng        if ((mIsEdit && !mExistingContactDataReady) || (mHasNewContact && !mNewContactDataReady)) {
7765671c7e7718c3285dc0391807401083986fcfd51Maurice Chu            return;
7775671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        }
7785671c7e7718c3285dc0391807401083986fcfd51Maurice Chu
779f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
780f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
781cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
782f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
783f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
784cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
785f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
786f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
787a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
788a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        int numRawContacts = mState.size();
78944cfc56d1701629070384364416c1311b780535dChiao Cheng
790a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        for (int i = 0; i < numRawContacts; i++) {
791f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
792851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta rawContactDelta = mState.get(i);
793851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if (!rawContactDelta.isVisible()) continue;
794f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
795851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = rawContactDelta.getAccountType(accountTypes);
796851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final long rawContactId = rawContactDelta.getRawContactId();
797f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
79872af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            final BaseRawContactEditorView editor;
7992b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann            if (!type.areContactsWritable()) {
800fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                editor = (BaseRawContactEditorView) inflater.inflate(
8012b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann                        R.layout.raw_contact_readonly_editor_view, mContent, false);
8022b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann                ((RawContactReadOnlyEditorView) editor).setListener(this);
803fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            } else {
804fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view,
805fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                        mContent, false);
806cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
80744cfc56d1701629070384364416c1311b780535dChiao Cheng            if (mHasNewContact && !mNewLocalProfile) {
8082b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                final List<AccountWithDataSet> accounts =
809d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        AccountTypeManager.getInstance(mContext).getAccounts(true);
81044cfc56d1701629070384364416c1311b780535dChiao Cheng                if (accounts.size() > 1) {
811d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    addAccountSwitcher(mState.get(0), editor);
812a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan                } else {
813a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan                    disableAccountSwitcher(editor);
814d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                }
815a3e69af03dd35124941a48c3bfaea87468d66863Katherine Kuan            } else {
816a3e69af03dd35124941a48c3bfaea87468d66863Katherine Kuan                disableAccountSwitcher(editor);
817d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
818a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan
81902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            editor.setEnabled(mEnabled);
820cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
821f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
8227d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
823851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile());
824f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
8256fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            // Set up the photo handler.
8266fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            bindPhotoHandler(editor, type, mState);
8276fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
82828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            // If a new photo was chosen but not yet saved, we need to
82928eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            // update the thumbnail to reflect this.
83028eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            Bitmap bitmap = updatedBitmapForRawContact(rawContactId);
83128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            if (bitmap != null) editor.setPhotoBitmap(bitmap);
83228eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
83372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (editor instanceof RawContactEditorView) {
8342828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                final Activity activity = getActivity();
83572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
8365ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                EditorListener listener = new EditorListener() {
837f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
838f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
839f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    public void onRequest(int request) {
8402828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                        if (activity.isFinishing()) { // Make sure activity is still running.
8412828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                            return;
8422828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                        }
8432bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson                        if (request == EditorListener.FIELD_CHANGED && !isEditingUserProfile()) {
8442828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                            acquireAggregationSuggestions(activity, rawContactEditor);
84511bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                        }
846f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
847f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
848f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
8492293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                    public void onDeleteRequested(Editor removedEditor) {
850f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
8515ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                };
8525ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov
85344cfc56d1701629070384364416c1311b780535dChiao Cheng                final StructuredNameEditorView nameEditor = rawContactEditor.getNameEditor();
8545ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                if (mRequestFocus) {
8555ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    nameEditor.requestFocus();
8565ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    mRequestFocus = false;
8575ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                }
8585ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                nameEditor.setEditorListener(listener);
859688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                if (!TextUtils.isEmpty(mDefaultDisplayName)) {
860688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                    nameEditor.setDisplayName(mDefaultDisplayName);
861688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                }
862f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
8635ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView phoneticNameEditor =
8645ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                        rawContactEditor.getPhoneticNameEditor();
8655ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                phoneticNameEditor.setEditorListener(listener);
8667d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
8677d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
8689302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (rawContactId == mAggregationSuggestionsRawContactId) {
8692828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                    acquireAggregationSuggestions(activity, rawContactEditor);
870f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
871f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
872cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
873f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
874eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = false;
875eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
876e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        bindGroupMetaData();
877e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
878f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
879f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
880a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
881a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        // Refresh Action Bar as the visibility of the join command
882825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Activity can be null if we have been detached from the Activity
883825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        final Activity activity = getActivity();
884825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (activity != null) activity.invalidateOptionsMenu();
8856fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    }
886eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
88728eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    /**
88828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus     * If we've stashed a temporary file containing a contact's new photo,
88928eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus     * decode it and return the bitmap.
89028eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus     * @param rawContactId identifies the raw-contact whose Bitmap we'll try to return.
89128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus     * @return Bitmap of photo for specified raw-contact, or null
89228eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    */
89328eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    private Bitmap updatedBitmapForRawContact(long rawContactId) {
89428eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus        String path = mUpdatedPhotos.getString(String.valueOf(rawContactId));
89528eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus        return BitmapFactory.decodeFile(path);
89628eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    }
89728eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
8986fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private void bindPhotoHandler(BaseRawContactEditorView editor, AccountType type,
899851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDeltaList state) {
9006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        final int mode;
9016fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        if (type.areContactsWritable()) {
9026fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            if (editor.hasSetPhoto()) {
9036fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (hasMoreThanOnePhoto()) {
904ced983d7a816256d93fdea1f81e63e4598c18875Josh Gargus                    mode = PhotoActionPopup.Modes.PHOTO_ALLOW_PRIMARY;
9056fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                } else {
906ced983d7a816256d93fdea1f81e63e4598c18875Josh Gargus                    mode = PhotoActionPopup.Modes.PHOTO_DISALLOW_PRIMARY;
9076fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                }
9086fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            } else {
909ced983d7a816256d93fdea1f81e63e4598c18875Josh Gargus                mode = PhotoActionPopup.Modes.NO_PHOTO;
9106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
9116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        } else {
9126fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            if (editor.hasSetPhoto() && hasMoreThanOnePhoto()) {
913ced983d7a816256d93fdea1f81e63e4598c18875Josh Gargus                mode = PhotoActionPopup.Modes.READ_ONLY_ALLOW_PRIMARY;
9146fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            } else {
9156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Read-only and either no photo or the only photo ==> no options
916740552201d103b80bc49ea8a39a30536222672eaDaniel Lehmann                editor.getPhotoEditor().setEditorListener(null);
9176fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                return;
9186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
9196fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        }
92091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        final PhotoHandler photoHandler = new PhotoHandler(mContext, editor, mode, state);
9216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        editor.getPhotoEditor().setEditorListener(
92291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                (PhotoHandler.PhotoEditorListener) photoHandler.getListener());
9234bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki
9244bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        // Note a newly created raw contact gets some random negative ID, so any value is valid
9254bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        // here. (i.e. don't check against -1 or anything.)
9264bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        if (mRawContactIdRequestingPhoto == editor.getRawContactId()) {
9274bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mCurrentPhotoHandler = photoHandler;
9284bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        }
929cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
930cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
931e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private void bindGroupMetaData() {
932e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        if (mGroupMetaData == null) {
933e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            return;
934e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
935e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
936e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        int editorCount = mContent.getChildCount();
937e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        for (int i = 0; i < editorCount; i++) {
93872af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i);
939e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            editor.setGroupMetaData(mGroupMetaData);
940e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
941e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
942e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
9430353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private void saveDefaultAccountIfNecessary() {
9440353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Verify that this is a newly created contact, that the contact is composed of only
9450353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // 1 raw contact, and that the contact is not a user profile.
9460353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (!Intent.ACTION_INSERT.equals(mAction) && mState.size() == 1 &&
9470353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                !isEditingUserProfile()) {
9480353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
9490353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
9500353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
9510353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Find the associated account for this contact (retrieve it here because there are
9520353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // multiple paths to creating a contact and this ensures we always have the correct
9530353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // account).
954851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta rawContactDelta = mState.get(0);
955851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String name = rawContactDelta.getAccountName();
956851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String type = rawContactDelta.getAccountType();
957851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String dataSet = rawContactDelta.getDataSet();
9580353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
9590353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        AccountWithDataSet account = (name == null || type == null) ? null :
9600353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                new AccountWithDataSet(name, type, dataSet);
9610353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        mEditorUtils.saveDefaultAndAllAccounts(account);
9620353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    }
9630353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
964d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void addAccountSwitcher(
965851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta currentState, BaseRawContactEditorView editor) {
9662b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final AccountWithDataSet currentAccount = new AccountWithDataSet(
967851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getAccountName(),
968851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getAccountType(),
969851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getDataSet());
970d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final View accountView = editor.findViewById(R.id.account);
971fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan        final View anchorView = editor.findViewById(R.id.account_container);
972d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        accountView.setOnClickListener(new View.OnClickListener() {
973d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            @Override
974d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            public void onClick(View v) {
975d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                final ListPopupWindow popup = new ListPopupWindow(mContext, null);
976a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                final AccountsListAdapter adapter =
9776f74c0f3313cbb08ee8a8fbb79bfefc5b03fe215Makoto Onuki                        new AccountsListAdapter(mContext,
9786f74c0f3313cbb08ee8a8fbb79bfefc5b03fe215Makoto Onuki                        AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, currentAccount);
979d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setWidth(anchorView.getWidth());
980d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAnchorView(anchorView);
981d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAdapter(adapter);
982d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setModal(true);
983d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
984d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
985d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    @Override
986d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    public void onItemClick(AdapterView<?> parent, View view, int position,
987d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            long id) {
98886625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng                        UiClosables.closeQuietly(popup);
9892b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        AccountWithDataSet newAccount = adapter.getItem(position);
990d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        if (!newAccount.equals(currentAccount)) {
991d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            rebindEditorsForNewContact(currentState, currentAccount, newAccount);
992d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        }
993d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    }
994d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                });
995d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.show();
996d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
997d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        });
998d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
999d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
1000a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan    private void disableAccountSwitcher(BaseRawContactEditorView editor) {
1001a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        // Remove the pressed state from the account header because the user cannot switch accounts
1002a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        // on an existing contact
1003a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        final View accountView = editor.findViewById(R.id.account);
1004740552201d103b80bc49ea8a39a30536222672eaDaniel Lehmann        accountView.setBackground(null);
1005a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        accountView.setEnabled(false);
1006a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan    }
1007a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan
1008b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
1009eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
1010c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        inflater.inflate(R.menu.edit_contact, menu);
1011cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
1012cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1013b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
1014eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onPrepareOptionsMenu(Menu menu) {
10159b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
10169b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // because the custom action bar contains the "save" button now (not the overflow menu).
10179b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
1018692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem doneMenu = menu.findItem(R.id.menu_done);
1019692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem splitMenu = menu.findItem(R.id.menu_split);
1020692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem joinMenu = menu.findItem(R.id.menu_join);
1021692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        final MenuItem helpMenu = menu.findItem(R.id.menu_help);
1022f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee        final MenuItem discardMenu = menu.findItem(R.id.menu_discard);
1023692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu
1024692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        // Set visibility of menus
1025692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        doneMenu.setVisible(false);
10269b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
102703587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson        // Split only if more than one raw profile and not a user profile
102844cfc56d1701629070384364416c1311b780535dChiao Cheng        splitMenu.setVisible(mState.size() > 1 && !isEditingUserProfile());
102903587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson
1030692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        // Cannot join a user profile
1031692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        joinMenu.setVisible(!isEditingUserProfile());
1032692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu
1033f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee        // Discard menu is only available if at least one raw contact is editable
1034f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee        discardMenu.setVisible(mState != null &&
1035f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee                mState.getFirstWritableRawContact(mContext) != null);
1036f3c73113f0882d79aece54bc8ad467a5d0660f62Yorke Lee
1037692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        // help menu depending on whether this is inserting or editing
1038692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        if (Intent.ACTION_INSERT.equals(mAction)) {
1039692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu            // inserting
1040ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus            HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add);
1041692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        } else if (Intent.ACTION_EDIT.equals(mAction)) {
1042692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu            // editing
1043ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus            HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit);
1044692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        } else {
1045692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu            // something else, so don't show the help menu
1046692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu            helpMenu.setVisible(false);
1047692d46364f2f0e32fd481b977c9e16832e70de5cMaurice Chu        }
104803587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson
104902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        int size = menu.size();
105002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        for (int i = 0; i < size; i++) {
105102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            menu.getItem(i).setEnabled(mEnabled);
105202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
1053cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
1054cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1055b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
1056cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public boolean onOptionsItemSelected(MenuItem item) {
1057cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (item.getItemId()) {
1058f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_done:
10599df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                return save(SaveMode.CLOSE);
1060f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_discard:
1061d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                return revert();
1062f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_split:
1063f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSplitContactAction();
1064f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_join:
1065f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doJoinContactAction();
1066f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1067f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
1068f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1069cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1070f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSplitContactAction() {
1071f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
1072f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1073a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        final SplitContactConfirmationDialogFragment dialog =
10744a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                new SplitContactConfirmationDialogFragment();
10754a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.setTargetFragment(this, 0);
10764a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG);
1077f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
1078f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1079f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1080f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doJoinContactAction() {
10814c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        if (!hasValidState()) {
10824c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov            return false;
10834c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
10844c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
10854c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // If we just started creating a new contact and haven't added any data, it's too
10864c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // early to do a join
1087764637aba745612a9fdc07adb99c615263916fa8Josh Gargus        if (mState.size() == 1 && mState.get(0).isContactInsert() && !hasPendingChanges()) {
1088ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus            Toast.makeText(mContext, R.string.toast_join_with_empty_contact,
1089a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                            Toast.LENGTH_LONG).show();
1090a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            return true;
10914c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
10924c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
10939df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        return save(SaveMode.JOIN);
1094f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1095f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1096f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1097f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Check if our internal {@link #mState} is valid, usually checked before
1098f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * performing user actions.
1099f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1100f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean hasValidState() {
110144cfc56d1701629070384364416c1311b780535dChiao Cheng        return mState.size() > 0;
1102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1103f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1105764637aba745612a9fdc07adb99c615263916fa8Josh Gargus     * Return true if there are any edits to the current contact which need to
1106764637aba745612a9fdc07adb99c615263916fa8Josh Gargus     * be saved.
1107764637aba745612a9fdc07adb99c615263916fa8Josh Gargus     */
1108764637aba745612a9fdc07adb99c615263916fa8Josh Gargus    private boolean hasPendingChanges() {
1109764637aba745612a9fdc07adb99c615263916fa8Josh Gargus        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1110851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        return RawContactModifier.hasChanges(mState, accountTypes);
1111764637aba745612a9fdc07adb99c615263916fa8Josh Gargus    }
1112764637aba745612a9fdc07adb99c615263916fa8Josh Gargus
1113764637aba745612a9fdc07adb99c615263916fa8Josh Gargus    /**
1114f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Saves or creates the contact based on the mode, and if successful
1115f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * finishes the activity.
1116f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
11179df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public boolean save(int saveMode) {
1118a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1119f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
1120f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1121f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
11228c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        // If we are about to close the editor - there is no need to refresh the data
1123a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
11249d2bcfb40d0ee107886eb99eba13a840e944ba43Dianne Hackborn            getLoaderManager().destroyLoader(LOADER_DATA);
11258c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        }
11268c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov
1127825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.SAVING;
11286cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
1129764637aba745612a9fdc07adb99c615263916fa8Josh Gargus        if (!hasPendingChanges()) {
1130ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann            if (mLookupUri == null && saveMode == SaveMode.RELOAD) {
1131ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                // We don't have anything to save and there isn't even an existing contact yet.
1132ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                // Nothing to do, simply go back to editing mode
1133ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                mStatus = Status.EDITING;
1134ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann                return true;
1135ba69014263332f2056263cddc41cc6d7cfd7b7caDaniel Lehmann            }
113636d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            onSaveCompleted(false, saveMode, mLookupUri != null, mLookupUri);
11376cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov            return true;
11386cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov        }
11396cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
1140a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        setEnabled(false);
1141f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
11420353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Store account as default account, only if this is a new contact
11430353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        saveDefaultAccountIfNecessary();
11440353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
11450353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Save contact
1146ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus        Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
1147ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
1148ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
1149ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                mUpdatedPhotos);
1150ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus        mContext.startService(intent);
115187270e1b58e669354bb1571ced686421c56deb7aJosh Gargus
115287270e1b58e669354bb1571ced686421c56deb7aJosh Gargus        // Don't try to save the same photos twice.
115387270e1b58e669354bb1571ced686421c56deb7aJosh Gargus        mUpdatedPhotos = new Bundle();
115487270e1b58e669354bb1571ced686421c56deb7aJosh Gargus
1155f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
1156f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1157f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1158d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    public static class CancelEditDialogFragment extends DialogFragment {
1159d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1160d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public static void show(ContactEditorFragment fragment) {
1161d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment dialog = new CancelEditDialogFragment();
1162d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.setTargetFragment(fragment, 0);
1163d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.show(fragment.getFragmentManager(), "cancelEditor");
1164d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1165d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1166d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        @Override
1167d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1168d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            AlertDialog dialog = new AlertDialog.Builder(getActivity())
11694292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1170d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setMessage(R.string.cancel_confirmation_dialog_message)
11711ba8b6fea4c3f82ded19305874e72a326612aed1Katherine Kuan                    .setPositiveButton(android.R.string.ok,
1172d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1173d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            @Override
1174f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            public void onClick(DialogInterface dialogInterface, int whichButton) {
1175d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                                ((ContactEditorFragment)getTargetFragment()).doRevertAction();
1176d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            }
1177d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        }
1178d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    )
1179d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setNegativeButton(android.R.string.cancel, null)
1180d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .create();
1181d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            return dialog;
1182d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1183d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
1184d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1185d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private boolean revert() {
118644cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty() || !hasPendingChanges()) {
1187d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            doRevertAction();
1188d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        } else {
1189d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment.show(this);
1190d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1191d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        return true;
1192d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
1193d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1194d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private void doRevertAction() {
1195825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // When this Fragment is closed we don't want it to auto-save
1196825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.CLOSING;
119722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        if (mListener != null) mListener.onReverted();
1198f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1199f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
12009b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    public void doSaveAction() {
12019b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        save(SaveMode.CLOSE);
12029b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    }
12039b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
12042b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    public void onJoinCompleted(Uri uri) {
120536d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri);
12062b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    }
12072b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov
120836d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro    public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
120936d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            Uri contactLookupUri) {
1210a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (hadChanges) {
121136d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            if (saveSucceeded) {
1212a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                if (saveMode != SaveMode.JOIN) {
1213a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                    Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
1214a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                }
1215a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else {
1216a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
1217a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            }
1218a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        }
1219f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
122015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.CLOSE:
12219df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            case SaveMode.HOME:
1222f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
122336d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                if (saveSucceeded && contactLookupUri != null) {
1224b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                    final String requestAuthority =
1225b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                            mLookupUri == null ? null : mLookupUri.getAuthority();
1226f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1227f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final String legacyAuthority = "contacts";
1228f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1229f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = new Intent();
12305649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                    resultIntent.setAction(Intent.ACTION_VIEW);
1231f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (legacyAuthority.equals(requestAuthority)) {
1232f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Build legacy Uri when requested by caller
1233f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final long contactId = ContentUris.parseId(Contacts.lookupContact(
1234f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                mContext.getContentResolver(), contactLookupUri));
1235f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyContentUri = Uri.parse("content://contacts/people");
1236f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyUri = ContentUris.withAppendedId(
1237f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                legacyContentUri, contactId);
1238f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(legacyUri);
1239f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    } else {
1240f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Otherwise pass back a lookup-style Uri
1241f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(contactLookupUri);
1242f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
1243f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1244f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
1245f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
1246f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1247825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                // It is already saved, so prevent that it is saved again
1248825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                mStatus = Status.CLOSING;
12495649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                if (mListener != null) mListener.onSaveFinished(resultIntent);
1250f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1251a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
125215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.RELOAD:
1253dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov            case SaveMode.JOIN:
125436d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                if (saveSucceeded && contactLookupUri != null) {
1255623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    // If it was a JOIN, we are now ready to bring up the join activity.
1256e813f5e56ddc6395c5e08e9245e2c5ad41e91724Daniel Lehmann                    if (saveMode == SaveMode.JOIN && hasValidState()) {
1257623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                        showJoinAggregateActivity(contactLookupUri);
1258623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    }
1259623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann
126015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If this was in INSERT, we are changing into an EDIT now.
126115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If it already was an EDIT, we are changing to the new Uri now
126244cfc56d1701629070384364416c1311b780535dChiao Cheng                    mState = new RawContactDeltaList();
12631015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov                    load(Intent.ACTION_EDIT, contactLookupUri, null);
1264825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    mStatus = Status.LOADING;
126515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
126615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                }
126715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                break;
1268a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
126915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.SPLIT:
1270a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                mStatus = Status.CLOSING;
1271a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                if (mListener != null) {
12728c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov                    mListener.onContactSplit(contactLookupUri);
1273a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                } else {
1274a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
1275a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                }
1276f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1277f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1278f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1279f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1280f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1281f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
1282f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
1283f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
1284f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1285f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
128673a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov        if (contactLookupUri == null || !isAdded()) {
1287f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
1288f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1289f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
1291623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        mContactWritableForJoin = isContactWritable();
1292f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT);
1293f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin);
1294a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        startActivityForResult(intent, REQUEST_CODE_JOIN);
1295f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1296f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1297f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1298f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
1299f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1300f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
13012b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
1302623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                contactId, mContactWritableForJoin,
13032b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
13042b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        mContext.startService(intent);
1305f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1306f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1307f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1308ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     * Returns true if there is at least one writable raw contact in the current contact.
1309ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     */
1310ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    private boolean isContactWritable() {
1311a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1312ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        int size = mState.size();
1313ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        for (int i = 0; i < size; i++) {
1314851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDelta entity = mState.get(i);
1315851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = entity.getAccountType(accountTypes);
131696e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (type.areContactsWritable()) {
1317ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov                return true;
1318ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            }
1319ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        }
1320ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        return false;
1321ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    }
1322ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov
13232bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson    private boolean isEditingUserProfile() {
13242bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson        return mNewLocalProfile || mIsUserProfile;
13252bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson    }
13262bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson
1327cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public static interface Listener {
1328cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
132922fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was not found, so somehow close this fragment. This is raised after a contact
133022fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * is removed via Menu/Delete (unless it was a new contact)
1331cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
133222fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onContactNotFound();
1333f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1334f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
13358c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov         * Contact was split, so we can close now.
1336a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * @param newLookupUri The lookup uri of the new contact that should be shown to the user.
1337a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * The editor tries best to chose the most natural contact here.
1338f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
13398c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov        void onContactSplit(Uri newLookupUri);
1340f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1341f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1342f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User has tapped Revert, close the fragment now.
1343f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
134422fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onReverted();
1345f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1346f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
134722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was saved and the Fragment can now be closed safely.
1348f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
13495649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan        void onSaveFinished(Intent resultIntent);
1350b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann
1351b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        /**
1352e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * User switched to editing a different contact (a suggestion from the
1353e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * aggregation engine).
1354e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         */
1355e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov        void onEditOtherContactRequested(
1356e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov                Uri contactLookupUri, ArrayList<ContentValues> contentValues);
1357fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1358fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1359fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * Contact is being created for an external account that provides its own
1360fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * new contact activity.
1361fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
13622b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        void onCustomCreateContactActivityRequested(AccountWithDataSet account,
13632b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                Bundle intentExtras);
1364fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1365fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1366fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * The edited raw contact belongs to an external account that provides
1367fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * its own edit activity.
1368fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *
1369fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * @param redirect indicates that the current editor should be closed
1370fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *            before the custom editor is shown.
1371fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
13722b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        void onCustomEditContactActivityRequested(AccountWithDataSet account, Uri rawContactUri,
1373fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                Bundle intentExtras, boolean redirect);
1374f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1375f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1376851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private class EntityDeltaComparator implements Comparator<RawContactDelta> {
1377f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Compare EntityDeltas for sorting the stack of editors.
1379f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
13804a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        @Override
1381851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public int compare(RawContactDelta one, RawContactDelta two) {
1382f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check direct equality
1383f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (one.equals(two)) {
1384f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 0;
1385f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1386f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1387a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov            final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
13882b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String accountType1 = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
13892b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String dataSet1 = one.getValues().getAsString(RawContacts.DATA_SET);
13902b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type1 = accountTypes.getAccountType(accountType1, dataSet1);
13912b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String accountType2 = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
13922b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String dataSet2 = two.getValues().getAsString(RawContacts.DATA_SET);
13932b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type2 = accountTypes.getAccountType(accountType2, dataSet2);
1394f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1395f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check read-only
139696e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (!type1.areContactsWritable() && type2.areContactsWritable()) {
1397f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
139896e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            } else if (type1.areContactsWritable() && !type2.areContactsWritable()) {
1399f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1400f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1401f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1402f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account type
1403f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean skipAccountTypeCheck = false;
1404b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount1 = type1 instanceof GoogleAccountType;
1405b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount2 = type2 instanceof GoogleAccountType;
140669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (isGoogleAccount1 && !isGoogleAccount2) {
1407f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
140869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (!isGoogleAccount1 && isGoogleAccount2) {
1409f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
141069f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (isGoogleAccount1 && isGoogleAccount2){
1411f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                skipAccountTypeCheck = true;
1412f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1413f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1414f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            int value;
1415f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!skipAccountTypeCheck) {
1416b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                if (type1.accountType == null) {
14172776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                    return 1;
14182776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                }
1419b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                value = type1.accountType.compareTo(type2.accountType);
1420f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (value != 0) {
1421f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    return value;
14222b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                } else {
14232b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    // Fall back to data set.
14242b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    if (type1.dataSet != null) {
14252b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        value = type1.dataSet.compareTo(type2.dataSet);
14262b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        if (value != 0) {
14272b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                            return value;
14282b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        }
14292b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    } else if (type2.dataSet != null) {
14302b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        return 1;
14312b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    }
1432f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1433f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1434f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1435f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account name
1436851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            String oneAccount = one.getAccountName();
1437f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneAccount == null) oneAccount = "";
1438851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            String twoAccount = two.getAccountName();
1439f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (twoAccount == null) twoAccount = "";
1440f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            value = oneAccount.compareTo(twoAccount);
1441f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (value != 0) {
1442f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return value;
1443f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1444f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1445f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Both are in the same account, fall back to contact ID
1446851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            Long oneId = one.getRawContactId();
1447851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            Long twoId = two.getRawContactId();
1448f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneId == null) {
1449f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1450f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoId == null) {
1451f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1452f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1453f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1454f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return (int)(oneId - twoId);
1455f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1456f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1457f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1458f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1459f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
1460f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1461f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected long getContactId() {
146244cfc56d1701629070384364416c1311b780535dChiao Cheng        for (RawContactDelta rawContact : mState) {
146344cfc56d1701629070384364416c1311b780535dChiao Cheng            Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
146444cfc56d1701629070384364416c1311b780535dChiao Cheng            if (contactId != null) {
146544cfc56d1701629070384364416c1311b780535dChiao Cheng                return contactId;
1466f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
1467f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1468f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return 0;
1469f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1470f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1471f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1472f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Triggers an asynchronous search for aggregation suggestions.
1473f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
14742828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki    private void acquireAggregationSuggestions(Context context,
14752828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki            RawContactEditorView rawContactEditor) {
14769302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        long rawContactId = rawContactEditor.getRawContactId();
14779302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (mAggregationSuggestionsRawContactId != rawContactId
14789302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                && mAggregationSuggestionView != null) {
14799302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
14809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView = null;
14819302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionEngine.reset();
14829302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
14839302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
14849302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionsRawContactId = rawContactId;
14859302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1486f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine == null) {
14872828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki            mAggregationSuggestionEngine = new AggregationSuggestionEngine(context);
1488f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.setListener(this);
1489f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.start();
1490f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1491f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1492916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        mAggregationSuggestionEngine.setContactId(getContactId());
1493916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
1494392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        LabeledEditorView nameEditor = rawContactEditor.getNameEditor();
1495f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mAggregationSuggestionEngine.onNameChange(nameEditor.getValues());
1496f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1497f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1498f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
1499f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onAggregationSuggestionChange() {
1500288532cddfccdc3793dd748d1c75750e2f46cb53Yorke Lee        Activity activity = getActivity();
1501288532cddfccdc3793dd748d1c75750e2f46cb53Yorke Lee        if ((activity != null && activity.isFinishing())
150244cfc56d1701629070384364416c1311b780535dChiao Cheng                || !isVisible() ||  mState.isEmpty() || mStatus != Status.EDITING) {
150302cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov            return;
150402cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov        }
150502cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov
150686625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng        UiClosables.closeQuietly(mAggregationSuggestionPopup);
1507f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
15086c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) {
1509f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
1510f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1511f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
15126c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final RawContactEditorView rawContactView =
15136c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
151402a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        if (rawContactView == null) {
151502a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki            return; // Raw contact deleted?
151602a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        }
15176c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final View anchorView = rawContactView.findViewById(R.id.anchor_view);
15186c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup = new ListPopupWindow(mContext, null);
15196c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAnchorView(anchorView);
15206c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setWidth(anchorView.getWidth());
15216c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
15226c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAdapter(
15236c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                new AggregationSuggestionAdapter(getActivity(),
15246c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        mState.size() == 1 && mState.get(0).isContactInsert(),
15256c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        this, mAggregationSuggestionEngine.getSuggestions()));
15266c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setOnItemClickListener(mAggregationSuggestionItemClickListener);
15276c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.show();
1528bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1529bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1530bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1531bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
1532bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        long rawContactIds[] = new long[rawContactIdList.size()];
1533bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        for (int i = 0; i < rawContactIds.length; i++) {
1534bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            rawContactIds[i] = rawContactIdList.get(i);
1535bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1536bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        JoinSuggestedContactDialogFragment dialog =
1537bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new JoinSuggestedContactDialogFragment();
1538bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1539bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putLongArray("rawContactIds", rawContactIds);
1540bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1541bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
154274f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        try {
154374f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            dialog.show(getFragmentManager(), "join");
154474f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        } catch (Exception ex) {
154574f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            // No problem - the activity is no longer available to display the dialog
154674f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        }
1547bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1548bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1549bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
1550bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1551bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1552bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1553bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
15544292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1555bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
1556bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1557bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1558f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            @Override
1559bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1560bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1561bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1562bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                long rawContactIds[] =
1563bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getLongArray("rawContactIds");
1564bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doJoinSuggestedContact(rawContactIds);
1565bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1566bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1567bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1568bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1569bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1570bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1571bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1572bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1573bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1574bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Joins the suggested contact (specified by the id's of constituent raw
1575bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * contacts), save all changes, and stay in the editor.
1576bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1577bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doJoinSuggestedContact(long[] rawContactIds) {
1578cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1579cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov            return;
1580cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        }
1581cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov
1582bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mState.setJoinWithRawContacts(rawContactIds);
15839df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.RELOAD);
1584bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1585bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1586bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1587bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onEditAction(Uri contactLookupUri) {
1588bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        SuggestionEditConfirmationDialogFragment dialog =
1589bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new SuggestionEditConfirmationDialogFragment();
1590bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1591bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putParcelable("contactUri", contactLookupUri);
1592bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1593bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
1594bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.show(getFragmentManager(), "edit");
1595bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1596bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1597bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
1598bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1599bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1600bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1601bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
16024292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1603bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
1604bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1605bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1606f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            @Override
1607bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1608bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1609bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1610bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                Uri contactUri =
1611bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getParcelable("contactUri");
1612bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doEditSuggestedContact(contactUri);
1613bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1614bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1615bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1616bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1617bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1618bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1619bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1620bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1621bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1622bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Abandons the currently edited contact and switches to editing the suggested
1623bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * one, transferring all the data there
1624bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1625bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doEditSuggestedContact(Uri contactUri) {
1626bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        if (mListener != null) {
1627a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            // make sure we don't save this contact when closing down
1628a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            mStatus = Status.CLOSING;
1629bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            mListener.onEditOtherContactRequested(
1630bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    contactUri, mState.get(0).getContentValues());
1631bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1632bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1633bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1634a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    public void setAggregationSuggestionViewEnabled(boolean enabled) {
1635a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (mAggregationSuggestionView == null) {
1636a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            return;
1637a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1638a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1639a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
1640a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov                R.id.aggregation_suggestions);
1641a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        int count = itemList.getChildCount();
1642a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        for (int i = 0; i < count; i++) {
1643a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            itemList.getChildAt(i).setEnabled(enabled);
1644a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1645a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    }
1646a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1647f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
1648f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
1649b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        outState.putParcelable(KEY_URI, mLookupUri);
1650d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putString(KEY_ACTION, mAction);
1651d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
1652f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (hasValidState()) {
1653f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Store entities with modifications
1654f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putParcelable(KEY_EDIT_STATE, mState);
1655f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
16564bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
1657f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
1658637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        outState.putParcelable(KEY_CURRENT_PHOTO_URI, mCurrentPhotoUri);
1659f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
1660623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
16619302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId);
166202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        outState.putBoolean(KEY_ENABLED, mEnabled);
1663ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        outState.putBoolean(KEY_NEW_LOCAL_PROFILE, mNewLocalProfile);
1664ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
1665ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov        outState.putInt(KEY_STATUS, mStatus);
166628eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
166744cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_HAS_NEW_CONTACT, mHasNewContact);
166844cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_IS_EDIT, mIsEdit);
166944cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_NEW_CONTACT_READY, mNewContactDataReady);
167044cfc56d1701629070384364416c1311b780535dChiao Cheng        outState.putBoolean(KEY_EXISTING_CONTACT_READY, mExistingContactDataReady);
167113d52b10fd720bb94ffe7a7e7ad1b37c1e06bb50Yorke Lee        outState.putParcelableArrayList(KEY_RAW_CONTACTS,
167213d52b10fd720bb94ffe7a7e7ad1b37c1e06bb50Yorke Lee                mRawContacts == null ?
167313d52b10fd720bb94ffe7a7e7ad1b37c1e06bb50Yorke Lee                Lists.<RawContact> newArrayList() :  Lists.newArrayList(mRawContacts));
167428eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
1675f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
1676f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1677f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1678d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
1679f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
1680f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (mStatus == Status.SUB_ACTIVITY) {
1681f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.EDITING;
1682f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        }
1683f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
16846fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        // See if the photo selection handler handles this result.
168591004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        if (mCurrentPhotoHandler != null && mCurrentPhotoHandler.handlePhotoActivityResult(
16866fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                requestCode, resultCode, data)) {
16876fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            return;
16886fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        }
1689f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
16906fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        switch (requestCode) {
1691a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_JOIN: {
16920353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // Ignore failed requests
16930353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (resultCode != Activity.RESULT_OK) return;
1694f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
1695f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
1696f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
1697f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
16984a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                break;
1699f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
17000353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            case REQUEST_CODE_ACCOUNTS_CHANGED: {
17010353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // Bail if the account selector was not successful.
17020353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (resultCode != Activity.RESULT_OK) {
17030353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    mListener.onReverted();
17040353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    return;
17050353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                }
17060353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // If there's an account specified, use it.
17070353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (data != null) {
17080353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    AccountWithDataSet account = data.getParcelableExtra(Intents.Insert.ACCOUNT);
17090353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    if (account != null) {
17100353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                        createContact(account);
17110353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                        return;
17120353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                    }
17130353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                }
17140353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // If there isn't an account specified, then this is likely a phone-local
17150353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // contact, so we should continue setting up the editor by automatically selecting
17160353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // the most appropriate account.
17170353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                createContact();
17180353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                break;
17190353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            }
1720f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1721cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
17229cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
1723c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    /**
1724c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
1725c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     */
1726637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee    private void setPhoto(long rawContact, Bitmap photo, Uri photoUri) {
1727bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
1728e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
1729e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus        if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) {
1730e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus            // This is unexpected.
1731e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus            Log.w(TAG, "Invalid bitmap passed to setPhoto()");
1732e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus        }
1733e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
17349302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestingEditor != null) {
17359302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            requestingEditor.setPhotoBitmap(photo);
17369302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        } else {
17379302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            Log.w(TAG, "The contact that requested the photo is no longer present.");
17389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1739e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
1740637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        mUpdatedPhotos.putParcelable(String.valueOf(rawContact), photoUri);
17419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
17429302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
17439302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    /**
17449302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     * Finds raw contact editor view for the given rawContactId.
17459302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     */
1746bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
1747c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        for (int i = 0; i < mContent.getChildCount(); i++) {
1748c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            final View childView = mContent.getChildAt(i);
174972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
175072af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
17519302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (editor.getRawContactId() == rawContactId) {
17529302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    return editor;
1753c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                }
1754c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1755c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        }
17569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return null;
1757c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    }
1758c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1759fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
1760fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     * Returns true if there is currently more than one photo on screen.
1761fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1762fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    private boolean hasMoreThanOnePhoto() {
1763fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int countWithPicture = 0;
176491004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        final int numEntities = mState.size();
176591004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        for (int i = 0; i < numEntities; i++) {
1766851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta entity = mState.get(i);
1767851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if (entity.isVisible()) {
176891004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                final ValuesDelta primary = entity.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
1769851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                if (primary != null && primary.getPhoto() != null) {
1770fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    countWithPicture++;
177191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                } else {
1772851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final long rawContactId = entity.getRawContactId();
1773637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                    final Uri uri = mUpdatedPhotos.getParcelable(String.valueOf(rawContactId));
1774637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                    if (uri != null) {
1775637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                        try {
1776637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                            mContext.getContentResolver().openInputStream(uri);
177791004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                            countWithPicture++;
1778637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                        } catch (FileNotFoundException e) {
177991004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                        }
178091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                    }
178191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                }
178291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu
178391004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                if (countWithPicture > 1) {
178491004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                    return true;
1785fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
1786fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1787fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1788fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        return false;
17899cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1790222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1791222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    /**
1792222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     * The listener for the data loader
1793222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     */
1794851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private final LoaderManager.LoaderCallbacks<Contact> mDataLoaderListener =
1795851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            new LoaderCallbacks<Contact>() {
1796222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1797851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public Loader<Contact> onCreateLoader(int id, Bundle args) {
1798222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            mLoaderStartTime = SystemClock.elapsedRealtime();
179945ee872fe7be69c6b3f0c59167eecd11af467812Makoto Onuki            return new ContactLoader(mContext, mLookupUri, true);
1800222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1801222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1802222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1803851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoadFinished(Loader<Contact> loader, Contact data) {
1804222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long loaderCurrentTime = SystemClock.elapsedRealtime();
1805222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
18062621c5bb7049401c8bce740005fa60bf1b304b86Makoto Onuki            if (!data.isLoaded()) {
1807222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                // Item has been deleted
1808222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                Log.i(TAG, "No contact found. Closing activity");
180922fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann                if (mListener != null) mListener.onContactNotFound();
1810222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                return;
1811222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            }
1812222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1813825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            mStatus = Status.EDITING;
18146caccaeeed943db323be89853a108f422e670760Dmitri Plotnikov            mLookupUri = data.getLookupUri();
1815222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataStartTime = SystemClock.elapsedRealtime();
1816222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            setData(data);
1817222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataEndTime = SystemClock.elapsedRealtime();
1818c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1819222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
1820222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
18214ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
1822623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        @Override
1823851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        public void onLoaderReset(Loader<Contact> loader) {
18244ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1825222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    };
1826a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
1827e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    /**
1828be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan     * The listener for the group meta data loader for all groups.
1829e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov     */
1830e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
1831e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            new LoaderCallbacks<Cursor>() {
1832e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1833e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1834e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public CursorLoader onCreateLoader(int id, Bundle args) {
1835be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan            return new GroupMetaDataLoader(mContext, Groups.CONTENT_URI);
1836e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
1837e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1838e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1839e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1840e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            mGroupMetaData = data;
1841e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            bindGroupMetaData();
1842e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
18434ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
1844f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann        @Override
18454ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<Cursor> loader) {
18464ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1847e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    };
1848e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1849a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    @Override
1850a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    public void onSplitContactConfirmed() {
185144cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
1852b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // This may happen when this Fragment is recreated by the system during users
1853b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // confirming the split action (and thus this method is called just before onCreate()),
1854b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // for example.
1855b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            Log.e(TAG, "mState became null during the user's confirming split action. " +
1856b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa                    "Cannot perform the save action.");
1857b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            return;
1858b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa        }
1859b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa
1860a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        mState.markRawContactsForSplitting();
18619df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.SPLIT);
1862a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    }
1863a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
18646fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    /**
18656fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * Custom photo handler for the editor.  The inner listener that this creates also has a
18666fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * reference to the editor and acts as an {@link EditorListener}, and uses that editor to hold
18676fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * state information in several of the listener methods.
18686fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     */
18696fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private final class PhotoHandler extends PhotoSelectionHandler {
187028eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
187128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus        final long mRawContactId;
1872e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        private final BaseRawContactEditorView mEditor;
18734bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        private final PhotoActionListener mPhotoEditorListener;
187428eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
18756fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode,
1876851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactDeltaList state) {
18776fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            super(context, editor.getPhotoEditor(), photoMode, false, state);
1878e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            mEditor = editor;
187928eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            mRawContactId = editor.getRawContactId();
18809a409d474b2b4f2e4261657f864eeb866fcb8816Daniel Lehmann            mPhotoEditorListener = new PhotoEditorListener();
1881e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        }
1882e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus
1883e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        @Override
1884e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        public PhotoActionListener getListener() {
18859a409d474b2b4f2e4261657f864eeb866fcb8816Daniel Lehmann            return mPhotoEditorListener;
1886e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        }
1887e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus
1888e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        @Override
1889637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        public void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) {
18904bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
189191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu            mCurrentPhotoHandler = this;
1892e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            mStatus = Status.SUB_ACTIVITY;
1893637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            mCurrentPhotoUri = photoUri;
1894e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            ContactEditorFragment.this.startActivityForResult(intent, requestCode);
18959442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
18969442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
18976fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        private final class PhotoEditorListener extends PhotoSelectionHandler.PhotoActionListener
18986fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                implements EditorListener {
1899fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
19006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19016fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onRequest(int request) {
19026fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (!hasValidState()) return;
1903a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
19046fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (request == EditorListener.REQUEST_PICK_PHOTO) {
19056fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    onClick(mEditor.getPhotoEditor());
19069442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                }
19079442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
1908a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
19096fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onDeleteRequested(Editor removedEditor) {
19116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // The picture cannot be deleted, it can only be removed, which is handled by
19126fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // onRemovePictureChosen()
19136fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
1914a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
19156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            /**
19166fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             * User has chosen to set the selected photo as the (super) primary photo
19176fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             */
19186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19196fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onUseAsPrimaryChosen() {
19206fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Set the IsSuperPrimary for each editor
19216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                int count = mContent.getChildCount();
19226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                for (int i = 0; i < count; i++) {
19236fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    final View childView = mContent.getChildAt(i);
19246fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    if (childView instanceof BaseRawContactEditorView) {
19256fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        final BaseRawContactEditorView editor =
19266fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                                (BaseRawContactEditorView) childView;
19276fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        final PhotoEditorView photoEditor = editor.getPhotoEditor();
19286fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        photoEditor.setSuperPrimary(editor == mEditor);
19296fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    }
19306fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                }
193191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
19326fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19339442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
19346fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            /**
19356fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             * User has chosen to remove a picture
19366fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             */
19376fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19386fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onRemovePictureChosen() {
19396fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                mEditor.setPhotoBitmap(null);
194028eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
194128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                // Prevent bitmap from being restored if rotate the device.
194228eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                // (only if we first chose a new photo before removing it)
194328eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                mUpdatedPhotos.remove(String.valueOf(mRawContactId));
194491004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
19456fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19466fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
19476fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
1948637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            public void onPhotoSelected(Uri uri) throws FileNotFoundException {
1949637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(mContext, uri);
1950637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                setPhoto(mRawContactId, bitmap, uri);
195191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                mCurrentPhotoHandler = null;
195291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
19536fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19546fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
19556fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
1956637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            public Uri getCurrentPhotoUri() {
1957637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                return mCurrentPhotoUri;
19586fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
19596fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
19606fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
19616fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onPhotoSelectionDismissed() {
19626fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Nothing to do.
19639442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
19644a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        }
19654a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann    }
19662ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1967