ContactEditorFragment.java revision b9e60280603f2fa57083c13952e4b25e2585b833
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
1918ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.ContactLoader;
2018ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.ContactSaveService;
2118ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.GroupMetaDataLoader;
22cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.R;
232b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport com.android.contacts.activities.ContactEditorActivity;
24d21ddb2c96e71f43eaf7addc25e163181d1ca87dDmitri Plotnikovimport com.android.contacts.activities.JoinContactActivity;
2518ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
2618ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.Editor.EditorListener;
274597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport com.android.contacts.model.AccountType;
28a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikovimport com.android.contacts.model.AccountTypeManager;
292b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoroimport com.android.contacts.model.AccountWithDataSet;
30f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityDelta;
31f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityDelta.ValuesDelta;
32ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmannimport com.android.contacts.model.EntityDeltaList;
33f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityModifier;
3435769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmannimport com.android.contacts.model.GoogleAccountType;
35d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport com.android.contacts.util.AccountsListAdapter;
36f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
37f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account;
38cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity;
39bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.AlertDialog;
40bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.Dialog;
41bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.DialogFragment;
42222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.Fragment;
43222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager;
44222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
45cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ActivityNotFoundException;
46cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
47cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues;
48cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
49e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader;
50bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface;
51e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikovimport android.content.Entity;
52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
53cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader;
54f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor;
55f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
56f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.graphics.Rect;
57f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.media.MediaScannerConnection;
58cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
59cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
60f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.Environment;
619767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock;
62cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
63362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Event;
64362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Organization;
65cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
66362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
67f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
680a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoroimport android.provider.ContactsContract.DisplayPhoto;
69be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuanimport android.provider.ContactsContract.Groups;
702013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmannimport android.provider.ContactsContract.Intents;
71f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
72f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.MediaStore;
73cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log;
74cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater;
75cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu;
76cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater;
77cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem;
78cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View;
79cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup;
80d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.AdapterView;
816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.AdapterView.OnItemClickListener;
826c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.BaseAdapter;
8380d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
84d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.ListPopupWindow;
85cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
86cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
87f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File;
88f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.text.SimpleDateFormat;
89cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList;
90f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
91f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator;
92f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Date;
93f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
95a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmannpublic class ContactEditorFragment extends Fragment implements
96d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        SplitContactConfirmationDialogFragment.Listener,
97fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
98fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        ExternalRawContactEditorView.Listener {
99cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1002245870a1354df03512010e4968b144840894fb7Frank Sposaro    private static final String TAG = ContactEditorFragment.class.getSimpleName();
101cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int LOADER_DATA = 1;
103e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private static final int LOADER_GROUPS = 2;
104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
105d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_URI = "uri";
106d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_ACTION = "action";
107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_EDIT_STATE = "state";
108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
112623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann    private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
1139302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions";
11402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private static final String KEY_ENABLED = "enabled";
115ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov    private static final String KEY_STATUS = "status";
116ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private static final String KEY_NEW_LOCAL_PROFILE = "newLocalProfile";
117ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private static final String KEY_IS_USER_PROFILE = "isUserProfile";
118f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
119a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
120a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
12115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    /**
1227d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * An intent extra that forces the editor to add the edited contact
1237d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * to the default group (e.g. "My Contacts").
1247d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     */
1257d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
1267d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
127ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    public static final String INTENT_EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
128ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson
1297d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    /**
13015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     * Modes that specify what the AsyncTask has to perform after saving
13115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     */
132c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    // TODO: Move this into a common utils class or the save service because the contact and
133c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    // group editors need to use this interface definition
1349df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public interface SaveMode {
13515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
13615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Close the editor after saving
13715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
13815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int CLOSE = 0;
13915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
14015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
14115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Reload the data so that the user can continue editing
14215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int RELOAD = 1;
14415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
14515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
14615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Split the contact after saving
14715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int SPLIT = 2;
14915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
15015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
15115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Join another contact after saving
15215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
15315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int JOIN = 3;
1549df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov
1559df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        /**
1569df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         * Navigate to Contacts Home activity after saving.
1579df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         */
1589df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        public static final int HOME = 4;
15915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    }
160a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
161825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private interface Status {
162825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
163825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * The loader is fetching data
164825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
165825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int LOADING = 0;
166825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
167825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
168825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * Not currently busy. We are waiting for the user to enter data
169825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
170825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int EDITING = 1;
171825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
172825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
173f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * The data is currently being saved. This is used to prevent more
174f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * auto-saves (they shouldn't overlap)
175825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
176825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int SAVING = 2;
177825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
178825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
179a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * Prevents any more saves. This is used if in the following cases:
180a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After Save/Close
181a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After Revert
182a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After the user has accepted an edit suggestion
183825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
184825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int CLOSING = 3;
185f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
186f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        /**
187f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * Prevents saving while running a child activity.
188f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         */
189f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        public static final int SUB_ACTIVITY = 4;
190825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    }
191825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
192a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_JOIN = 0;
193a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1;
194a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 2;
195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
196c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private Bitmap mPhoto = null;
197f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mRawContactIdRequestingPhoto = -1;
198c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private long mRawContactIdRequestingPhotoAfterLoad = -1;
199cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final File PHOTO_DIR = new File(
203f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Environment.getExternalStorageDirectory() + "/DCIM/Camera");
204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
205e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private Cursor mGroupMetaData;
206e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
207f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private File mCurrentPhotoFile;
208cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2090a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    // Height/width (in pixels) to request for the photo - queried from the provider.
2100a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    private int mPhotoPickSize;
2110a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro
212cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Context mContext;
213f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mAction;
214b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann    private Uri mLookupUri;
215f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Bundle mIntentExtras;
216cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Listener mListener;
217cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
218f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mContactIdForJoin;
219623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann    private boolean mContactWritableForJoin;
220cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
221f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private LinearLayout mContent;
222ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    private EntityDeltaList mState;
223cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
224f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
225cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2269767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann    private long mLoaderStartTime;
2279767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann
228825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private int mStatus;
229825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
230f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private AggregationSuggestionEngine mAggregationSuggestionEngine;
2319302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private long mAggregationSuggestionsRawContactId;
2329302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private View mAggregationSuggestionView;
233f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
2346c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private ListPopupWindow mAggregationSuggestionPopup;
2356c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2366c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private static final class AggregationSuggestionAdapter extends BaseAdapter {
2376c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final Activity mActivity;
2386c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final boolean mSetNewContact;
2396c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final AggregationSuggestionView.Listener mListener;
2406c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final List<Suggestion> mSuggestions;
2416c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2426c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public AggregationSuggestionAdapter(Activity activity, boolean setNewContact,
2436c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) {
2446c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mActivity = activity;
2456c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSetNewContact = setNewContact;
2466c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mListener = listener;
2476c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSuggestions = suggestions;
2486c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2496c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2506c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2516c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public View getView(int position, View convertView, ViewGroup parent) {
2526c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            Suggestion suggestion = (Suggestion) getItem(position);
2536c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            LayoutInflater inflater = mActivity.getLayoutInflater();
2546c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            AggregationSuggestionView suggestionView =
2556c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                    (AggregationSuggestionView) inflater.inflate(
2566c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                            R.layout.aggregation_suggestions_item, null);
2576c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setNewContact(mSetNewContact);
2586c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setListener(mListener);
2596c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.bindSuggestion(suggestion);
2606c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return suggestionView;
2616c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2626c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2636c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2646c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public long getItemId(int position) {
2656c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return position;
2666c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2676c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2686c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2696c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public Object getItem(int position) {
2706c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.get(position);
2716c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2726c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2736c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2746c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public int getCount() {
2756c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.size();
2766c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2776c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    }
2786c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2796c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private OnItemClickListener mAggregationSuggestionItemClickListener =
2806c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            new OnItemClickListener() {
2816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
2826c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
2836c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view;
2846c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.handleItemClickEvent();
2856c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mAggregationSuggestionPopup.dismiss();
2866c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mAggregationSuggestionPopup = null;
2876c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
2886c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    };
2896c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
2907d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    private boolean mAutoAddToDefaultGroup;
2917d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
29202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private boolean mEnabled = true;
293eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov    private boolean mRequestFocus;
294ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private boolean mNewLocalProfile = false;
295ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson    private boolean mIsUserProfile = false;
29602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
297cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
298cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
299cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
30002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public void setEnabled(boolean enabled) {
30102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mEnabled != enabled) {
30202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = enabled;
30302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (mContent != null) {
30402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                int count = mContent.getChildCount();
30502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                for (int i = 0; i < count; i++) {
30602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                    mContent.getChildAt(i).setEnabled(enabled);
30702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                }
30802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
309a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            setAggregationSuggestionViewEnabled(enabled);
31002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            final Activity activity = getActivity();
31102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (activity != null) activity.invalidateOptionsMenu();
31202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
31302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
31402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
315cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
316cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public void onAttach(Activity activity) {
317cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        super.onAttach(activity);
318cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        mContext = activity;
3190a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        loadPhotoPickSize();
320cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
321cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
322cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
323f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onStop() {
324f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super.onStop();
325f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine != null) {
326f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.quit();
327f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
328248fba273e867616b1f8973dac6ce3e5ee1ba544Dmitri Plotnikov
329825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If anything was left unsaved, save it now but keep the editor open.
330f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
331623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            save(SaveMode.RELOAD);
332825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
333f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
334f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
335f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
336cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
337cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
338cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
339f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
340e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
3413648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
342cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
343825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If we are in an orientation change, we already have mState (it was loaded by onCreate)
344825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (mState != null) {
345825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            bindEditors();
346825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
347825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
348cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
349cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
350cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
351222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
352222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    public void onActivityCreated(Bundle savedInstanceState) {
353222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        super.onActivityCreated(savedInstanceState);
354222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
355825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Handle initial actions only when existing state missing
3564a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        final boolean hasIncomingState = savedInstanceState != null;
357825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
358825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (!hasIncomingState) {
359825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            if (Intent.ACTION_EDIT.equals(mAction)) {
360825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
361825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            } else if (Intent.ACTION_INSERT.equals(mAction)) {
3622013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                final Account account = mIntentExtras == null ? null :
3632b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        (Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT);
3642b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                final String dataSet = mIntentExtras == null ? null :
3652b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        mIntentExtras.getString(Intents.Insert.DATA_SET);
3662013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann
3672013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                if (account != null) {
3682013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // Account specified in Intent
3692b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    createContact(new AccountWithDataSet(account.name, account.type, dataSet));
3702013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                } else {
3712013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // No Account specified. Let the user choose
37240bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    // Load Accounts async so that we can present them
373d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    createContact();
3742013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                }
375a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else if (ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(mAction)) {
376a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                // do nothing
377825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            } else throw new IllegalArgumentException("Unknown Action String " + mAction +
378825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
379825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
380222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    }
381222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
382e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    @Override
383e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    public void onStart() {
384e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
385e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        super.onStart();
386e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
387e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
3881015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov    public void load(String action, Uri lookupUri, Bundle intentExtras) {
389f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mAction = action;
390b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        mLookupUri = lookupUri;
391f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mIntentExtras = intentExtras;
3927d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov        mAutoAddToDefaultGroup = mIntentExtras != null
3937d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                && mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
394ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        mNewLocalProfile = mIntentExtras != null
395ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            && mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
396f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
397f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
398f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void setListener(Listener value) {
399f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mListener = value;
400cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
401cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
402cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
403f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
404d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        if (savedState != null) {
405d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // Restore mUri before calling super.onCreate so that onInitializeLoaders
406d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // would already have a uri and an action to work with
407b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            mLookupUri = savedState.getParcelable(KEY_URI);
408d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mAction = savedState.getString(KEY_ACTION);
409d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        }
410d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
411f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
412f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
413f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (savedState == null) {
414f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // If savedState is non-null, onRestoreInstanceState() will restore the generator.
415f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = new ViewIdGenerator();
416f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
417825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            // Read state from savedState. No loading involved here
418ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
419f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mRawContactIdRequestingPhoto = savedState.getLong(
420f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
421f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
422f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE);
423f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (fileName != null) {
424f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                mCurrentPhotoFile = new File(fileName);
425cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
426f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
427623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
4289302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS);
42902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = savedState.getBoolean(KEY_ENABLED);
430ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov            mStatus = savedState.getInt(KEY_STATUS);
431ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            mNewLocalProfile = savedState.getBoolean(KEY_NEW_LOCAL_PROFILE);
432ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
433cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
434cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
435cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
436bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann    public void setData(ContactLoader.Result data) {
437d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        // If we have already loaded data, we do not want to change it here to not confuse the user
438d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        if (mState != null) {
439d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            Log.v(TAG, "Ignoring background change. This will have to be rebased later");
440d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            return;
441d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        }
442d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann
443fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        // See if this edit operation needs to be redirected to a custom editor
444fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        ArrayList<Entity> entities = data.getEntities();
445fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        if (entities.size() == 1) {
446fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            Entity entity = entities.get(0);
447fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            ContentValues entityValues = entity.getEntityValues();
448fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
4492b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
4502b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            AccountType accountType = AccountTypeManager.getInstance(mContext).getAccountType(
4512b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    type, dataSet);
452fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (accountType.getEditContactActivityClassName() != null) {
453fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                if (mListener != null) {
454fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    String name = entityValues.getAsString(RawContacts.ACCOUNT_NAME);
455fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
4562b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    mListener.onCustomEditContactActivityRequested(
4572b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                            new AccountWithDataSet(name, type, dataSet),
458fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
459fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            mIntentExtras, true);
460fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                }
461fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                return;
462fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
463fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
464fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
465fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        bindEditorsForExistingContact(data);
466fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
467fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
468fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    @Override
4692b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    public void onExternalEditorRequest(AccountWithDataSet account, Uri uri) {
470fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        mListener.onCustomEditContactActivityRequested(account, uri, null, false);
471fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
472fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
473fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    private void bindEditorsForExistingContact(ContactLoader.Result data) {
47402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        setEnabled(true);
47502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
476a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        mState = EntityDeltaList.fromIterator(data.getEntities().iterator());
4771ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        setIntentExtras(mIntentExtras);
4781ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        mIntentExtras = null;
479e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov
480ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // For user profile, change the contacts query URI
481ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        mIsUserProfile = data.isUserProfile();
482ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (mIsUserProfile) {
483ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            for (EntityDelta state : mState) {
484ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson                state.setProfileQueryUri();
485ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            }
486ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        }
487eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
488eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
4891ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        bindEditors();
4901ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    }
4911ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov
4921ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    /**
4931ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     * Merges extras from the intent.
4941ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     */
4951ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    public void setIntentExtras(Bundle extras) {
4961ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        if (extras == null || extras.size() == 0) {
4971ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            return;
498bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
499916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
500a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
5011ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        for (EntityDelta state : mState) {
5021ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
5032b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final String dataSet = state.getValues().getAsString(RawContacts.DATA_SET);
5042b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type = accountTypes.getAccountType(accountType, dataSet);
50569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (!type.readOnly) {
5061ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                // Apply extras to the first writable raw contact only
50769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                EntityModifier.parseExtras(mContext, type, state, extras);
5081ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                break;
5091ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            }
5101ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        }
511f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
512cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
513d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
514d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Shows the account creation screen. An account associated with the contact is automatically
515d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * selected. If there's no available account, device-local contact should be created.
516d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
517d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void createContact() {
5182b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final List<AccountWithDataSet> accounts =
519a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov                AccountTypeManager.getInstance(mContext).getAccounts(true);
520ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // No Accounts available or creating a local profile.  Create a phone-local contact.
521ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (accounts.isEmpty() || mNewLocalProfile) {
52240bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov            createContact(null);
523f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;  // Don't show a dialog.
524f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
525cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
526d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // We have an account switcher in "create-account" screen, so don't need to ask a user to
527d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // select an account here.
528d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        createContact(accounts.get(0));
529cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
530cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
531d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
532cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    /**
533d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Shows account creation screen associated with a given account.
534d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
535d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param account may be null to signal a device-local contact should be created.
536cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann     */
5372b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void createContact(AccountWithDataSet account) {
538a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
539b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        final AccountType accountType =
5402b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                accountTypes.getAccountType(account != null ? account.type : null,
5412b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        account != null ? account.dataSet : null);
542fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
543b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        if (accountType.getCreateContactActivityClassName() != null) {
544fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (mListener != null) {
545fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                mListener.onCustomCreateContactActivityRequested(account, mIntentExtras);
546fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
547fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        } else {
548b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            bindEditorsForNewContact(account, accountType);
549fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
550fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
551fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
552d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
553d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
554d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Some of old data are reused with new restriction enforced by the new account.
555d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
5562b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro     * @param oldState Old data being edited.
557d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param oldAccount Old account associated with oldState.
558d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param newAccount New account to be used.
559d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
560d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void rebindEditorsForNewContact(
5612b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            EntityDelta oldState, AccountWithDataSet oldAccount, AccountWithDataSet newAccount) {
562d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
5632b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        AccountType oldAccountType = accountTypes.getAccountType(
5642b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                oldAccount.type, oldAccount.dataSet);
5652b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        AccountType newAccountType = accountTypes.getAccountType(
5662b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                newAccount.type, newAccount.dataSet);
567d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
568d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccountType.getCreateContactActivityClassName() != null) {
569d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            Log.w(TAG, "external activity called in rebind situation");
570d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            if (mListener != null) {
571d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
572d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
573d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
574d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            mState = null;
575d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType);
576d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
577d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
578d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
5792b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void bindEditorsForNewContact(AccountWithDataSet account,
5802b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType accountType) {
581d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        bindEditorsForNewContact(account, accountType, null, null);
582d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
583d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
5842b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    private void bindEditorsForNewContact(AccountWithDataSet newAccount,
5852b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType newAccountType, EntityDelta oldState, AccountType oldAccountType) {
586a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        mStatus = Status.EDITING;
587a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
588f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ContentValues values = new ContentValues();
589d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccount != null) {
590d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            values.put(RawContacts.ACCOUNT_NAME, newAccount.name);
591d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            values.put(RawContacts.ACCOUNT_TYPE, newAccount.type);
5922b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            values.put(RawContacts.DATA_SET, newAccount.dataSet);
593f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
594f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_NAME);
595f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_TYPE);
5962b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            values.putNull(RawContacts.DATA_SET);
597cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
598cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
599f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
600d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (oldState == null) {
601d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            // Parse any values from incoming intent
602d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            EntityModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
603d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
604d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            EntityModifier.migrateStateForNewContact(mContext, oldState, insert,
605d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    oldAccountType, newAccountType);
606d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
607f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
60869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        // Ensure we have some default fields (if the account type does not support a field,
609362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmann        // ensureKind will not add it, so it is safe to add e.g. Event)
610d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
611d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
612d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
613d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
614d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, StructuredPostal.CONTENT_ITEM_TYPE);
615f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
616ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        // Set the correct URI for saving the contact as a profile
617ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        if (mNewLocalProfile) {
618ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson            insert.setProfileQueryUri();
619ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        }
620ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson
621f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mState == null) {
622f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Create state if none exists yet
623ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = EntityDeltaList.fromSingle(insert);
624f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
625f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add contact onto end of existing state
626f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mState.add(insert);
627cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
628f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
629eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
630eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
631f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
632cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
633cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
634f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void bindEditors() {
635f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
636f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
637cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
638f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
639f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
640cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
641f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
642f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
643a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
644a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        int numRawContacts = mState.size();
645a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        for (int i = 0; i < numRawContacts; i++) {
646f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
647f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final EntityDelta entity = mState.get(i);
648f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ValuesDelta values = entity.getValues();
649f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!values.isVisible()) continue;
650f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
651f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
6522b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final String dataSet = values.getAsString(RawContacts.DATA_SET);
6532b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type = accountTypes.getAccountType(accountType, dataSet);
654f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final long rawContactId = values.getAsLong(RawContacts._ID);
655f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
65672af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            final BaseRawContactEditorView editor;
65769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (type.isExternal()) {
658fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                editor = (BaseRawContactEditorView) inflater.inflate(
659fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                        R.layout.external_raw_contact_editor_view, mContent, false);
660fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                ((ExternalRawContactEditorView) editor).setListener(this);
661fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            } else {
662fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view,
663fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                        mContent, false);
664cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
665a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan            if (Intent.ACTION_INSERT.equals(mAction) && numRawContacts == 1) {
6662b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                final List<AccountWithDataSet> accounts =
667d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        AccountTypeManager.getInstance(mContext).getAccounts(true);
668ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson                if (accounts.size() > 1 && !mNewLocalProfile) {
669d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    addAccountSwitcher(mState.get(0), editor);
670a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan                } else {
671a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan                    disableAccountSwitcher(editor);
672d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                }
673d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
674a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan
67502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            editor.setEnabled(mEnabled);
676cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
677f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
6787d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
679681f36cc7cc49be781eedc4685eda2d1b2c0444cIsaac Katzenelson            editor.setState(entity, type, mViewIdGenerator, isEditingUserProfile());
680f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
6819442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            editor.getPhotoEditor().setEditorListener(
68269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                    new PhotoEditorListener(editor, type.readOnly));
68372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (editor instanceof RawContactEditorView) {
68472af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
6855ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                EditorListener listener = new EditorListener() {
686f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
687f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
688f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    public void onRequest(int request) {
6892bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson                        if (request == EditorListener.FIELD_CHANGED && !isEditingUserProfile()) {
69011bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                            acquireAggregationSuggestions(rawContactEditor);
69111bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                        }
692f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
693f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
694f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
6952293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                    public void onDeleteRequested(Editor removedEditor) {
696f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
6975ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                };
6985ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov
6995ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor();
7005ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                if (mRequestFocus) {
7015ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    nameEditor.requestFocus();
7025ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    mRequestFocus = false;
7035ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                }
7045ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                nameEditor.setEditorListener(listener);
705f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
7065ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView phoneticNameEditor =
7075ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                        rawContactEditor.getPhoneticNameEditor();
7085ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                phoneticNameEditor.setEditorListener(listener);
7097d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
7107d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
7119302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (rawContactId == mAggregationSuggestionsRawContactId) {
712f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    acquireAggregationSuggestions(rawContactEditor);
713f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
714f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
715cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
716f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
717eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = false;
718eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
719e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        bindGroupMetaData();
720e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
721f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
722f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
723a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
724a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        // Refresh Action Bar as the visibility of the join command
725825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Activity can be null if we have been detached from the Activity
726825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        final Activity activity = getActivity();
727825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (activity != null) activity.invalidateOptionsMenu();
728eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
729cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
730cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
731e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private void bindGroupMetaData() {
732e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        if (mGroupMetaData == null) {
733e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            return;
734e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
735e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
736e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        int editorCount = mContent.getChildCount();
737e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        for (int i = 0; i < editorCount; i++) {
73872af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i);
739e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            editor.setGroupMetaData(mGroupMetaData);
740e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
741e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
742e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
743d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void addAccountSwitcher(
744d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            final EntityDelta currentState, BaseRawContactEditorView editor) {
745d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        ValuesDelta values = currentState.getValues();
7462b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final AccountWithDataSet currentAccount = new AccountWithDataSet(
747d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                values.getAsString(RawContacts.ACCOUNT_NAME),
7482b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                values.getAsString(RawContacts.ACCOUNT_TYPE),
7492b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                values.getAsString(RawContacts.DATA_SET));
750d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final View accountView = editor.findViewById(R.id.account);
751fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan        final View anchorView = editor.findViewById(R.id.account_container);
752d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        accountView.setOnClickListener(new View.OnClickListener() {
753d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            @Override
754d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            public void onClick(View v) {
755d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                final ListPopupWindow popup = new ListPopupWindow(mContext, null);
756a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                final AccountsListAdapter adapter =
757a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                        new AccountsListAdapter(mContext, true, currentAccount);
758d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setWidth(anchorView.getWidth());
759d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAnchorView(anchorView);
760d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAdapter(adapter);
761d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setModal(true);
762d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
763d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
764d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    @Override
765d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    public void onItemClick(AdapterView<?> parent, View view, int position,
766d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            long id) {
767d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        popup.dismiss();
7682b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        AccountWithDataSet newAccount = adapter.getItem(position);
769d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        if (!newAccount.equals(currentAccount)) {
770d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            rebindEditorsForNewContact(currentState, currentAccount, newAccount);
771d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        }
772d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    }
773d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                });
774d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.show();
775d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
776d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        });
777d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
778d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
779a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan    private void disableAccountSwitcher(BaseRawContactEditorView editor) {
780a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        // Remove the pressed state from the account header because the user cannot switch accounts
781a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        // on an existing contact
782a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        final View accountView = editor.findViewById(R.id.account);
783a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        accountView.setBackgroundDrawable(null);
784a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        accountView.setEnabled(false);
785a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan    }
786a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan
787b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
788eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
789c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        inflater.inflate(R.menu.edit_contact, menu);
790cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
791cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
792b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
793eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onPrepareOptionsMenu(Menu menu) {
7949b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
7959b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // because the custom action bar contains the "save" button now (not the overflow menu).
7969b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
7979b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        menu.findItem(R.id.menu_done).setVisible(false);
7989b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
79903587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson        // Split only if more than one raw profile and not a user profile
80003587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson        menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1 &&
8012bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson                !isEditingUserProfile());
80203587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson        // Cannot join a user profile
8032bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson        menu.findItem(R.id.menu_join).setVisible(!isEditingUserProfile());
80403587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson
80503587ecd46c0a524f3cdc5ffd2959be2bc30bb34Isaac Katzenelson
80602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        int size = menu.size();
80702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        for (int i = 0; i < size; i++) {
80802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            menu.getItem(i).setEnabled(mEnabled);
80902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
810cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
811cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
812b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
813cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public boolean onOptionsItemSelected(MenuItem item) {
814cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (item.getItemId()) {
815f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_done:
8169df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                return save(SaveMode.CLOSE);
817f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_discard:
818d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                return revert();
819f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_split:
820f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSplitContactAction();
821f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_join:
822f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doJoinContactAction();
823f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
824f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
825f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
826cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
827f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSplitContactAction() {
828f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
829f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
830a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        final SplitContactConfirmationDialogFragment dialog =
8314a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                new SplitContactConfirmationDialogFragment();
8324a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.setTargetFragment(this, 0);
8334a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG);
834f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
835f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
836f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
837f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doJoinContactAction() {
8384c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        if (!hasValidState()) {
8394c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov            return false;
8404c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
8414c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
8424c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // If we just started creating a new contact and haven't added any data, it's too
8434c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // early to do a join
844a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
845a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (mState.size() == 1 && mState.get(0).isContactInsert()
846a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                && !EntityModifier.hasChanges(mState, accountTypes)) {
847a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact,
848a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                            Toast.LENGTH_LONG).show();
849a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            return true;
8504c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
8514c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
8529df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        return save(SaveMode.JOIN);
853f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
854f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
8550a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    private void loadPhotoPickSize() {
8560a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        Cursor c = mContext.getContentResolver().query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
8570a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro                new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
8580a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        try {
8590a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro            c.moveToFirst();
8600a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro            mPhotoPickSize = c.getInt(0);
8610a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        } finally {
8620a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro            c.close();
8630a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        }
8640a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    }
8650a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro
866f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
867f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap.
868f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
8690a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    public Intent getPhotoPickIntent() {
870f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
871f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setType("image/*");
872f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
873f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
874f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
8750a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputX", mPhotoPickSize);
8760a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputY", mPhotoPickSize);
877f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
878f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
879f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
880f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
881f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
882f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Check if our internal {@link #mState} is valid, usually checked before
883f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * performing user actions.
884f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
885f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean hasValidState() {
886f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return mState != null && mState.size() > 0;
887f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
888f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
889f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
890f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Create a file name for the icon photo using current time.
891f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
892f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String getPhotoFileName() {
893f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Date date = new Date(System.currentTimeMillis());
894f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
895f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return dateFormat.format(date) + ".jpg";
896f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
897f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
898f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
899f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for capturing a photo and storing it in a temporary file.
900f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
901f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getTakePickIntent(File f) {
902f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
903f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
904f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
905f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
906f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
907f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
908f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Sends a newly acquired photo to Gallery for cropping
909f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
910f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    protected void doCropPhoto(File f) {
911f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
912f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add the image to the media store
913f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            MediaScannerConnection.scanFile(
914f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mContext,
915f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { f.getAbsolutePath() },
916f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { null },
917f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    null);
918f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
919f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Launch gallery to crop the photo
920f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = getCropImageIntent(Uri.fromFile(f));
921f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.SUB_ACTIVITY;
922a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
923f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (Exception e) {
924f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Log.e(TAG, "Cannot crop image", e);
925f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
926cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
927cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
928cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
929f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
930f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for image cropping.
931f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
9320a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    public Intent getCropImageIntent(Uri photoUri) {
933f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent("com.android.camera.action.CROP");
934f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setDataAndType(photoUri, "image/*");
935f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
936f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
937f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
9380a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputX", mPhotoPickSize);
9390a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputY", mPhotoPickSize);
940f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
941f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
942f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
943f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
944f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
945f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Saves or creates the contact based on the mode, and if successful
946f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * finishes the activity.
947f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
9489df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public boolean save(int saveMode) {
949a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
950f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
951f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
952f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
9538c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        // If we are about to close the editor - there is no need to refresh the data
954a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
9559d2bcfb40d0ee107886eb99eba13a840e944ba43Dianne Hackborn            getLoaderManager().destroyLoader(LOADER_DATA);
9568c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        }
9578c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov
958825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.SAVING;
9596cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
960a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
961a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (!EntityModifier.hasChanges(mState, accountTypes)) {
962a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            onSaveCompleted(false, saveMode, mLookupUri);
9636cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov            return true;
9646cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov        }
9656cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
966a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        setEnabled(false);
967f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
968a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState,
9692bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
970ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson                getActivity().getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED);
971a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        getActivity().startService(intent);
972f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
973f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
974f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
975d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    public static class CancelEditDialogFragment extends DialogFragment {
976d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
977d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public static void show(ContactEditorFragment fragment) {
978d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment dialog = new CancelEditDialogFragment();
979d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.setTargetFragment(fragment, 0);
980d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.show(fragment.getFragmentManager(), "cancelEditor");
981d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
982d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
983d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        @Override
984d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
985d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            AlertDialog dialog = new AlertDialog.Builder(getActivity())
9864292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
987d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setTitle(R.string.cancel_confirmation_dialog_title)
988d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setMessage(R.string.cancel_confirmation_dialog_message)
9891ba8b6fea4c3f82ded19305874e72a326612aed1Katherine Kuan                    .setPositiveButton(android.R.string.ok,
990d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
991d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            @Override
992d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
993d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                                ((ContactEditorFragment)getTargetFragment()).doRevertAction();
994d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            }
995d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        }
996d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    )
997d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setNegativeButton(android.R.string.cancel, null)
998d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .create();
999d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            return dialog;
1000d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1001d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
1002d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1003d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private boolean revert() {
1004c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1005c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov        if (mState == null || !EntityModifier.hasChanges(mState, accountTypes)) {
1006d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            doRevertAction();
1007d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        } else {
1008d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment.show(this);
1009d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
1010d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        return true;
1011d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
1012d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
1013d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private void doRevertAction() {
1014825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // When this Fragment is closed we don't want it to auto-save
1015825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.CLOSING;
101622fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        if (mListener != null) mListener.onReverted();
1017f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1018f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
10199b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    public void doSaveAction() {
10209b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        save(SaveMode.CLOSE);
10219b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    }
10229b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
10232b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    public void onJoinCompleted(Uri uri) {
1024a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        onSaveCompleted(false, SaveMode.RELOAD, uri);
10252b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    }
10262b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov
1027a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public void onSaveCompleted(boolean hadChanges, int saveMode, Uri contactLookupUri) {
1028a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        boolean success = contactLookupUri != null;
1029a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        Log.d(TAG, "onSaveCompleted(" + saveMode + ", " + contactLookupUri);
1030a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (hadChanges) {
1031a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            if (success) {
1032a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                if (saveMode != SaveMode.JOIN) {
1033a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                    Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
1034a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                }
1035a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else {
1036a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
1037a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            }
1038a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        }
1039f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
104015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.CLOSE:
10419df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            case SaveMode.HOME:
1042f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
1043f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (success && contactLookupUri != null) {
1044b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                    final String requestAuthority =
1045b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                            mLookupUri == null ? null : mLookupUri.getAuthority();
1046f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1047f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final String legacyAuthority = "contacts";
1048f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1049f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = new Intent();
10505649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                    resultIntent.setAction(Intent.ACTION_VIEW);
1051f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (legacyAuthority.equals(requestAuthority)) {
1052f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Build legacy Uri when requested by caller
1053f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final long contactId = ContentUris.parseId(Contacts.lookupContact(
1054f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                mContext.getContentResolver(), contactLookupUri));
1055f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyContentUri = Uri.parse("content://contacts/people");
1056f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyUri = ContentUris.withAppendedId(
1057f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                legacyContentUri, contactId);
1058f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(legacyUri);
1059f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    } else {
1060f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Otherwise pass back a lookup-style Uri
1061f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(contactLookupUri);
1062f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
1063f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1064f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
1065f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
1066f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1067825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                // It is already saved, so prevent that it is saved again
1068825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                mStatus = Status.CLOSING;
10695649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                if (mListener != null) mListener.onSaveFinished(resultIntent);
1070f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1071a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
107215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.RELOAD:
1073dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov            case SaveMode.JOIN:
107415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                if (success && contactLookupUri != null) {
1075623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    // If it was a JOIN, we are now ready to bring up the join activity.
1076623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    if (saveMode == SaveMode.JOIN) {
1077623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                        showJoinAggregateActivity(contactLookupUri);
1078623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    }
1079623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann
108015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If this was in INSERT, we are changing into an EDIT now.
108115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If it already was an EDIT, we are changing to the new Uri now
108215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    mState = null;
10831015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov                    load(Intent.ACTION_EDIT, contactLookupUri, null);
1084825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    mStatus = Status.LOADING;
108515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
108615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                }
108715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                break;
1088a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
108915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.SPLIT:
1090a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                mStatus = Status.CLOSING;
1091a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                if (mListener != null) {
10928c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov                    mListener.onContactSplit(contactLookupUri);
1093a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                } else {
1094a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
1095a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                }
1096f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1097f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1098f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1099f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1100f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1101f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
1102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
1103f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
1104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1105f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
110673a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov        if (contactLookupUri == null || !isAdded()) {
1107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
1108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
1111623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        mContactWritableForJoin = isContactWritable();
1112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT);
1113f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin);
1114a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        startActivityForResult(intent, REQUEST_CODE_JOIN);
1115f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1116f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1117f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1118f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
1119f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1120f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
11212b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
1122623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                contactId, mContactWritableForJoin,
11232b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
11242b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        mContext.startService(intent);
1125f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1126f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1127f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1128ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     * Returns true if there is at least one writable raw contact in the current contact.
1129ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     */
1130ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    private boolean isContactWritable() {
1131a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1132ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        int size = mState.size();
1133ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        for (int i = 0; i < size; i++) {
1134ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            ValuesDelta values = mState.get(i).getValues();
1135ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
11362b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final String dataSet = values.getAsString(RawContacts.DATA_SET);
11372b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type = accountTypes.getAccountType(accountType, dataSet);
113869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (!type.readOnly) {
1139ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov                return true;
1140ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            }
1141ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        }
1142ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        return false;
1143ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    }
1144ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov
11452bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson    private boolean isEditingUserProfile() {
11462bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson        return mNewLocalProfile || mIsUserProfile;
11472bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson    }
11482bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson
1149cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public static interface Listener {
1150cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
115122fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was not found, so somehow close this fragment. This is raised after a contact
115222fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * is removed via Menu/Delete (unless it was a new contact)
1153cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
115422fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onContactNotFound();
1155f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1156f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
11578c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov         * Contact was split, so we can close now.
1158a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * @param newLookupUri The lookup uri of the new contact that should be shown to the user.
1159a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * The editor tries best to chose the most natural contact here.
1160f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
11618c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov        void onContactSplit(Uri newLookupUri);
1162f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1163f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1164f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User has tapped Revert, close the fragment now.
1165f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
116622fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onReverted();
1167f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1168f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
116922fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was saved and the Fragment can now be closed safely.
1170f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
11715649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan        void onSaveFinished(Intent resultIntent);
1172b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann
1173b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        /**
1174e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * User switched to editing a different contact (a suggestion from the
1175e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * aggregation engine).
1176e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         */
1177e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov        void onEditOtherContactRequested(
1178e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov                Uri contactLookupUri, ArrayList<ContentValues> contentValues);
1179fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1180fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1181fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * Contact is being created for an external account that provides its own
1182fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * new contact activity.
1183fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
11842b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        void onCustomCreateContactActivityRequested(AccountWithDataSet account,
11852b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                Bundle intentExtras);
1186fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1187fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1188fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * The edited raw contact belongs to an external account that provides
1189fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * its own edit activity.
1190fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *
1191fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * @param redirect indicates that the current editor should be closed
1192fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *            before the custom editor is shown.
1193fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
11942b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        void onCustomEditContactActivityRequested(AccountWithDataSet account, Uri rawContactUri,
1195fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                Bundle intentExtras, boolean redirect);
1196f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1197f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1198f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private class EntityDeltaComparator implements Comparator<EntityDelta> {
1199f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Compare EntityDeltas for sorting the stack of editors.
1201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
12024a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        @Override
1203f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public int compare(EntityDelta one, EntityDelta two) {
1204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check direct equality
1205f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (one.equals(two)) {
1206f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 0;
1207f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1208f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1209a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov            final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
12102b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String accountType1 = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
12112b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String dataSet1 = one.getValues().getAsString(RawContacts.DATA_SET);
12122b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type1 = accountTypes.getAccountType(accountType1, dataSet1);
12132b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String accountType2 = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
12142b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            String dataSet2 = two.getValues().getAsString(RawContacts.DATA_SET);
12152b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro            final AccountType type2 = accountTypes.getAccountType(accountType2, dataSet2);
1216f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1217f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check read-only
1218b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            if (type1.readOnly && !type2.readOnly) {
1219f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1220b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            } else if (!type1.readOnly && type2.readOnly) {
1221f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1222f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1223f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1224f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account type
1225f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean skipAccountTypeCheck = false;
1226b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount1 = type1 instanceof GoogleAccountType;
1227b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount2 = type2 instanceof GoogleAccountType;
122869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (isGoogleAccount1 && !isGoogleAccount2) {
1229f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
123069f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (!isGoogleAccount1 && isGoogleAccount2) {
1231f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
123269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (isGoogleAccount1 && isGoogleAccount2){
1233f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                skipAccountTypeCheck = true;
1234f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1235f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1236f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            int value;
1237f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!skipAccountTypeCheck) {
1238b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                if (type1.accountType == null) {
12392776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                    return 1;
12402776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                }
1241b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                value = type1.accountType.compareTo(type2.accountType);
1242f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (value != 0) {
1243f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    return value;
12442b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                } else {
12452b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    // Fall back to data set.
12462b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    if (type1.dataSet != null) {
12472b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        value = type1.dataSet.compareTo(type2.dataSet);
12482b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        if (value != 0) {
12492b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                            return value;
12502b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        }
12512b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    } else if (type2.dataSet != null) {
12522b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        return 1;
12532b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                    }
1254f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1255f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1256f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1257f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account name
1258f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta oneValues = one.getValues();
1259f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME);
1260f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneAccount == null) oneAccount = "";
1261f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta twoValues = two.getValues();
1262f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME);
1263f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (twoAccount == null) twoAccount = "";
1264f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            value = oneAccount.compareTo(twoAccount);
1265f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (value != 0) {
1266f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return value;
1267f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1268f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1269f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Both are in the same account, fall back to contact ID
1270f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long oneId = oneValues.getAsLong(RawContacts._ID);
1271f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long twoId = twoValues.getAsLong(RawContacts._ID);
1272f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneId == null) {
1273f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1274f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoId == null) {
1275f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1276f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1277f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1278f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return (int)(oneId - twoId);
1279f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1280f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1281f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1282f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1283f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
1284f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1285f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected long getContactId() {
1286c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov        if (mState != null) {
1287c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov            for (EntityDelta rawContact : mState) {
1288c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
1289c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                if (contactId != null) {
1290c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                    return contactId;
1291c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                }
1292f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
1293f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1294f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return 0;
1295f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1296f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1297f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1298f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Triggers an asynchronous search for aggregation suggestions.
1299f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
130072af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann    public void acquireAggregationSuggestions(RawContactEditorView rawContactEditor) {
13019302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        long rawContactId = rawContactEditor.getRawContactId();
13029302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (mAggregationSuggestionsRawContactId != rawContactId
13039302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                && mAggregationSuggestionView != null) {
13049302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
13059302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView = null;
13069302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionEngine.reset();
13079302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
13089302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
13099302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionsRawContactId = rawContactId;
13109302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1311f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine == null) {
1312f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine = new AggregationSuggestionEngine(getActivity());
1313f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.setListener(this);
1314f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.start();
1315f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1316f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1317916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        mAggregationSuggestionEngine.setContactId(getContactId());
1318916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
1319392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        LabeledEditorView nameEditor = rawContactEditor.getNameEditor();
1320f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mAggregationSuggestionEngine.onNameChange(nameEditor.getValues());
1321f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1322f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1323f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
1324f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onAggregationSuggestionChange() {
1325a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!isAdded() || mState == null || mStatus != Status.EDITING) {
132602cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov            return;
132702cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov        }
132802cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov
13296c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        if (mAggregationSuggestionPopup != null && mAggregationSuggestionPopup.isShowing()) {
13306c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mAggregationSuggestionPopup.dismiss();
13319302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1332f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
13336c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) {
1334f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
1335f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1336f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
13376c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final RawContactEditorView rawContactView =
13386c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
133902a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        if (rawContactView == null) {
134002a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki            return; // Raw contact deleted?
134102a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        }
13426c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final View anchorView = rawContactView.findViewById(R.id.anchor_view);
13436c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup = new ListPopupWindow(mContext, null);
13446c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAnchorView(anchorView);
13456c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setWidth(anchorView.getWidth());
13466c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
13476c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setModal(true);
13486c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAdapter(
13496c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                new AggregationSuggestionAdapter(getActivity(),
13506c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        mState.size() == 1 && mState.get(0).isContactInsert(),
13516c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        this, mAggregationSuggestionEngine.getSuggestions()));
13526c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setOnItemClickListener(mAggregationSuggestionItemClickListener);
13536c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.show();
1354bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1355bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1356bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1357bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
1358bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        long rawContactIds[] = new long[rawContactIdList.size()];
1359bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        for (int i = 0; i < rawContactIds.length; i++) {
1360bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            rawContactIds[i] = rawContactIdList.get(i);
1361bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1362bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        JoinSuggestedContactDialogFragment dialog =
1363bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new JoinSuggestedContactDialogFragment();
1364bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1365bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putLongArray("rawContactIds", rawContactIds);
1366bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1367bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
136874f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        try {
136974f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            dialog.show(getFragmentManager(), "join");
137074f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        } catch (Exception ex) {
137174f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            // No problem - the activity is no longer available to display the dialog
137274f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        }
1373bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1374bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1375bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
1376bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1377bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1378bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1379bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
13804292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1381bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setTitle(R.string.aggregation_suggestion_join_dialog_title)
1382bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
1383bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1384bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1385bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1386bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1387bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1388bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                long rawContactIds[] =
1389bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getLongArray("rawContactIds");
1390bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doJoinSuggestedContact(rawContactIds);
1391bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1392bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1393bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1394bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1395bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1396bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1397bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1398bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1399bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1400bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Joins the suggested contact (specified by the id's of constituent raw
1401bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * contacts), save all changes, and stay in the editor.
1402bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1403bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doJoinSuggestedContact(long[] rawContactIds) {
1404cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1405cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov            return;
1406cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        }
1407cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov
1408bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mState.setJoinWithRawContacts(rawContactIds);
14099df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.RELOAD);
1410bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1411bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1412bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1413bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onEditAction(Uri contactLookupUri) {
1414bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        SuggestionEditConfirmationDialogFragment dialog =
1415bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new SuggestionEditConfirmationDialogFragment();
1416bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1417bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putParcelable("contactUri", contactLookupUri);
1418bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1419bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
1420bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.show(getFragmentManager(), "edit");
1421bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1422bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1423bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
1424bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1425bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1426bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1427bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
14284292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1429bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setTitle(R.string.aggregation_suggestion_edit_dialog_title)
1430bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
1431bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1432bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1433bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1434bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1435bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1436bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                Uri contactUri =
1437bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getParcelable("contactUri");
1438bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doEditSuggestedContact(contactUri);
1439bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1440bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1441bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1442bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1443bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1444bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1445bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1446bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1447bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1448bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Abandons the currently edited contact and switches to editing the suggested
1449bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * one, transferring all the data there
1450bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1451bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doEditSuggestedContact(Uri contactUri) {
1452bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        if (mListener != null) {
1453a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            // make sure we don't save this contact when closing down
1454a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            mStatus = Status.CLOSING;
1455bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            mListener.onEditOtherContactRequested(
1456bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    contactUri, mState.get(0).getContentValues());
1457bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1458bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1459bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1460a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    public void setAggregationSuggestionViewEnabled(boolean enabled) {
1461a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (mAggregationSuggestionView == null) {
1462a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            return;
1463a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1464a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1465a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
1466a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov                R.id.aggregation_suggestions);
1467a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        int count = itemList.getChildCount();
1468a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        for (int i = 0; i < count; i++) {
1469a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            itemList.getChildAt(i).setEnabled(enabled);
1470a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1471a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    }
1472a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1473f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1474f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Computes bounds of the supplied view relative to its ascendant.
1475f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1476f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private Rect getRelativeBounds(View ascendant, View view) {
1477f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Rect rect = new Rect();
1478f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
1479f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1480f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        View parent = (View) view.getParent();
1481f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        while (parent != ascendant) {
1482f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            rect.offset(parent.getLeft(), parent.getTop());
1483f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            parent = (View) parent.getParent();
1484f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1485f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return rect;
1486f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1487f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1488f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
1489f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
1490b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        outState.putParcelable(KEY_URI, mLookupUri);
1491d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putString(KEY_ACTION, mAction);
1492d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
1493f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (hasValidState()) {
1494f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Store entities with modifications
1495f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putParcelable(KEY_EDIT_STATE, mState);
1496f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1497f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1498f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
1499f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
1500f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mCurrentPhotoFile != null) {
1501f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
1502f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1503f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
1504623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
15059302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId);
150602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        outState.putBoolean(KEY_ENABLED, mEnabled);
1507ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        outState.putBoolean(KEY_NEW_LOCAL_PROFILE, mNewLocalProfile);
1508ead19c5eafee0ffb43b02a4ae75ac5244ad3f853Isaac Katzenelson        outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
1509ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov        outState.putInt(KEY_STATUS, mStatus);
1510f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
1511f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1512f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1513d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
1514f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
1515f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (mStatus == Status.SUB_ACTIVITY) {
1516f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.EDITING;
1517f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        }
1518f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
1519f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Ignore failed requests
1520f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (resultCode != Activity.RESULT_OK) return;
1521f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (requestCode) {
1522a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: {
1523c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                // As we are coming back to this view, the editor will be reloaded automatically,
1524c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                // which will cause the photo that is set here to disappear. To prevent this,
15254a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                // we remember to set a flag which is interpreted after loading.
15264a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                // This photo is set here already to reduce flickering.
1527c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mPhoto = data.getParcelableExtra("data");
1528c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                setPhoto(mRawContactIdRequestingPhoto, mPhoto);
1529c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhotoAfterLoad = mRawContactIdRequestingPhoto;
1530c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhoto = -1;
1531f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1532f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1533f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1534a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_CAMERA_WITH_DATA: {
1535f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                doCropPhoto(mCurrentPhotoFile);
1536f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1537f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1538a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_JOIN: {
1539f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
1540f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
1541f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
1542f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
15434a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                break;
1544f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1545f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1546cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
15479cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
1548c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    /**
1549c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
1550c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     */
1551c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private void setPhoto(long rawContact, Bitmap photo) {
1552bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
15539302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestingEditor != null) {
15549302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            requestingEditor.setPhotoBitmap(photo);
15559302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        } else {
15569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            Log.w(TAG, "The contact that requested the photo is no longer present.");
15579302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
15589302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
15599302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
15609302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    /**
15619302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     * Finds raw contact editor view for the given rawContactId.
15629302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     */
1563bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
1564c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        for (int i = 0; i < mContent.getChildCount(); i++) {
1565c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            final View childView = mContent.getChildAt(i);
156672af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
156772af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
15689302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (editor.getRawContactId() == rawContactId) {
15699302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    return editor;
1570c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                }
1571c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1572c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        }
15739302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return null;
1574c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    }
1575c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1576fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
1577fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     * Returns true if there is currently more than one photo on screen.
1578fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1579fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    private boolean hasMoreThanOnePhoto() {
1580fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int count = mContent.getChildCount();
1581fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int countWithPicture = 0;
1582fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        for (int i = 0; i < count; i++) {
1583fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            final View childView = mContent.getChildAt(i);
1584fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
1585fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
1586fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                if (editor.hasSetPhoto()) {
1587fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    countWithPicture++;
1588fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    if (countWithPicture > 1) return true;
1589fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
1590fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1591fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1592fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
1593fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        return false;
15949cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1595222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1596222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    /**
1597222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     * The listener for the data loader
1598222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     */
1599222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener =
1600222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            new LoaderCallbacks<ContactLoader.Result>() {
1601222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1602222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
1603222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            mLoaderStartTime = SystemClock.elapsedRealtime();
1604b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            return new ContactLoader(mContext, mLookupUri);
1605222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1606222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1607222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1608222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
1609222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long loaderCurrentTime = SystemClock.elapsedRealtime();
1610222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
16119e7b5da669fcf92a6a627fb720749e5cb627684aMakoto Onuki            if (data == ContactLoader.Result.NOT_FOUND || data.isError()) {
1612222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                // Item has been deleted
1613222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                Log.i(TAG, "No contact found. Closing activity");
161422fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann                if (mListener != null) mListener.onContactNotFound();
1615222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                return;
1616222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            }
1617222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1618825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            mStatus = Status.EDITING;
16196caccaeeed943db323be89853a108f422e670760Dmitri Plotnikov            mLookupUri = data.getLookupUri();
1620222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataStartTime = SystemClock.elapsedRealtime();
1621222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            setData(data);
1622222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataEndTime = SystemClock.elapsedRealtime();
1623c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1624c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            // If we are coming back from the photo trimmer, this will be set.
1625c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            if (mRawContactIdRequestingPhotoAfterLoad != -1) {
1626c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                setPhoto(mRawContactIdRequestingPhotoAfterLoad, mPhoto);
1627c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhotoAfterLoad = -1;
1628c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mPhoto = null;
1629c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1630222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
1631222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
16324ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
1633623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        @Override
16344ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<ContactLoader.Result> loader) {
16354ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1636222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    };
1637a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
1638e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    /**
1639be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan     * The listener for the group meta data loader for all groups.
1640e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov     */
1641e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
1642e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            new LoaderCallbacks<Cursor>() {
1643e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1644e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1645e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public CursorLoader onCreateLoader(int id, Bundle args) {
1646be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan            return new GroupMetaDataLoader(mContext, Groups.CONTENT_URI);
1647e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
1648e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1649e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1650e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1651e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            mGroupMetaData = data;
1652e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            bindGroupMetaData();
1653e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
16544ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
16554ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<Cursor> loader) {
16564ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1657e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    };
1658e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1659a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    @Override
1660a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    public void onSplitContactConfirmed() {
1661b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa        if (mState == null) {
1662b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // This may happen when this Fragment is recreated by the system during users
1663b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // confirming the split action (and thus this method is called just before onCreate()),
1664b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // for example.
1665b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            Log.e(TAG, "mState became null during the user's confirming split action. " +
1666b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa                    "Cannot perform the save action.");
1667b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            return;
1668b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa        }
1669b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa
1670a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        mState.markRawContactsForSplitting();
16719df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.SPLIT);
1672a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    }
1673a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
16749442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann    private final class PhotoEditorListener
16759442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            implements EditorListener, PhotoActionPopup.Listener {
16769442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        private final BaseRawContactEditorView mEditor;
167769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        private final boolean mAccountReadOnly;
16789442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
167969f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        private PhotoEditorListener(BaseRawContactEditorView editor, boolean accountReadOnly) {
16809442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mEditor = editor;
168169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            mAccountReadOnly = accountReadOnly;
16829442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
16839442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16849442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16859442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onRequest(int request) {
16869442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            if (!hasValidState()) return;
16879442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16889442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            if (request == EditorListener.REQUEST_PICK_PHOTO) {
16899442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Determine mode
16909442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final int mode;
169169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                if (mAccountReadOnly) {
16929442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    if (mEditor.hasSetPhoto() && hasMoreThanOnePhoto()) {
16939442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        mode = PhotoActionPopup.MODE_READ_ONLY_ALLOW_PRIMARY;
16949442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    } else {
16959442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        // Read-only and either no photo or the only photo ==> no options
16969442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        return;
16979442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    }
16989442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                } else {
16999442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    if (mEditor.hasSetPhoto()) {
17009442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        if (hasMoreThanOnePhoto()) {
17019442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                            mode = PhotoActionPopup.MODE_PHOTO_ALLOW_PRIMARY;
17029442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        } else {
17039442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                            mode = PhotoActionPopup.MODE_PHOTO_DISALLOW_PRIMARY;
17049442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        }
17059442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    } else {
17069442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        mode = PhotoActionPopup.MODE_NO_PHOTO;
17079442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    }
1708fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
17099442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                PhotoActionPopup.createPopupMenu(mContext, mEditor.getPhotoEditor(), this, mode)
17109442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        .show();
1711fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1712fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1713fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
17149442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17152293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        public void onDeleteRequested(Editor removedEditor) {
17162293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            // The picture cannot be deleted, it can only be removed, which is handled by
17172293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            // onRemovePictureChosen()
17189442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
1719a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17209442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17219442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * User has chosen to set the selected photo as the (super) primary photo
17229442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17239442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17249442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onUseAsPrimaryChosen() {
17259442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            // Set the IsSuperPrimary for each editor
17269442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            int count = mContent.getChildCount();
17279442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            for (int i = 0; i < count; i++) {
17289442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final View childView = mContent.getChildAt(i);
17299442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                if (childView instanceof BaseRawContactEditorView) {
17309442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
17319442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    final PhotoEditorView photoEditor = editor.getPhotoEditor();
17329442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    photoEditor.setSuperPrimary(editor == mEditor);
17339442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                }
17349442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
1735a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        }
1736a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17379442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17389442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * User has chosen to remove a picture
17399442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17409442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17412293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        public void onRemovePictureChosen() {
17429442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mEditor.setPhotoBitmap(null);
1743a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        }
1744a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17459442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17469442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * Launches Camera to take a picture and store it in a file.
17479442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17489442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17499442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onTakePhotoChosen() {
17509442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
17519442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            try {
17529442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Launch camera to take photo for selected contact
17539442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                PHOTO_DIR.mkdirs();
17549442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
17559442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final Intent intent = getTakePickIntent(mCurrentPhotoFile);
17569442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
1757f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov                mStatus = Status.SUB_ACTIVITY;
17589442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                startActivityForResult(intent, REQUEST_CODE_CAMERA_WITH_DATA);
17599442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            } catch (ActivityNotFoundException e) {
17609442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                Toast.makeText(mContext, R.string.photoPickerNotFoundText,
17619442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        Toast.LENGTH_LONG).show();
17629442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
17639442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
1764a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17659442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17669442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * Launches Gallery to pick a photo.
17679442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17689442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17699442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onPickFromGalleryChosen() {
17709442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
17719442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            try {
17729442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Launch picker to choose photo for selected contact
17739442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final Intent intent = getPhotoPickIntent();
1774f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov                mStatus = Status.SUB_ACTIVITY;
17759442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
17769442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            } catch (ActivityNotFoundException e) {
17779442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                Toast.makeText(mContext, R.string.photoPickerNotFoundText,
17789442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        Toast.LENGTH_LONG).show();
17799442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
17804a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        }
17814a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann    }
17822ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1783