ContactEditorFragment.java revision d8f3da6a4ea4054bd47959db85657a7e01d28358
13f990ba4e35a99078d831c041290e574a320caa5Walter Jang/*
23f990ba4e35a99078d831c041290e574a320caa5Walter Jang * Copyright (C) 2015 The Android Open Source Project
33f990ba4e35a99078d831c041290e574a320caa5Walter Jang *
43f990ba4e35a99078d831c041290e574a320caa5Walter Jang * Licensed under the Apache License, Version 2.0 (the "License");
53f990ba4e35a99078d831c041290e574a320caa5Walter Jang * you may not use this file except in compliance with the License.
63f990ba4e35a99078d831c041290e574a320caa5Walter Jang * You may obtain a copy of the License at
73f990ba4e35a99078d831c041290e574a320caa5Walter Jang *
83f990ba4e35a99078d831c041290e574a320caa5Walter Jang *      http://www.apache.org/licenses/LICENSE-2.0
93f990ba4e35a99078d831c041290e574a320caa5Walter Jang *
103f990ba4e35a99078d831c041290e574a320caa5Walter Jang * Unless required by applicable law or agreed to in writing, software
113f990ba4e35a99078d831c041290e574a320caa5Walter Jang * distributed under the License is distributed on an "AS IS" BASIS,
123f990ba4e35a99078d831c041290e574a320caa5Walter Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133f990ba4e35a99078d831c041290e574a320caa5Walter Jang * See the License for the specific language governing permissions and
143f990ba4e35a99078d831c041290e574a320caa5Walter Jang * limitations under the License
153f990ba4e35a99078d831c041290e574a320caa5Walter Jang */
163f990ba4e35a99078d831c041290e574a320caa5Walter Jang
173f990ba4e35a99078d831c041290e574a320caa5Walter Jangpackage com.android.contacts.editor;
183f990ba4e35a99078d831c041290e574a320caa5Walter Jang
197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.accounts.Account;
2049ed2033f83005f92c30068ae33c3138d75e1825Walter Jangimport android.app.Activity;
217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.app.Fragment;
227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.app.LoaderManager;
23e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskeyimport android.content.ContentResolver;
247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.content.ContentUris;
257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.content.ContentValues;
267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.content.Context;
277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.content.CursorLoader;
283f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport android.content.Intent;
297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.content.Loader;
307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.database.Cursor;
313efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jangimport android.graphics.Bitmap;
323efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jangimport android.net.Uri;
333f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport android.os.Bundle;
347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.os.SystemClock;
357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract;
367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.CommonDataKinds.Email;
377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.CommonDataKinds.Event;
387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.CommonDataKinds.Organization;
397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.CommonDataKinds.Phone;
407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.Intents;
437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.provider.ContactsContract.RawContacts;
44e394595987e288807b8c02c78d7d33e854f152b1Walter Jangimport android.text.TextUtils;
45cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jangimport android.util.Log;
463f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport android.view.LayoutInflater;
477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.view.Menu;
487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.view.MenuInflater;
49c90cc15b804fb00339a3b98e5c951549f9b03599Walter Jangimport android.view.MenuItem;
503f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport android.view.View;
513f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport android.view.ViewGroup;
527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.widget.AdapterView;
537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.widget.BaseAdapter;
543f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport android.widget.LinearLayout;
557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport android.widget.ListPopupWindow;
5679658e14360a4ec75530a9dcae338f48c9d5f043Walter Jangimport android.widget.Toast;
5715646ce3e2e7a7f889976dc5684ecbc3029230c2Gary Maiimport android.widget.Toolbar;
583f990ba4e35a99078d831c041290e574a320caa5Walter Jang
597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.ContactSaveService;
607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.GroupMetaDataLoader;
617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.R;
62a4adae163d83db9226b831f8c9705914e68b5cd1Gary Maiimport com.android.contacts.activities.ContactEditorAccountsChangedActivity;
63363af60ea23e5a3b945005712a16564ab69db18bGary Maiimport com.android.contacts.activities.ContactEditorActivity;
64363af60ea23e5a3b945005712a16564ab69db18bGary Maiimport com.android.contacts.activities.ContactEditorActivity.ContactEditor;
657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.activities.ContactSelectionActivity;
66581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jangimport com.android.contacts.common.Experiments;
677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.logging.ScreenEvent.ScreenType;
687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.AccountTypeManager;
697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.Contact;
707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.ContactLoader;
717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.RawContact;
727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.RawContactDelta;
737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.RawContactDeltaList;
747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.RawContactModifier;
757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.ValuesDelta;
767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.account.AccountType;
777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.model.account.AccountWithDataSet;
78e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskeyimport com.android.contacts.common.preference.ContactsPreferences;
79e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskeyimport com.android.contacts.common.util.ContactDisplayUtils;
807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.util.ImplicitIntentsUtil;
817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.common.util.MaterialColorMapUtils;
827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
835c1bff2efa542ea112c3f2a1d1ed1e271c7691a7Gary Maiimport com.android.contacts.group.GroupUtil;
847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.list.UiIntentActions;
85e48746654178e9448819f86b3129fd32f539b3c9Gary Maiimport com.android.contacts.quickcontact.InvisibleContactUtil;
867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.quickcontact.QuickContactActivity;
877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.util.ContactPhotoUtils;
887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.android.contacts.util.UiClosables;
89a4adae163d83db9226b831f8c9705914e68b5cd1Gary Maiimport com.android.contactsbind.HelpUtils;
90581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jangimport com.android.contactsbind.ObjectFactory;
91581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jangimport com.android.contactsbind.experiments.Flags;
927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.google.common.collect.ImmutableList;
947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport com.google.common.collect.Lists;
957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
963efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jangimport java.io.FileNotFoundException;
9731a74ad969b650eb733e536569254ed3978c4f54Walter Jangimport java.util.ArrayList;
987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport java.util.HashSet;
997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport java.util.Iterator;
1007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport java.util.List;
1017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jangimport java.util.Set;
1023efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
1033f990ba4e35a99078d831c041290e574a320caa5Walter Jang/**
1043f990ba4e35a99078d831c041290e574a320caa5Walter Jang * Contact editor with only the most important fields displayed initially.
1053f990ba4e35a99078d831c041290e574a320caa5Walter Jang */
106363af60ea23e5a3b945005712a16564ab69db18bGary Maipublic class ContactEditorFragment extends Fragment implements
1077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        ContactEditor, SplitContactConfirmationDialogFragment.Listener,
1087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        JoinContactConfirmationDialogFragment.Listener,
1097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
1107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        CancelEditDialogFragment.Listener,
111363af60ea23e5a3b945005712a16564ab69db18bGary Mai        RawContactEditorView.Listener, PhotoEditorView.Listener {
1123f990ba4e35a99078d831c041290e574a320caa5Walter Jang
1137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    static final String TAG = "ContactEditor";
1147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final int LOADER_CONTACT = 1;
1167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final int LOADER_GROUPS = 2;
1177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1183efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    private static final String KEY_PHOTO_RAW_CONTACT_ID = "photo_raw_contact_id";
11928a27279554af7b1e5ff664d3da97954c462a797Walter Jang    private static final String KEY_UPDATED_PHOTOS = "updated_photos";
1203efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
1217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final List<String> VALID_INTENT_ACTIONS = new ArrayList<String>() {{
1227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        add(Intent.ACTION_EDIT);
1237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        add(Intent.ACTION_INSERT);
124363af60ea23e5a3b945005712a16564ab69db18bGary Mai        add(ContactEditorActivity.ACTION_SAVE_COMPLETED);
1257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }};
1267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_ACTION = "action";
1287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_URI = "uri";
1297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_AUTO_ADD_TO_DEFAULT_GROUP = "autoAddToDefaultGroup";
1307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_DISABLE_DELETE_MENU_OPTION = "disableDeleteMenuOption";
1317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_NEW_LOCAL_PROFILE = "newLocalProfile";
1327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_MATERIAL_PALETTE = "materialPalette";
1337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
1357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_RAW_CONTACTS = "rawContacts";
1377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_EDIT_STATE = "state";
1397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_STATUS = "status";
1407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_HAS_NEW_CONTACT = "hasNewContact";
1427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_NEW_CONTACT_READY = "newContactDataReady";
1437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_IS_EDIT = "isEdit";
1457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_EXISTING_CONTACT_READY = "existingContactDataReady";
1467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_IS_USER_PROFILE = "isUserProfile";
1487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_ENABLED = "enabled";
1507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Aggregation PopupWindow
1527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID =
1537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            "aggregationSuggestionsRawContactId";
1547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Join Activity
1567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
1577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
158698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    private static final String KEY_READ_ONLY_DISPLAY_NAME_ID = "readOnlyDisplayNameId";
159698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    private static final String KEY_COPY_READ_ONLY_DISPLAY_NAME = "copyReadOnlyDisplayName";
1607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected static final int REQUEST_CODE_JOIN = 0;
1627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected static final int REQUEST_CODE_ACCOUNTS_CHANGED = 1;
1637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final int CURRENT_API_VERSION = android.os.Build.VERSION.SDK_INT;
1657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
1677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * An intent extra that forces the editor to add the edited contact
1687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * to the default group (e.g. "My Contacts").
1697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
1717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String INTENT_EXTRA_NEW_LOCAL_PROFILE = "newLocalProfile";
1737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION =
1757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            "disableDeleteMenuOption";
1767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
1787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Intent key to pass the photo palette primary color calculated by
179363af60ea23e5a3b945005712a16564ab69db18bGary Mai     * {@link com.android.contacts.quickcontact.QuickContactActivity} to the editor.
1807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String INTENT_EXTRA_MATERIAL_PALETTE_PRIMARY_COLOR =
1827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            "material_palette_primary_color";
1837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
1857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Intent key to pass the photo palette secondary color calculated by
186363af60ea23e5a3b945005712a16564ab69db18bGary Mai     * {@link com.android.contacts.quickcontact.QuickContactActivity} to the editor.
1877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String INTENT_EXTRA_MATERIAL_PALETTE_SECONDARY_COLOR =
1897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            "material_palette_secondary_color";
1907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
1927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Intent key to pass the ID of the photo to display on the editor.
1937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
194da20b47c2b85390a2c3772379e71203c5aab513cGary Mai    // TODO: This can be cleaned up if we decide to not pass the photo id through
195da20b47c2b85390a2c3772379e71203c5aab513cGary Mai    // QuickContactActivity.
1967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String INTENT_EXTRA_PHOTO_ID = "photo_id";
1977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
199a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai     * Intent key to pass the ID of the raw contact id that should be displayed in the full editor
200a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai     * by itself.
201a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai     */
202a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai    public static final String INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE =
203a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai            "raw_contact_id_to_display_alone";
204a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai
205a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai    /**
2067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Intent extra to specify a {@link ContactEditor.SaveMode}.
2077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
2087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
2097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
2117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Intent extra key for the contact ID to join the current contact to after saving.
2127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
2137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public static final String JOIN_CONTACT_ID_EXTRA_KEY = "joinContactId";
2147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
2167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Callbacks for Activities that host contact editors Fragments.
2177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
2187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public interface Listener {
2197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        /**
2217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * Contact was not found, so somehow close this fragment. This is raised after a contact
2227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * is removed via Menu/Delete
2237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         */
2247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        void onContactNotFound();
2257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        /**
2277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * Contact was split, so we can close now.
2287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         *
2297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * @param newLookupUri The lookup uri of the new contact that should be shown to the user.
2307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         *                     The editor tries best to chose the most natural contact here.
2317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         */
2327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        void onContactSplit(Uri newLookupUri);
2337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        /**
2357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * User has tapped Revert, close the fragment now.
2367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         */
2377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        void onReverted();
2387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        /**
2407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * Contact was saved and the Fragment can now be closed safely.
2417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         */
2427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        void onSaveFinished(Intent resultIntent);
2437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        /**
245678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai         * User switched to editing a different raw contact (a suggestion from the
2467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * aggregation engine).
2477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         */
248678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai        void onEditOtherRawContactRequested(Uri contactLookupUri, long rawContactId,
2497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                ArrayList<ContentValues> contentValues);
2507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        /**
2527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         * User has requested that contact be deleted.
2537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang         */
2547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        void onDeleteRequested(Uri contactUri);
2557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
2567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
2587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Adapter for aggregation suggestions displayed in a PopupWindow when
2597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * editor fields change.
2607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
2617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static final class AggregationSuggestionAdapter extends BaseAdapter {
2627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        private final LayoutInflater mLayoutInflater;
2637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        private final AggregationSuggestionView.Listener mListener;
2647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        private final List<AggregationSuggestionEngine.Suggestion> mSuggestions;
2657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
266678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai        public AggregationSuggestionAdapter(Activity activity,
2677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) {
2687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mLayoutInflater = activity.getLayoutInflater();
2697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mListener = listener;
2707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mSuggestions = suggestions;
2717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
2727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        @Override
2747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        public View getView(int position, View convertView, ViewGroup parent) {
2757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            final Suggestion suggestion = (Suggestion) getItem(position);
2767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            final AggregationSuggestionView suggestionView =
2777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    (AggregationSuggestionView) mLayoutInflater.inflate(
2787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                            R.layout.aggregation_suggestions_item, null);
2797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            suggestionView.setListener(mListener);
2807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            suggestionView.bindSuggestion(suggestion);
2817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return suggestionView;
2827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
2837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        @Override
2857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        public long getItemId(int position) {
2867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return position;
2877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
2887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        @Override
2907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        public Object getItem(int position) {
2917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return mSuggestions.get(position);
2927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
2937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
2947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        @Override
2957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        public int getCount() {
2967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return mSuggestions.size();
2977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
2987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
2997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected Context mContext;
3017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected Listener mListener;
3027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Views
3057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected LinearLayout mContent;
3077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected View mAggregationSuggestionView;
3087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected ListPopupWindow mAggregationSuggestionPopup;
3097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Parameters passed in on {@link #load}
3127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected String mAction;
3147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected Uri mLookupUri;
3157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected Bundle mIntentExtras;
3167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mAutoAddToDefaultGroup;
3177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mDisableDeleteMenuOption;
3187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mNewLocalProfile;
3197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected MaterialColorMapUtils.MaterialPalette mMaterialPalette;
3207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Helpers
3237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected ContactEditorUtils mEditorUtils;
3257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected RawContactDeltaComparator mComparator;
3267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected ViewIdGenerator mViewIdGenerator;
3277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private AggregationSuggestionEngine mAggregationSuggestionEngine;
3287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Loaded data
3317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Used to store existing contact data so it can be re-applied during a rebind call,
3337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // i.e. account switch.
3347b75145e9b4fcd46c3cbb5678f8842934467b3aaGary Mai    protected Contact mContact;
3357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected ImmutableList<RawContact> mRawContacts;
3367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected Cursor mGroupMetaData;
3377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Editor state
3407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
3417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected RawContactDeltaList mState;
3427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected int mStatus;
3437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected long mRawContactIdToDisplayAlone = -1;
3447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Whether to show the new contact blank form and if it's corresponding delta is ready.
3467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mHasNewContact;
3477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected AccountWithDataSet mAccountWithDataSet;
3487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mNewContactDataReady;
3497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mNewContactAccountChanged;
3507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Whether it's an edit of existing contact and if it's corresponding delta is ready.
3527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mIsEdit;
3537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mExistingContactDataReady;
3547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Whether we are editing the "me" profile
3567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected boolean mIsUserProfile;
3577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Whether editor views and options menu items should be enabled
3597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean mEnabled = true;
3607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Aggregation PopupWindow
3627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private long mAggregationSuggestionsRawContactId;
3637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Join Activity
3657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected long mContactIdForJoin;
3667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Used to pre-populate the editor with a display name when a user edits a read-only contact.
368698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    protected long mReadOnlyDisplayNameId;
369698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    protected boolean mCopyReadOnlyName;
3707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
3727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * The contact data loader listener.
3737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
3747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected final LoaderManager.LoaderCallbacks<Contact> mContactLoaderListener =
3757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            new LoaderManager.LoaderCallbacks<Contact>() {
3767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                protected long mLoaderStartTime;
3787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
3807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public Loader<Contact> onCreateLoader(int id, Bundle args) {
3817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mLoaderStartTime = SystemClock.elapsedRealtime();
382e48746654178e9448819f86b3129fd32f539b3c9Gary Mai                    return new ContactLoader(mContext, mLookupUri,
383e48746654178e9448819f86b3129fd32f539b3c9Gary Mai                            /* postViewNotification */ true,
384e48746654178e9448819f86b3129fd32f539b3c9Gary Mai                            /* loadGroupMetaData */ true);
3857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
3867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
3887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public void onLoadFinished(Loader<Contact> loader, Contact contact) {
3897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    final long loaderCurrentTime = SystemClock.elapsedRealtime();
3907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
3917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    if (!contact.isLoaded()) {
3927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        // Item has been deleted. Close activity without saving again.
3937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        Log.i(TAG, "No contact found. Closing activity");
3947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        mStatus = Status.CLOSING;
3957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        if (mListener != null) mListener.onContactNotFound();
3967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        return;
3977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    }
3987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
3997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mStatus = Status.EDITING;
4007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mLookupUri = contact.getLookupUri();
4017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    final long setDataStartTime = SystemClock.elapsedRealtime();
4027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    setState(contact);
4037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    final long setDataEndTime = SystemClock.elapsedRealtime();
4047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime - setDataStartTime));
4067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
4077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
4097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public void onLoaderReset(Loader<Contact> loader) {
4107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
4117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            };
4127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
4147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * The groups meta data loader listener.
4157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
4167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected final LoaderManager.LoaderCallbacks<Cursor> mGroupsLoaderListener =
4177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            new LoaderManager.LoaderCallbacks<Cursor>() {
4187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
4207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public CursorLoader onCreateLoader(int id, Bundle args) {
4215c1bff2efa542ea112c3f2a1d1ed1e271c7691a7Gary Mai                    return new GroupMetaDataLoader(mContext, ContactsContract.Groups.CONTENT_URI,
4225c1bff2efa542ea112c3f2a1d1ed1e271c7691a7Gary Mai                            GroupUtil.ALL_GROUPS_SELECTION);
4237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
4247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
4267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
4277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mGroupMetaData = data;
4287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    setGroupMetaData();
4297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
4307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
4327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public void onLoaderReset(Loader<Cursor> loader) {
4337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
4347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            };
4357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4363efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    private long mPhotoRawContactId;
43728a27279554af7b1e5ff664d3da97954c462a797Walter Jang    private Bundle mUpdatedPhotos = new Bundle();
4383efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
4393efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    @Override
4407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public Context getContext() {
4417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return getActivity();
4427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
4437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
4457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onAttach(Activity activity) {
4467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        super.onAttach(activity);
4477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mContext = activity;
448a7978d5bc3fcbe62a40e59e29aebea668385a98aMarcus Hagerott        mEditorUtils = ContactEditorUtils.create(mContext);
4497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mComparator = new RawContactDeltaComparator(mContext);
4507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
4517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
4533efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    public void onCreate(Bundle savedState) {
4547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (savedState != null) {
4557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Restore mUri before calling super.onCreate so that onInitializeLoaders
4567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // would already have a uri and an action to work with
4577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAction = savedState.getString(KEY_ACTION);
4587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mLookupUri = savedState.getParcelable(KEY_URI);
4597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
4607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4613efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang        super.onCreate(savedState);
4623efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
4637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (savedState == null) {
4647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mViewIdGenerator = new ViewIdGenerator();
4657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // mState can still be null because it may not have have finished loading before
4677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // onSaveInstanceState was called.
4687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mState = new RawContactDeltaList();
4697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
4707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
4717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAutoAddToDefaultGroup = savedState.getBoolean(KEY_AUTO_ADD_TO_DEFAULT_GROUP);
4737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mDisableDeleteMenuOption = savedState.getBoolean(KEY_DISABLE_DELETE_MENU_OPTION);
4747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mNewLocalProfile = savedState.getBoolean(KEY_NEW_LOCAL_PROFILE);
4757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mMaterialPalette = savedState.getParcelable(KEY_MATERIAL_PALETTE);
4767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mRawContacts = ImmutableList.copyOf(savedState.<RawContact>getParcelableArrayList(
4787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    KEY_RAW_CONTACTS));
4797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // NOTE: mGroupMetaData is not saved/restored
4807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Read state from savedState. No loading involved here
4827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mState = savedState.<RawContactDeltaList> getParcelable(KEY_EDIT_STATE);
4837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mStatus = savedState.getInt(KEY_STATUS);
4847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mHasNewContact = savedState.getBoolean(KEY_HAS_NEW_CONTACT);
4867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mNewContactDataReady = savedState.getBoolean(KEY_NEW_CONTACT_READY);
4877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mIsEdit = savedState.getBoolean(KEY_IS_EDIT);
4897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mExistingContactDataReady = savedState.getBoolean(KEY_EXISTING_CONTACT_READY);
4907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mIsUserProfile = savedState.getBoolean(KEY_IS_USER_PROFILE);
4927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mEnabled = savedState.getBoolean(KEY_ENABLED);
4947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Aggregation PopupWindow
4967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionsRawContactId = savedState.getLong(
4977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID);
4987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
4997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Join Activity
5007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
5017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
502698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            mReadOnlyDisplayNameId = savedState.getLong(KEY_READ_ONLY_DISPLAY_NAME_ID);
503698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            mCopyReadOnlyName = savedState.getBoolean(KEY_COPY_READ_ONLY_DISPLAY_NAME, false);
5047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5053efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang            mPhotoRawContactId = savedState.getLong(KEY_PHOTO_RAW_CONTACT_ID);
50628a27279554af7b1e5ff664d3da97954c462a797Walter Jang            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
5073efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang        }
5083efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    }
5093efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
5103f990ba4e35a99078d831c041290e574a320caa5Walter Jang    @Override
5113f990ba4e35a99078d831c041290e574a320caa5Walter Jang    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
512ed8f6c9744dd38e089598acfba6fb90446954e6eWalter Jang        setHasOptionsMenu(true);
513ed8f6c9744dd38e089598acfba6fb90446954e6eWalter Jang
5143f990ba4e35a99078d831c041290e574a320caa5Walter Jang        final View view = inflater.inflate(
515363af60ea23e5a3b945005712a16564ab69db18bGary Mai                R.layout.contact_editor_fragment, container, false);
516f5dfea4a5c94382a632eae5c538881f7da726a50Walter Jang        mContent = (LinearLayout) view.findViewById(R.id.raw_contacts_editor_view);
5173f990ba4e35a99078d831c041290e574a320caa5Walter Jang        return view;
5183f990ba4e35a99078d831c041290e574a320caa5Walter Jang    }
5193f990ba4e35a99078d831c041290e574a320caa5Walter Jang
520ed8f6c9744dd38e089598acfba6fb90446954e6eWalter Jang    @Override
5217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onActivityCreated(Bundle savedInstanceState) {
5227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        super.onActivityCreated(savedInstanceState);
5237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        validateAction(mAction);
5257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mState.isEmpty()) {
5277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // The delta list may not have finished loading before orientation change happens.
5287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // In this case, there will be a saved state but deltas will be missing.  Reload from
5297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // database.
5307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (Intent.ACTION_EDIT.equals(mAction)) {
5317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // Either
5327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // 1) orientation change but load never finished.
5337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // 2) not an orientation change so data needs to be loaded for first time.
5347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                getLoaderManager().initLoader(LOADER_CONTACT, null, mContactLoaderListener);
5357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupsLoaderListener);
5367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
5377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
5387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Orientation change, we already have mState, it was loaded by onCreate
5397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            bindEditors();
5407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
5417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Handle initial actions only when existing state missing
5437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (savedInstanceState == null) {
5447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            final Account account = mIntentExtras == null ? null :
5457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    (Account) mIntentExtras.getParcelable(Intents.Insert.EXTRA_ACCOUNT);
5467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            final String dataSet = mIntentExtras == null ? null :
5477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mIntentExtras.getString(Intents.Insert.EXTRA_DATA_SET);
5487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (account != null) {
5497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mAccountWithDataSet = new AccountWithDataSet(account.name, account.type, dataSet);
5507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
5517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (Intent.ACTION_EDIT.equals(mAction)) {
5537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mIsEdit = true;
5547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            } else if (Intent.ACTION_INSERT.equals(mAction)) {
5557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mHasNewContact = true;
5567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (mAccountWithDataSet != null) {
5577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    createContact(mAccountWithDataSet);
558935b56aabd5ee1562df1d16324ce8e3f51005651Marcus Hagerott                } else if (mIntentExtras != null && mIntentExtras.getBoolean(
559363af60ea23e5a3b945005712a16564ab69db18bGary Mai                        ContactEditorActivity.EXTRA_SAVE_TO_DEVICE_FLAG, false)) {
560935b56aabd5ee1562df1d16324ce8e3f51005651Marcus Hagerott                    createContact(null);
5617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                } else {
5627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    // No Account specified. Let the user choose
5637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    // Load Accounts async so that we can present them
5647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    selectAccountAndCreateContact();
5657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
5667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
5677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
5687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
5697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
5717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Checks if the requested action is valid.
5727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *
5737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param action The action to test.
5747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @throws IllegalArgumentException when the action is invalid.
5757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
5767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static void validateAction(String action) {
5777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (VALID_INTENT_ACTIONS.contains(action)) {
5787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
5797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
5807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        throw new IllegalArgumentException(
5817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                "Unknown action " + action + "; Supported actions: " + VALID_INTENT_ACTIONS);
5827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
5837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
5853efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    public void onSaveInstanceState(Bundle outState) {
5867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putString(KEY_ACTION, mAction);
5877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putParcelable(KEY_URI, mLookupUri);
5887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_AUTO_ADD_TO_DEFAULT_GROUP, mAutoAddToDefaultGroup);
5897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_DISABLE_DELETE_MENU_OPTION, mDisableDeleteMenuOption);
5907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_NEW_LOCAL_PROFILE, mNewLocalProfile);
5917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mMaterialPalette != null) {
5927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            outState.putParcelable(KEY_MATERIAL_PALETTE, mMaterialPalette);
5937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
5947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
5957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
5967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putParcelableArrayList(KEY_RAW_CONTACTS, mRawContacts == null ?
5977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                Lists.<RawContact>newArrayList() : Lists.newArrayList(mRawContacts));
5987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // NOTE: mGroupMetaData is not saved
5997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
60036ceb4235ed685a222af86076dcf160ba124a583Gary Mai        outState.putParcelable(KEY_EDIT_STATE, mState);
6017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putInt(KEY_STATUS, mStatus);
6027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_HAS_NEW_CONTACT, mHasNewContact);
6037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_NEW_CONTACT_READY, mNewContactDataReady);
6047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_IS_EDIT, mIsEdit);
6057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_EXISTING_CONTACT_READY, mExistingContactDataReady);
6067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_IS_USER_PROFILE, mIsUserProfile);
6087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putBoolean(KEY_ENABLED, mEnabled);
6107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Aggregation PopupWindow
6127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putLong(KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID,
6137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mAggregationSuggestionsRawContactId);
6147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Join Activity
6167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
6177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
618698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        outState.putLong(KEY_READ_ONLY_DISPLAY_NAME_ID, mReadOnlyDisplayNameId);
619698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        outState.putBoolean(KEY_COPY_READ_ONLY_DISPLAY_NAME, mCopyReadOnlyName);
6207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6213efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang        outState.putLong(KEY_PHOTO_RAW_CONTACT_ID, mPhotoRawContactId);
62228a27279554af7b1e5ff664d3da97954c462a797Walter Jang        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
6233efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang        super.onSaveInstanceState(outState);
6243efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    }
6253efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
6263efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    @Override
6277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onStop() {
6287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        super.onStop();
6297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        UiClosables.closeQuietly(mAggregationSuggestionPopup);
6307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
6317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
6337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onDestroy() {
6347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        super.onDestroy();
6357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mAggregationSuggestionEngine != null) {
6367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionEngine.quit();
6377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
6387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
6397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
6417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onActivityResult(int requestCode, int resultCode, Intent data) {
6427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        switch (requestCode) {
6437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case REQUEST_CODE_JOIN: {
6447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // Ignore failed requests
6457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (resultCode != Activity.RESULT_OK) return;
6467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (data != null) {
6477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    final long contactId = ContentUris.parseId(data.getData());
6487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    if (hasPendingChanges()) {
6497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        // Ask the user if they want to save changes before doing the join
6507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        JoinContactConfirmationDialogFragment.show(this, contactId);
6517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    } else {
6527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        // Do the join immediately
6537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        joinAggregate(contactId);
6547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    }
6557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
6567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
6577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
6587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case REQUEST_CODE_ACCOUNTS_CHANGED: {
6597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // Bail if the account selector was not successful.
6607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (resultCode != Activity.RESULT_OK) {
6617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    if (mListener != null) {
6627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        mListener.onReverted();
6637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    }
6647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    return;
6657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
6667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // If there's an account specified, use it.
6677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (data != null) {
6687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    AccountWithDataSet account = data.getParcelableExtra(
6697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                            Intents.Insert.EXTRA_ACCOUNT);
6707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    if (account != null) {
6717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        createContact(account);
6727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        return;
6737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    }
6747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
6757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // If there isn't an account specified, then this is likely a phone-local
6767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // contact, so we should continue setting up the editor by automatically selecting
6777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // the most appropriate account.
6787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                createContact();
6797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
6807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
6817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
6827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
6837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
6857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Options menu
6867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
6877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
6897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
6907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        inflater.inflate(R.menu.edit_contact, menu);
6917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
6927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
6937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
6947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onPrepareOptionsMenu(Menu menu) {
6957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
6967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // because the custom action bar contains the "save" button now (not the overflow menu).
6977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
6987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final MenuItem saveMenu = menu.findItem(R.id.menu_save);
6997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final MenuItem splitMenu = menu.findItem(R.id.menu_split);
7007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final MenuItem joinMenu = menu.findItem(R.id.menu_join);
7017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final MenuItem deleteMenu = menu.findItem(R.id.menu_delete);
7027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7035eda257528e45fe6ae59cca3f1178590b53662f8Gary Mai        // TODO: b/30771904, b/31827701, temporarily disable these items until we get them to work
7045eda257528e45fe6ae59cca3f1178590b53662f8Gary Mai        // on a raw contact level.
7055eda257528e45fe6ae59cca3f1178590b53662f8Gary Mai        joinMenu.setVisible(false);
7065eda257528e45fe6ae59cca3f1178590b53662f8Gary Mai        splitMenu.setVisible(false);
7075eda257528e45fe6ae59cca3f1178590b53662f8Gary Mai        deleteMenu.setVisible(false);
7087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Save menu is invisible when there's only one read only contact in the editor.
709d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai        saveMenu.setVisible(!isEditingReadOnlyRawContact());
7107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (saveMenu.isVisible()) {
7117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Since we're using a custom action layout we have to manually hook up the handler.
7127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            saveMenu.getActionView().setOnClickListener(new View.OnClickListener() {
7137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                @Override
7147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                public void onClick(View v) {
7157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    onOptionsItemSelected(saveMenu);
7167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
7177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            });
7187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        int size = menu.size();
7217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        for (int i = 0; i < size; i++) {
7227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            menu.getItem(i).setEnabled(mEnabled);
7237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
7257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
727c90cc15b804fb00339a3b98e5c951549f9b03599Walter Jang    public boolean onOptionsItemSelected(MenuItem item) {
728c90cc15b804fb00339a3b98e5c951549f9b03599Walter Jang        if (item.getItemId() == android.R.id.home) {
729c90cc15b804fb00339a3b98e5c951549f9b03599Walter Jang            return revert();
730c90cc15b804fb00339a3b98e5c951549f9b03599Walter Jang        }
7317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final Activity activity = getActivity();
7337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (activity == null || activity.isFinishing() || activity.isDestroyed()) {
7347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // If we no longer are attached to a running activity want to
7357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // drain this event.
7367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return true;
7377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        switch (item.getItemId()) {
7407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case R.id.menu_save:
7417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return save(SaveMode.CLOSE);
7427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case R.id.menu_delete:
7437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (mListener != null) mListener.onDeleteRequested(mLookupUri);
7447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return true;
7457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case R.id.menu_split:
7467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return doSplitContactAction();
7477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case R.id.menu_join:
7487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return doJoinContactAction();
749a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai            case R.id.menu_help:
750a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                HelpUtils.launchHelpAndFeedbackForContactScreen(getActivity());
7517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return true;
7527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return false;
7557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
7567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
7587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public boolean revert() {
7597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mState.isEmpty() || !hasPendingChanges()) {
7607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            onCancelEditConfirmed();
7617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
7627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            CancelEditDialogFragment.show(this);
7637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return true;
7657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
7667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
7687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onCancelEditConfirmed() {
7697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // When this Fragment is closed we don't want it to auto-save
7707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mStatus = Status.CLOSING;
7717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mListener != null) {
7727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mListener.onReverted();
7737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
7757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
7777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onSplitContactConfirmed(boolean hasPendingChanges) {
7787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mState.isEmpty()) {
7797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // This may happen when this Fragment is recreated by the system during users
7807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // confirming the split action (and thus this method is called just before onCreate()),
7817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // for example.
7827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            Log.e(TAG, "mState became null during the user's confirming split action. " +
7837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    "Cannot perform the save action.");
7847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
7857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
7877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!hasPendingChanges && mHasNewContact) {
7887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // If the user didn't add anything new, we don't want to split out the newly created
7897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // raw contact into a name-only contact so remove them.
7907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            final Iterator<RawContactDelta> iterator = mState.iterator();
7917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            while (iterator.hasNext()) {
7927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                final RawContactDelta rawContactDelta = iterator.next();
7937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (rawContactDelta.getRawContactId() < 0) {
7947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    iterator.remove();
7957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
7967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
7977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
7987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mState.markRawContactsForSplitting();
7997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        save(SaveMode.SPLIT);
8007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
802b9065ddb28a2040cabda251891be2062b5260217Gary Mai    @Override
803b9065ddb28a2040cabda251891be2062b5260217Gary Mai    public void onSplitContactCanceled() {}
804b9065ddb28a2040cabda251891be2062b5260217Gary Mai
8057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean doSplitContactAction() {
8067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!hasValidState()) return false;
8077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        SplitContactConfirmationDialogFragment.show(this, hasPendingChanges());
8097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return true;
8107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean doJoinContactAction() {
8137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!hasValidState() || mLookupUri == null) {
8147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return false;
8157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
8167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // If we just started creating a new contact and haven't added any data, it's too
8187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // early to do a join
8197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mState.size() == 1 && mState.get(0).isContactInsert()
8207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                && !hasPendingChanges()) {
8217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            Toast.makeText(mContext, R.string.toast_join_with_empty_contact,
8227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    Toast.LENGTH_LONG).show();
8237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return true;
8247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
8257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        showJoinAggregateActivity(mLookupUri);
8277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return true;
8287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
8317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onJoinContactConfirmed(long joinContactId) {
8327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        doSaveAction(SaveMode.JOIN, joinContactId);
8337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
835c90cc15b804fb00339a3b98e5c951549f9b03599Walter Jang    @Override
8367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public boolean save(int saveMode) {
8377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!hasValidState() || mStatus != Status.EDITING) {
8387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return false;
8397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
8407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // If we are about to close the editor - there is no need to refresh the data
842363af60ea23e5a3b945005712a16564ab69db18bGary Mai        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.EDITOR
8437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                || saveMode == SaveMode.SPLIT) {
8447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            getLoaderManager().destroyLoader(LOADER_CONTACT);
8457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
8467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mStatus = Status.SAVING;
8487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!hasPendingChanges()) {
8507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (mLookupUri == null && saveMode == SaveMode.RELOAD) {
8517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // We don't have anything to save and there isn't even an existing contact yet.
8527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // Nothing to do, simply go back to editing mode
8537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mStatus = Status.EDITING;
8547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return true;
8557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
8567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            onSaveCompleted(/* hadChanges =*/ false, saveMode,
8577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    /* saveSucceeded =*/ mLookupUri != null, mLookupUri, /* joinContactId =*/ null);
8587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return true;
8597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
8607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        setEnabled(false);
8627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return doSaveAction(saveMode, /* joinContactId */ null);
8647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
8677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // State accessor methods
8687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
8697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
8717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Check if our internal {@link #mState} is valid, usually checked before
8727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * performing user actions.
8737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
8747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean hasValidState() {
8757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return mState.size() > 0;
8767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean isEditingUserProfile() {
8797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return mNewLocalProfile || mIsUserProfile;
8807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
8835a00de39004d298de4daee3e183add5eff17102cGary Mai     * Whether the contact being edited is composed of read-only raw contacts
8847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * aggregated with a newly created writable raw contact.
8857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
8867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean isEditingReadOnlyRawContactWithNewContact() {
8875a00de39004d298de4daee3e183add5eff17102cGary Mai        return mHasNewContact && mState.size() > 1;
8887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
8897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
8907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
891d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai     * @return true if the single raw contact we're looking at is read-only.
892d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai     */
893d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai    private boolean isEditingReadOnlyRawContact() {
894d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai        return hasValidState() && mRawContactIdToDisplayAlone > 0
895d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai                && !mState.getByRawContactId(mRawContactIdToDisplayAlone)
896d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai                        .getAccountType(AccountTypeManager.getInstance(mContext))
897d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai                                .areContactsWritable();
898d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai    }
899d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai
900d7faa65c1349a7ded4d2d478822c07d024e5e792Gary Mai    /**
9017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Return true if there are any edits to the current contact which need to
9027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * be saved.
9037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
9047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean hasPendingRawContactChanges(Set<String> excludedMimeTypes) {
9057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
9067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return RawContactModifier.hasChanges(mState, accountTypes, excludedMimeTypes);
9077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
9087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
9097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
9107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Determines if changes were made in the editor that need to be saved, while taking into
9117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * account that name changes are not real for read-only contacts.
9127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * See go/editing-read-only-contacts
9137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
9147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean hasPendingChanges() {
915698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        if (isEditingReadOnlyRawContactWithNewContact()) {
9167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // We created a new raw contact delta with a default display name.
9177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // We must test for pending changes while ignoring the default display name.
918698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final ValuesDelta beforeDelta = mState.getByRawContactId(mReadOnlyDisplayNameId)
919698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai                    .getSuperPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
920698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final ValuesDelta pendingDelta = mState
921698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai                    .getSuperPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
922698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            if (structuredNamesAreEqual(beforeDelta, pendingDelta)) {
9237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                final Set<String> excludedMimeTypes = new HashSet<>();
9247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                excludedMimeTypes.add(StructuredName.CONTENT_ITEM_TYPE);
9257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return hasPendingRawContactChanges(excludedMimeTypes);
9267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
9277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return true;
9287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
9297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return hasPendingRawContactChanges(/* excludedMimeTypes =*/ null);
9307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
9317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
9327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
933698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     * Compares the two {@link ValuesDelta} to see if the structured name is changed. We made a copy
934698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     * of a read only delta and now we want to check if the copied delta has changes.
935698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     *
936698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     * @param before original {@link ValuesDelta}
937698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     * @param after copied {@link ValuesDelta}
938698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     * @return true if the copied {@link ValuesDelta} has all the same values in the structured
939698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     * name fields as the original.
940698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai     */
941698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    private boolean structuredNamesAreEqual(ValuesDelta before, ValuesDelta after) {
9425a00de39004d298de4daee3e183add5eff17102cGary Mai        if (before == after) return true;
943698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        if (before == null || after == null) return false;
944698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        final ContentValues original = before.getBefore();
945698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        final ContentValues pending = after.getAfter();
946698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        if (original != null && pending != null) {
947a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai            final String beforeDisplayName = original.getAsString(StructuredName.DISPLAY_NAME);
948698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String afterDisplayName = pending.getAsString(StructuredName.DISPLAY_NAME);
949698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            if (!TextUtils.equals(beforeDisplayName, afterDisplayName)) return false;
950698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
951698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String beforePrefix = original.getAsString(StructuredName.PREFIX);
952698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String afterPrefix = pending.getAsString(StructuredName.PREFIX);
953698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            if (!TextUtils.equals(beforePrefix, afterPrefix)) return false;
954698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
955698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String beforeFirstName = original.getAsString(StructuredName.GIVEN_NAME);
956698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String afterFirstName = pending.getAsString(StructuredName.GIVEN_NAME);
957698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            if (!TextUtils.equals(beforeFirstName, afterFirstName)) return false;
958698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
959698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String beforeMiddleName = original.getAsString(StructuredName.MIDDLE_NAME);
960698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String afterMiddleName = pending.getAsString(StructuredName.MIDDLE_NAME);
961698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            if (!TextUtils.equals(beforeMiddleName, afterMiddleName)) return false;
962698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
963698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String beforeLastName = original.getAsString(StructuredName.FAMILY_NAME);
964698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String afterLastName = pending.getAsString(StructuredName.FAMILY_NAME);
965698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            if (!TextUtils.equals(beforeLastName, afterLastName)) return false;
966698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
967698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String beforeSuffix = original.getAsString(StructuredName.SUFFIX);
968698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            final String afterSuffix = pending.getAsString(StructuredName.SUFFIX);
969698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            return TextUtils.equals(beforeSuffix, afterSuffix);
970698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        }
971698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        return false;
972698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    }
973698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
9747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
9757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Account creation
9767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
9777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
9787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void selectAccountAndCreateContact() {
9797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // If this is a local profile, then skip the logic about showing the accounts changed
9807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // activity and create a phone-local contact.
9817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mNewLocalProfile) {
9827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            createContact(null);
9837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
9847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
9857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
9867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // If there is no default account or the accounts have changed such that we need to
9877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // prompt the user again, then launch the account prompt.
9887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mEditorUtils.shouldShowAccountChangedNotification()) {
9897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            Intent intent = new Intent(mContext, ContactEditorAccountsChangedActivity.class);
9907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Prevent a second instance from being started on rotates
9917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
9927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mStatus = Status.SUB_ACTIVITY;
9937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            startActivityForResult(intent, REQUEST_CODE_ACCOUNTS_CHANGED);
9947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
9953107b25dcaea54943c58f984084fa9b348ea1885Gary Mai            // Make sure the default account is automatically set if there is only one non-device
9963107b25dcaea54943c58f984084fa9b348ea1885Gary Mai            // account.
9973107b25dcaea54943c58f984084fa9b348ea1885Gary Mai            mEditorUtils.maybeUpdateDefaultAccount();
9987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Otherwise, there should be a default account. Then either create a local contact
9997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // (if default account is null) or create a contact with the specified account.
1000a7978d5bc3fcbe62a40e59e29aebea668385a98aMarcus Hagerott            AccountWithDataSet defaultAccount = mEditorUtils.getOnlyOrDefaultAccount();
10017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            createContact(defaultAccount);
10027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
10037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
10047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
10067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Create a contact by automatically selecting the first account. If there's no available
10077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * account, a device-local contact should be created.
10087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
10097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void createContact() {
10107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final List<AccountWithDataSet> accounts =
10117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                AccountTypeManager.getInstance(mContext).getAccounts(true);
10127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // No Accounts available. Create a phone-local contact.
10137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (accounts.isEmpty()) {
10147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            createContact(null);
10157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
10167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
10177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // We have an account switcher in "create-account" screen, so don't need to ask a user to
10197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // select an account here.
10207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        createContact(accounts.get(0));
10217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
10227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
10247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Shows account creation screen associated with a given account.
10257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *
10267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param account may be null to signal a device-local contact should be created.
10277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
10287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void createContact(AccountWithDataSet account) {
10297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
10307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final AccountType accountType = accountTypes.getAccountTypeForAccount(account);
10317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1032aebf3206766a05cce290245f09506adb789b6e37Gary Mai        setStateForNewContact(account, accountType, isEditingUserProfile());
10337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
10347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
10367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Data binding
10377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
10387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void setState(Contact contact) {
10407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // If we have already loaded data, we do not want to change it here to not confuse the user
10417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!mState.isEmpty()) {
10427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            Log.v(TAG, "Ignoring background change. This will have to be rebased later");
10437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
10447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
10457b75145e9b4fcd46c3cbb5678f8842934467b3aaGary Mai        mContact = contact;
10464ceabed629c43cb247fd4a0faa36c09bd5ec999aGary Mai        mRawContacts = contact.getRawContacts();
10477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Check for writable raw contacts.  If there are none, then we need to create one so user
10497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // can edit.  For the user profile case, there is already an editable contact.
10507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!contact.isUserProfile() && !contact.isWritableContact(mContext)) {
10517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mHasNewContact = true;
1052698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            mReadOnlyDisplayNameId = contact.getNameRawContactId();
1053698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            mCopyReadOnlyName = true;
10547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // This is potentially an asynchronous call and will add deltas to list.
10557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            selectAccountAndCreateContact();
10567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
10577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mHasNewContact = false;
10587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
10597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1060698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        setStateForExistingContact(contact.isUserProfile(), mRawContacts);
1061e48746654178e9448819f86b3129fd32f539b3c9Gary Mai        if (mAutoAddToDefaultGroup
1062e48746654178e9448819f86b3129fd32f539b3c9Gary Mai                && InvisibleContactUtil.isInvisibleAndAddable(contact, getContext())) {
1063e48746654178e9448819f86b3129fd32f539b3c9Gary Mai            InvisibleContactUtil.markAddToDefaultGroup(contact, mState, getContext());
1064e48746654178e9448819f86b3129fd32f539b3c9Gary Mai        }
10657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
10667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
10687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Prepare {@link #mState} for a newly created phone-local contact.
10697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
10707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void setStateForNewContact(AccountWithDataSet account, AccountType accountType,
10717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            boolean isUserProfile) {
10727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        setStateForNewContact(account, accountType, /* oldState =*/ null,
10737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                /* oldAccountType =*/ null, isUserProfile);
10747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
10757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
10777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Prepare {@link #mState} for a newly created phone-local contact, migrating the state
10787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * specified by oldState and oldAccountType.
10797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
10807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void setStateForNewContact(AccountWithDataSet account, AccountType accountType,
10817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            RawContactDelta oldState, AccountType oldAccountType, boolean isUserProfile) {
10827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mStatus = Status.EDITING;
10837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mState.add(createNewRawContactDelta(account, accountType, oldState, oldAccountType));
10847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mIsUserProfile = isUserProfile;
10857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mNewContactDataReady = true;
10867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        bindEditors();
10877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
10887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
10897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
10907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Returns a {@link RawContactDelta} for a new contact suitable for addition into
10917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * {@link #mState}.
10927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *
10937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * If oldState and oldAccountType are specified, the state specified by those parameters
10947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * is migrated to the result {@link RawContactDelta}.
10957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
10967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private RawContactDelta createNewRawContactDelta(AccountWithDataSet account,
10977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            AccountType accountType, RawContactDelta oldState, AccountType oldAccountType) {
10987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final RawContact rawContact = new RawContact();
10997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (account != null) {
11007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            rawContact.setAccount(account);
11017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
11027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            rawContact.setAccountToLocal();
11037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
11047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final RawContactDelta result = new RawContactDelta(
11067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                ValuesDelta.fromAfter(rawContact.getValues()));
11077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (oldState == null) {
11087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Parse any values from incoming intent
11097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            RawContactModifier.parseExtras(mContext, accountType, result, mIntentExtras);
11107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        } else {
11117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            RawContactModifier.migrateStateForNewContact(
11127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mContext, oldState, result, oldAccountType, accountType);
11137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
11147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Ensure we have some default fields (if the account type does not support a field,
11167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // ensureKind will not add it, so it is safe to add e.g. Event)
111762ec0b10c0ddc00053df39aeaed1f3316116e849Gary Mai        RawContactModifier.ensureKindExists(result, accountType, StructuredName.CONTENT_ITEM_TYPE);
11187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        RawContactModifier.ensureKindExists(result, accountType, Phone.CONTENT_ITEM_TYPE);
11197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        RawContactModifier.ensureKindExists(result, accountType, Email.CONTENT_ITEM_TYPE);
11207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        RawContactModifier.ensureKindExists(result, accountType, Organization.CONTENT_ITEM_TYPE);
11217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        RawContactModifier.ensureKindExists(result, accountType, Event.CONTENT_ITEM_TYPE);
11227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        RawContactModifier.ensureKindExists(result, accountType,
11237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                StructuredPostal.CONTENT_ITEM_TYPE);
11247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // Set the correct URI for saving the contact as a profile
11267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mNewLocalProfile) {
11277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            result.setProfileQueryUri();
11287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
11297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return result;
11317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
11327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
11347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Prepare {@link #mState} for an existing contact.
11357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1136698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    private void setStateForExistingContact(boolean isUserProfile,
11377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            ImmutableList<RawContact> rawContacts) {
11387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        setEnabled(true);
11397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mState.addAll(rawContacts.iterator());
11417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        setIntentExtras(mIntentExtras);
11427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mIntentExtras = null;
11437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        // For user profile, change the contacts query URI
11457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mIsUserProfile = isUserProfile;
11467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        boolean localProfileExists = false;
11477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mIsUserProfile) {
11497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            for (RawContactDelta rawContactDelta : mState) {
11507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // For profile contacts, we need a different query URI
11517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                rawContactDelta.setProfileQueryUri();
11527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // Try to find a local profile contact
11537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (rawContactDelta.getValues().getAsString(RawContacts.ACCOUNT_TYPE) == null) {
11547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    localProfileExists = true;
11557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
11567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
11577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Editor should always present a local profile for editing
11587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // TODO(wjang): Need to figure out when this case comes up.  We can't do this if we're
11597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // going to prune all but the one raw contact that we're trying to display by itself.
11607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (!localProfileExists && mRawContactIdToDisplayAlone <= 0) {
11617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mState.add(createLocalRawContactDelta());
11627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
11637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
11647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mExistingContactDataReady = true;
11657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        bindEditors();
11667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
11677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
11697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Set the enabled state of editors.
11707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
11717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void setEnabled(boolean enabled) {
11727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mEnabled != enabled) {
11737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mEnabled = enabled;
11747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Enable/disable editors
11767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (mContent != null) {
11777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                int count = mContent.getChildCount();
11787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                for (int i = 0; i < count; i++) {
11797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mContent.getChildAt(i).setEnabled(enabled);
11807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
11817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
11827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Enable/disable aggregation suggestion vies
11847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (mAggregationSuggestionView != null) {
11857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
11867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        R.id.aggregation_suggestions);
11877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                int count = itemList.getChildCount();
11887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                for (int i = 0; i < count; i++) {
11897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    itemList.getChildAt(i).setEnabled(enabled);
11907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
11917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
11927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // Maybe invalidate the options menu
11947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            final Activity activity = getActivity();
11957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (activity != null) activity.invalidateOptionsMenu();
11967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
11977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
11987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
11997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
12007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Returns a {@link RawContactDelta} for a local contact suitable for addition into
12017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * {@link #mState}.
12027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
12037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private static RawContactDelta createLocalRawContactDelta() {
12047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final RawContact rawContact = new RawContact();
12057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        rawContact.setAccountToLocal();
12067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
12077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final RawContactDelta result = new RawContactDelta(
12087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                ValuesDelta.fromAfter(rawContact.getValues()));
12097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        result.setProfileQueryUri();
12107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
12117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return result;
12127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
12137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1214698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    private void copyReadOnlyName() {
1215698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        // We should only ever be doing this if we're creating a new writable contact to attach to
1216698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        // a read only contact.
1217698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        if (!isEditingReadOnlyRawContactWithNewContact()) {
1218698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            return;
1219698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        }
1220698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        final int writableIndex = mState.indexOfFirstWritableRawContact(getContext());
1221698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        final RawContactDelta writable = mState.get(writableIndex);
12227b75145e9b4fcd46c3cbb5678f8842934467b3aaGary Mai        final RawContactDelta readOnly = mState.getByRawContactId(mContact.getNameRawContactId());
1223698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        final ValuesDelta writeNameDelta = writable
1224698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai                .getSuperPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
1225698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        final ValuesDelta readNameDelta = readOnly
1226698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai                .getSuperPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
1227698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        writeNameDelta.copyStructuredNameFieldsFrom(readNameDelta);
1228698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        mCopyReadOnlyName = false;
1229698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai    }
1230698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai
12317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
12327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Bind editors using {@link #mState} and other members initialized from the loaded (or new)
12337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Contact.
12347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1235ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    protected void bindEditors() {
1236cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        if (!isReadyToBindEditors()) {
1237cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            return;
1238cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        }
1239cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang
1240d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        // Add input fields for the loaded Contact
1241363af60ea23e5a3b945005712a16564ab69db18bGary Mai        final RawContactEditorView editorView = getContent();
1242b6ca272f26b47ecef8fafe94326c4d553576c521Walter Jang        editorView.setListener(this);
1243698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        if (mCopyReadOnlyName) {
1244698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            copyReadOnlyName();
1245698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai        }
1246678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai        editorView.setState(mState, mMaterialPalette, mViewIdGenerator,
12479a55237f705453caae1f8aa3576a9acd7596d5ecWalter Jang                mHasNewContact, mIsUserProfile, mAccountWithDataSet,
12485a00de39004d298de4daee3e183add5eff17102cGary Mai                mRawContactIdToDisplayAlone);
1249079598fa2e09c22bb672715a9559b9d8973044d5Gary Mai        if (isEditingReadOnlyRawContact()) {
125015646ce3e2e7a7f889976dc5684ecbc3029230c2Gary Mai            final Toolbar toolbar = getEditorActivity().getToolbar();
125115646ce3e2e7a7f889976dc5684ecbc3029230c2Gary Mai            if (toolbar != null) {
125215646ce3e2e7a7f889976dc5684ecbc3029230c2Gary Mai                toolbar.setTitle(R.string.contact_editor_title_read_only_contact);
1253d8f3da6a4ea4054bd47959db85657a7e01d28358Gary Mai                // Set activity title for Talkback
1254d8f3da6a4ea4054bd47959db85657a7e01d28358Gary Mai                getEditorActivity().setTitle(R.string.contact_editor_title_read_only_contact);
125515646ce3e2e7a7f889976dc5684ecbc3029230c2Gary Mai                toolbar.setNavigationIcon(R.drawable.ic_back_arrow);
125615646ce3e2e7a7f889976dc5684ecbc3029230c2Gary Mai                toolbar.setNavigationContentDescription(R.string.back_arrow_content_description);
1257079598fa2e09c22bb672715a9559b9d8973044d5Gary Mai            }
1258079598fa2e09c22bb672715a9559b9d8973044d5Gary Mai        }
1259cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang
1260d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        // Set up the photo widget
126131a74ad969b650eb733e536569254ed3978c4f54Walter Jang        editorView.setPhotoListener(this);
12623efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang        mPhotoRawContactId = editorView.getPhotoRawContactId();
126331a74ad969b650eb733e536569254ed3978c4f54Walter Jang        // If there is an updated full resolution photo apply it now, this will be the case if
126431a74ad969b650eb733e536569254ed3978c4f54Walter Jang        // the user selects or takes a new photo, then rotates the device.
126531a74ad969b650eb733e536569254ed3978c4f54Walter Jang        final Uri uri = (Uri) mUpdatedPhotos.get(String.valueOf(mPhotoRawContactId));
126631a74ad969b650eb733e536569254ed3978c4f54Walter Jang        if (uri != null) {
126731a74ad969b650eb733e536569254ed3978c4f54Walter Jang            editorView.setFullSizePhoto(uri);
126841b3ea1c712f01164feb55455f1391564cb76deeWalter Jang        }
12693efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang
1270d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        // The editor is ready now so make it visible
1271678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai        editorView.setEnabled(mEnabled);
1272d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        editorView.setVisibility(View.VISIBLE);
1273d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang
1274d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        // Refresh the ActionBar as the visibility of the join command
1275d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        // Activity can be null if we have been detached from the Activity.
1276cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        invalidateOptionsMenu();
1277cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang    }
1278cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang
12797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
12807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Invalidates the options menu if we are still associated with an Activity.
12817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
12827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void invalidateOptionsMenu() {
12837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final Activity activity = getActivity();
12847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (activity != null) {
12857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            activity.invalidateOptionsMenu();
12867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
12877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
12887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1289cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang    private boolean isReadyToBindEditors() {
1290cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        if (mState.isEmpty()) {
1291cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1292cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang                Log.v(TAG, "No data to bind editors");
1293cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            }
1294cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            return false;
1295cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        }
1296cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        if (mIsEdit && !mExistingContactDataReady) {
1297cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1298cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang                Log.v(TAG, "Existing contact data is not ready to bind editors.");
1299cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            }
1300cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            return false;
1301cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        }
1302cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        if (mHasNewContact && !mNewContactDataReady) {
1303cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1304cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang                Log.v(TAG, "New contact data is not ready to bind editors.");
1305cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            }
1306cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang            return false;
1307cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        }
1308cab3dcec1401a32aff583d946b4a9f8af954358fWalter Jang        return true;
1309ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    }
1310ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang
13117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
13127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
13137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Some of old data are reused with new restriction enforced by the new account.
13147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *
13157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param oldState Old data being edited.
13167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param oldAccount Old account associated with oldState.
13177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param newAccount New account to be used.
13187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
13197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void rebindEditorsForNewContact(
13207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            RawContactDelta oldState, AccountWithDataSet oldAccount,
13217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            AccountWithDataSet newAccount) {
13227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
13237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        AccountType oldAccountType = accountTypes.getAccountTypeForAccount(oldAccount);
13247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        AccountType newAccountType = accountTypes.getAccountTypeForAccount(newAccount);
13257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1326aebf3206766a05cce290245f09506adb789b6e37Gary Mai        mExistingContactDataReady = false;
1327aebf3206766a05cce290245f09506adb789b6e37Gary Mai        mNewContactDataReady = false;
1328aebf3206766a05cce290245f09506adb789b6e37Gary Mai        mState = new RawContactDeltaList();
1329aebf3206766a05cce290245f09506adb789b6e37Gary Mai        setStateForNewContact(newAccount, newAccountType, oldState, oldAccountType,
1330aebf3206766a05cce290245f09506adb789b6e37Gary Mai                isEditingUserProfile());
1331aebf3206766a05cce290245f09506adb789b6e37Gary Mai        if (mIsEdit) {
1332698cee7d410f06b0c883c11f53481bfa5b2b787aGary Mai            setStateForExistingContact(isEditingUserProfile(), mRawContacts);
13337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
13347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
13357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
13367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
13377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // ContactEditor
13387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
13397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
13407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
13417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void setListener(Listener listener) {
13427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mListener = listener;
13437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
13447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
13457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
13467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void load(String action, Uri lookupUri, Bundle intentExtras) {
13477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAction = action;
13487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mLookupUri = lookupUri;
13497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mIntentExtras = intentExtras;
13507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
13517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mIntentExtras != null) {
13527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAutoAddToDefaultGroup =
13537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
13547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mNewLocalProfile =
13557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
13567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mDisableDeleteMenuOption =
13577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mIntentExtras.getBoolean(INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION);
13587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (mIntentExtras.containsKey(INTENT_EXTRA_MATERIAL_PALETTE_PRIMARY_COLOR)
13597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    && mIntentExtras.containsKey(INTENT_EXTRA_MATERIAL_PALETTE_SECONDARY_COLOR)) {
13607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mMaterialPalette = new MaterialColorMapUtils.MaterialPalette(
13617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        mIntentExtras.getInt(INTENT_EXTRA_MATERIAL_PALETTE_PRIMARY_COLOR),
13627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        mIntentExtras.getInt(INTENT_EXTRA_MATERIAL_PALETTE_SECONDARY_COLOR));
13637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
1364a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai            mRawContactIdToDisplayAlone = mIntentExtras
1365a6c80b378e03ebdf6b654dbdb12f2c665fe98a80Gary Mai                    .getLong(INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE);
13667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
13677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
13687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
13697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
13707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void setIntentExtras(Bundle extras) {
13715336e6ef1924162b94942cbd8f69202d553822daGary Mai        getContent().setIntentExtras(extras);
13727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
13737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
13747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
13757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onJoinCompleted(Uri uri) {
13767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri, /* joinContactId */ null);
13777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
13787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1379e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey
1380e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey    private String getNameToDisplay(Uri contactUri) {
1381e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey        final ContentResolver resolver = mContext.getContentResolver();
1382e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey        final Cursor cursor = resolver.query(contactUri, new String[]{
1383e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey                ContactsContract.Contacts.DISPLAY_NAME,
1384e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey                ContactsContract.Contacts.DISPLAY_NAME_ALTERNATIVE}, null, null, null);
1385a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai
1386a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai        if (cursor != null) {
1387a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai            try {
1388a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                if (cursor.moveToFirst()) {
1389a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                    final String displayName = cursor.getString(0);
1390a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                    final String displayNameAlt = cursor.getString(1);
1391a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                    cursor.close();
1392a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                    return ContactDisplayUtils.getPreferredDisplayName(displayName, displayNameAlt,
1393a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                            new ContactsPreferences(mContext));
1394a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai                }
1395a4adae163d83db9226b831f8c9705914e68b5cd1Gary Mai            } finally {
1396e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey                cursor.close();
1397e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey            }
1398e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey        }
1399e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey        return null;
1400e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey    }
1401e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey
1402e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey
14037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
14047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
14057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            Uri contactLookupUri, Long joinContactId) {
14067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (hadChanges) {
14077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (saveSucceeded) {
14087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                switch (saveMode) {
14097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    case SaveMode.JOIN:
14107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        break;
14117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    case SaveMode.SPLIT:
14127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        Toast.makeText(mContext, R.string.contactUnlinkedToast, Toast.LENGTH_SHORT)
14137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                                .show();
14147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        break;
14157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    default:
1416e5a140a1b60854a08a0ea0dc2068e9bf7cb058e6James Laskey                        final String displayName = getNameToDisplay(contactLookupUri);
1417b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                        final String toastMessage;
1418b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                        if (!TextUtils.isEmpty(displayName)) {
1419b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                            toastMessage = getResources().getString(
1420b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                                    R.string.contactSavedNamedToast, displayName);
1421b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                        } else {
1422b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                            toastMessage = getResources().getString(R.string.contactSavedToast);
1423b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                        }
1424b1671053e48d14f2c620f48bc5f2cd915b51a002James Laskey                        Toast.makeText(mContext, toastMessage, Toast.LENGTH_SHORT).show();
14257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
14267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
14277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            } else {
14287b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
14297b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
14307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
14317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        switch (saveMode) {
14327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case SaveMode.CLOSE: {
1433581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                Intent resultIntent = null;
14347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (saveSucceeded && contactLookupUri != null) {
14357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    final Uri lookupUri = ContactEditorUtils.maybeConvertToLegacyLookupUri(
14367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                            mContext, contactLookupUri, mLookupUri);
1437df86ede2101d902eb95838adf4176c89d9263c89Walter Jang                    if (Flags.getInstance().getBoolean(Experiments.CONTACT_SHEET)) {
1438581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                        resultIntent = ObjectFactory.getContactSheetIntent(mContext, lookupUri);
1439581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                    }
1440581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                    if (resultIntent == null) {
1441581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                        resultIntent = ImplicitIntentsUtil.composeQuickContactIntent(
1442581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                                mContext, lookupUri, ScreenType.EDITOR);
1443581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                        resultIntent.putExtra(QuickContactActivity.EXTRA_CONTACT_EDITED, true);
1444581585d9ad2e7d3d4b65798acaa0fa462d30710dWalter Jang                    }
14457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                } else {
14467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    resultIntent = null;
14477b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
14487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // It is already saved, so prevent it from being saved again
14497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mStatus = Status.CLOSING;
14507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (mListener != null) mListener.onSaveFinished(resultIntent);
14517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
14527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
1453363af60ea23e5a3b945005712a16564ab69db18bGary Mai            case SaveMode.EDITOR: {
14547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                // It is already saved, so prevent it from being saved again
14557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mStatus = Status.CLOSING;
14567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (mListener != null) mListener.onSaveFinished(/* resultIntent= */ null);
14577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
14587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
14597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case SaveMode.JOIN:
14607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (saveSucceeded && contactLookupUri != null && joinContactId != null) {
14617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    joinAggregate(joinContactId);
14627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
14637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
14647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case SaveMode.RELOAD:
14657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (saveSucceeded && contactLookupUri != null) {
14667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    // If this was in INSERT, we are changing into an EDIT now.
14677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    // If it already was an EDIT, we are changing to the new Uri now
14687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mState = new RawContactDeltaList();
14697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    load(Intent.ACTION_EDIT, contactLookupUri, null);
14707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mStatus = Status.LOADING;
14717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    getLoaderManager().restartLoader(LOADER_CONTACT, null, mContactLoaderListener);
14727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
14737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
14747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
14757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            case SaveMode.SPLIT:
14767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mStatus = Status.CLOSING;
14777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                if (mListener != null) {
14787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    mListener.onContactSplit(contactLookupUri);
14797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                } else {
14807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
14817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                }
14827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                break;
14837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
14847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
14857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
14867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
14877b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
14887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *
14897b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
14907b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
14917b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private void showJoinAggregateActivity(Uri contactLookupUri) {
14927b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (contactLookupUri == null || !isAdded()) {
14937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
14947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
14957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
14967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
14977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final Intent intent = new Intent(mContext, ContactSelectionActivity.class);
14987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        intent.setAction(UiIntentActions.PICK_JOIN_CONTACT_ACTION);
14997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, mContactIdForJoin);
15007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        startActivityForResult(intent, REQUEST_CODE_JOIN);
15017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
15027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
15047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Aggregation PopupWindow
15057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
15067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15077b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
15087b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Triggers an asynchronous search for aggregation suggestions.
15097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
15107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    protected void acquireAggregationSuggestions(Context context,
15117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            long rawContactId, ValuesDelta valuesDelta) {
15127b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mAggregationSuggestionsRawContactId != rawContactId
15137b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                && mAggregationSuggestionView != null) {
15147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionView.setVisibility(View.GONE);
15157b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionView = null;
15167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionEngine.reset();
15177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
15187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15197b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionsRawContactId = rawContactId;
15207b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mAggregationSuggestionEngine == null) {
15227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionEngine = new AggregationSuggestionEngine(context);
15237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionEngine.setListener(this);
15247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mAggregationSuggestionEngine.start();
15257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
15267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15277b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionEngine.setContactId(getContactId());
1528220d10cd7095f5ab803ff6155d7adaa576a8c4ffGary Mai        mAggregationSuggestionEngine.setAccountFilter(
1529220d10cd7095f5ab803ff6155d7adaa576a8c4ffGary Mai                getContent().getCurrentRawContactDelta().getAccountWithDataSet());
15307b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15317b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionEngine.onNameChange(valuesDelta);
15327b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
15337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
15357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
15367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
15377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private long getContactId() {
15387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        for (RawContactDelta rawContact : mState) {
15397b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
15407b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            if (contactId != null) {
15417b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                return contactId;
15427b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
15437b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
15447b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return 0;
15457b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
15467b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15473f990ba4e35a99078d831c041290e574a320caa5Walter Jang    @Override
15487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void onAggregationSuggestionChange() {
15497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final Activity activity = getActivity();
15507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if ((activity != null && activity.isFinishing())
15517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                || !isVisible() ||  mState.isEmpty() || mStatus != Status.EDITING) {
15527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
15537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
15547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        UiClosables.closeQuietly(mAggregationSuggestionPopup);
15567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) {
15587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
15597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
15607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
1561da20b47c2b85390a2c3772379e71203c5aab513cGary Mai        final View anchorView = getAggregationAnchorView();
15627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (anchorView == null) {
15637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return; // Raw contact deleted?
15647b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
15657b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup = new ListPopupWindow(mContext, null);
15667b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup.setAnchorView(anchorView);
15677b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup.setWidth(anchorView.getWidth());
15687b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
15697b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup.setAdapter(
15707b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                new AggregationSuggestionAdapter(
15717b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        getActivity(),
15727b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        /* listener =*/ this,
15737b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                        mAggregationSuggestionEngine.getSuggestions()));
15747b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
15757b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            @Override
15767b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
15777b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view;
15787b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                suggestionView.handleItemClickEvent();
15797b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                UiClosables.closeQuietly(mAggregationSuggestionPopup);
15807b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                mAggregationSuggestionPopup = null;
15817b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            }
15827b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        });
15837b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mAggregationSuggestionPopup.show();
15847b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
15857b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
15867b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
1587da20b47c2b85390a2c3772379e71203c5aab513cGary Mai     * Returns the editor view that should be used as the anchor for aggregation suggestions.
15887b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1589da20b47c2b85390a2c3772379e71203c5aab513cGary Mai    protected View getAggregationAnchorView() {
1590d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang        return getContent().getAggregationAnchorView();
1591d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang    }
1592d35e5eff8737e757a4179d49dfe9c7db999b4e9dWalter Jang
15937b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
15947b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Joins the suggested contact (specified by the id's of constituent raw
15957b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * contacts), save all changes, and stay in the editor.
15967b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
15977b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    public void doJoinSuggestedContact(long[] rawContactIds) {
15987b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!hasValidState() || mStatus != Status.EDITING) {
15997b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            return;
16007b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
16017b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
16027b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        mState.setJoinWithRawContacts(rawContactIds);
16037b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        save(SaveMode.RELOAD);
16047b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
16057b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
16067b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    @Override
1607678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai    public void onEditAction(Uri contactLookupUri, long rawContactId) {
1608678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai        SuggestionEditConfirmationDialogFragment.show(this, contactLookupUri, rawContactId);
16097b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
16107b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
16117b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
1612678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai     * Abandons the currently edited contact and switches to editing the selected raw contact,
1613678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai     * transferring all the data there
16147b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1615678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai    public void doEditSuggestedContact(Uri contactUri, long rawContactId) {
16167b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (mListener != null) {
16177b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            // make sure we don't save this contact when closing down
16187b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            mStatus = Status.CLOSING;
1619678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai            mListener.onEditOtherRawContactRequested(contactUri, rawContactId,
1620678108ebb9926a79ad0d7ac4f11417dec1583d42Gary Mai                    getContent().getCurrentRawContactDelta().getContentValues());
16217b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
16227b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
16237b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
16247b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
16257b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Sets group metadata on all bound editors.
16267b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
162792f8ccc1f15df787b7434224857c056721281046Walter Jang    protected void setGroupMetaData() {
1628f10ca15ffa550b36805d2330fc210b58601a215cWalter Jang        if (mGroupMetaData != null) {
1629f10ca15ffa550b36805d2330fc210b58601a215cWalter Jang            getContent().setGroupMetaData(mGroupMetaData);
1630f10ca15ffa550b36805d2330fc210b58601a215cWalter Jang        }
16313f990ba4e35a99078d831c041290e574a320caa5Walter Jang    }
16323f990ba4e35a99078d831c041290e574a320caa5Walter Jang
16337b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
16347b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Persist the accumulated editor deltas.
16357b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *
16367b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * @param joinContactId the raw contact ID to join the contact being saved to after the save,
16377b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     *         may be null.
16387b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
1639e3373dceb689209533e95a2cfbfbf1d9008ab6f6Walter Jang    protected boolean doSaveAction(int saveMode, Long joinContactId) {
164049ed2033f83005f92c30068ae33c3138d75e1825Walter Jang        final Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
164149ed2033f83005f92c30068ae33c3138d75e1825Walter Jang                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
164249ed2033f83005f92c30068ae33c3138d75e1825Walter Jang                ((Activity) mContext).getClass(),
1643363af60ea23e5a3b945005712a16564ab69db18bGary Mai                ContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos,
1644e3373dceb689209533e95a2cfbfbf1d9008ab6f6Walter Jang                JOIN_CONTACT_ID_EXTRA_KEY, joinContactId);
1645dd7d456a080f48d93aa3a9f9b04da0f17a8833a7Wenyi Wang        return startSaveService(mContext, intent, saveMode);
164649ed2033f83005f92c30068ae33c3138d75e1825Walter Jang    }
164749ed2033f83005f92c30068ae33c3138d75e1825Walter Jang
16487b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    private boolean startSaveService(Context context, Intent intent, int saveMode) {
16497b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        final boolean result = ContactSaveService.startService(
16507b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang                context, intent, saveMode);
16517b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        if (!result) {
16527b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang            onCancelEditConfirmed();
16537b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        }
16547b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang        return result;
16557b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    }
16567b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
16577b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
16587b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    // Join Activity
16597b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    //
16607b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang
16617b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang    /**
16627b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
16637b0970fd1db1a97f1be915d66d07f4dc8499f96dWalter Jang     */
166449ed2033f83005f92c30068ae33c3138d75e1825Walter Jang    protected void joinAggregate(final long contactId) {
166549ed2033f83005f92c30068ae33c3138d75e1825Walter Jang        final Intent intent = ContactSaveService.createJoinContactsIntent(
1666363af60ea23e5a3b945005712a16564ab69db18bGary Mai                mContext, mContactIdForJoin, contactId, ContactEditorActivity.class,
1667363af60ea23e5a3b945005712a16564ab69db18bGary Mai                ContactEditorActivity.ACTION_JOIN_COMPLETED);
166849ed2033f83005f92c30068ae33c3138d75e1825Walter Jang        mContext.startService(intent);
16693f990ba4e35a99078d831c041290e574a320caa5Walter Jang    }
1670b6ca272f26b47ecef8fafe94326c4d553576c521Walter Jang
167131a74ad969b650eb733e536569254ed3978c4f54Walter Jang    public void removePhoto() {
167231a74ad969b650eb733e536569254ed3978c4f54Walter Jang        getContent().removePhoto();
167331a74ad969b650eb733e536569254ed3978c4f54Walter Jang        mUpdatedPhotos.remove(String.valueOf(mPhotoRawContactId));
16740e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang    }
16750e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang
167631a74ad969b650eb733e536569254ed3978c4f54Walter Jang    public void updatePhoto(Uri uri) throws FileNotFoundException {
167731a74ad969b650eb733e536569254ed3978c4f54Walter Jang        final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(getActivity(), uri);
167831a74ad969b650eb733e536569254ed3978c4f54Walter Jang        if (bitmap == null || bitmap.getHeight() <= 0 || bitmap.getWidth() <= 0) {
16799bc9ba878cf7f77a2a6b3200a6ab716d13f1affcWenyi Wang            Toast.makeText(mContext, R.string.contactPhotoSavedErrorToast,
168031a74ad969b650eb733e536569254ed3978c4f54Walter Jang                    Toast.LENGTH_SHORT).show();
168131a74ad969b650eb733e536569254ed3978c4f54Walter Jang            return;
16820e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang        }
168331a74ad969b650eb733e536569254ed3978c4f54Walter Jang        mUpdatedPhotos.putParcelable(String.valueOf(mPhotoRawContactId), uri);
168431a74ad969b650eb733e536569254ed3978c4f54Walter Jang        getContent().updatePhoto(uri);
16850e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang    }
16860e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang
1687da20b47c2b85390a2c3772379e71203c5aab513cGary Mai    public void setPrimaryPhoto() {
1688da20b47c2b85390a2c3772379e71203c5aab513cGary Mai        getContent().setPrimaryPhoto();
16890e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang    }
16900e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang
16910e72ce9d97e0133a5f7cc348eef363bef9395979Walter Jang    @Override
1692151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang    public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta) {
1693151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang        final Activity activity = getActivity();
1694151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang        if (activity == null || activity.isFinishing()) {
1695151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang            return;
1696151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang        }
169745b86d5e83a7d6eca4abe5cdfece2e9050b1809cWalter Jang        acquireAggregationSuggestions(activity, rawContactId, valuesDelta);
1698151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang    }
1699151f3e6883e5785019f7b5083dc8baf3e305dc18Walter Jang
17005a7a23bdb698b8e741a425c9617c5e33e6314cddWalter Jang    @Override
1701708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang    public void onRebindEditorsForNewContact(RawContactDelta oldState,
1702708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang            AccountWithDataSet oldAccount, AccountWithDataSet newAccount) {
1703708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang        mNewContactAccountChanged = true;
1704708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang        mAccountWithDataSet = newAccount;
1705708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang        rebindEditorsForNewContact(oldState, oldAccount, newAccount);
1706708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang    }
1707708ea9e6f6f671178c0424f89e911000d4f330dcWalter Jang
170879658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang    @Override
170979658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang    public void onBindEditorsFailed() {
171079658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang        final Activity activity = getActivity();
171179658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang        if (activity != null && !activity.isFinishing()) {
1712363af60ea23e5a3b945005712a16564ab69db18bGary Mai            Toast.makeText(activity, R.string.editor_failed_to_load,
171379658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang                    Toast.LENGTH_SHORT).show();
171479658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang            activity.setResult(Activity.RESULT_CANCELED);
171579658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang            activity.finish();
171679658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang        }
171779658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang    }
171879658e14360a4ec75530a9dcae338f48c9d5f043Walter Jang
1719d675315606e8be431e6e5487e0b1cc33036a6ed7Walter Jang    @Override
1720d675315606e8be431e6e5487e0b1cc33036a6ed7Walter Jang    public void onEditorsBound() {
17213cb77bbf7119749ed4854a4b981fcabcf55823beWenyi Wang        final Activity activity = getActivity();
17223cb77bbf7119749ed4854a4b981fcabcf55823beWenyi Wang        if (activity == null || activity.isFinishing()) {
17233cb77bbf7119749ed4854a4b981fcabcf55823beWenyi Wang            return;
17243cb77bbf7119749ed4854a4b981fcabcf55823beWenyi Wang        }
1725d675315606e8be431e6e5487e0b1cc33036a6ed7Walter Jang        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupsLoaderListener);
1726d675315606e8be431e6e5487e0b1cc33036a6ed7Walter Jang    }
1727d675315606e8be431e6e5487e0b1cc33036a6ed7Walter Jang
172831a74ad969b650eb733e536569254ed3978c4f54Walter Jang    @Override
172931a74ad969b650eb733e536569254ed3978c4f54Walter Jang    public void onPhotoEditorViewClicked() {
17303f18d6197a54aad10bea9c5cc2c89ca82809e793Walter Jang        // For contacts composed of a single writable raw contact, or raw contacts have no more
17313f18d6197a54aad10bea9c5cc2c89ca82809e793Walter Jang        // than 1 photo, clicking the photo view simply opens the source photo dialog
173231a74ad969b650eb733e536569254ed3978c4f54Walter Jang        getEditorActivity().changePhoto(getPhotoMode());
173331a74ad969b650eb733e536569254ed3978c4f54Walter Jang    }
173431a74ad969b650eb733e536569254ed3978c4f54Walter Jang
173531a74ad969b650eb733e536569254ed3978c4f54Walter Jang    private int getPhotoMode() {
1736da20b47c2b85390a2c3772379e71203c5aab513cGary Mai        return getContent().isWritablePhotoSet() ? PhotoActionPopup.Modes.WRITE_ABLE_PHOTO
1737da20b47c2b85390a2c3772379e71203c5aab513cGary Mai                : PhotoActionPopup.Modes.NO_PHOTO;
173831a74ad969b650eb733e536569254ed3978c4f54Walter Jang    }
173931a74ad969b650eb733e536569254ed3978c4f54Walter Jang
1740363af60ea23e5a3b945005712a16564ab69db18bGary Mai    private ContactEditorActivity getEditorActivity() {
1741363af60ea23e5a3b945005712a16564ab69db18bGary Mai        return (ContactEditorActivity) getActivity();
174231a74ad969b650eb733e536569254ed3978c4f54Walter Jang    }
174331a74ad969b650eb733e536569254ed3978c4f54Walter Jang
1744363af60ea23e5a3b945005712a16564ab69db18bGary Mai    private RawContactEditorView getContent() {
1745363af60ea23e5a3b945005712a16564ab69db18bGary Mai        return (RawContactEditorView) mContent;
17463efae4aeae8715fbfcf67c56f123da49330ea01aWalter Jang    }
17473f990ba4e35a99078d831c041290e574a320caa5Walter Jang}
1748