ContactEditorFragment.java revision b55107303cc46906c265582a8931172f13d684b6
1cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann/*
2ef3f8f045ed4150caa64749742227acd0e6b85d8Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project
3cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
4cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * you may not use this file except in compliance with the License.
6cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * You may obtain a copy of the License at
7cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
8cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
10cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * See the License for the specific language governing permissions and
14cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * limitations under the License
15cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */
16cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
19cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity;
20bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.AlertDialog;
21bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.Dialog;
22bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.DialogFragment;
23cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
24cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
25bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface;
26cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
27f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
28cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
29cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
3091004b37683c15650eccde68ff04defcf94a1c84Maurice Chuimport android.provider.ContactsContract.CommonDataKinds.Photo;
31f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
32688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Leeimport android.text.TextUtils;
33cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log;
34cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater;
35cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View;
36cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup;
37d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.AdapterView;
386c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.AdapterView.OnItemClickListener;
396c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawaimport android.widget.BaseAdapter;
4080d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
41d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.ListPopupWindow;
42cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
43cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
44e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.ContactSaveService;
45e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
46e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ContactEditorActivity;
473f990ba4e35a99078d831c041290e574a320caa5Walter Jangimport com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor;
4844cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.AccountTypeManager;
4992101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContactDelta;
5092101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContactDeltaList;
5192101e77238e450dedb56814cec80edc0adf79c0Walter Jangimport com.android.contacts.common.model.RawContactModifier;
5244cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.ValuesDelta;
5344cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.AccountType;
5444cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.model.account.AccountWithDataSet;
5544cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.util.AccountsListAdapter;
5644cfc56d1701629070384364416c1311b780535dChiao Chengimport com.android.contacts.common.util.AccountsListAdapter.AccountListFilter;
57e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.detail.PhotoSelectionHandler;
58e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
59e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.editor.Editor.EditorListener;
60c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwellimport com.android.contacts.list.UiIntentActions;
61e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.ContactPhotoUtils;
6286625158bdc52855c37e96bf098ba7a213c810d7Chiao Chengimport com.android.contacts.util.UiClosables;
6392101e77238e450dedb56814cec80edc0adf79c0Walter Jang
64851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.google.common.collect.ImmutableList;
6544cfc56d1701629070384364416c1311b780535dChiao Chengimport com.google.common.collect.Lists;
66e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
67637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Leeimport java.io.FileNotFoundException;
68f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
69daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwellimport java.util.HashMap;
70f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
71f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
723f990ba4e35a99078d831c041290e574a320caa5Walter Jang/**
733f990ba4e35a99078d831c041290e574a320caa5Walter Jang * Contact editor with all fields displayed.
743f990ba4e35a99078d831c041290e574a320caa5Walter Jang */
753f990ba4e35a99078d831c041290e574a320caa5Walter Jangpublic class ContactEditorFragment extends ContactEditorBaseFragment implements
763f990ba4e35a99078d831c041290e574a320caa5Walter Jang        ContactEditor, SplitContactConfirmationDialogFragment.Listener,
77fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
782b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann        RawContactReadOnlyEditorView.Listener {
79cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
80cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Joins
81cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
82cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
83cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
84daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    private static final String KEY_EXPANDED_EDITORS = "expandedEditors";
85f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
86cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Photos
87cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
88cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_CURRENT_PHOTO_URI = "currentphotouri";
89cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_UPDATED_PHOTOS = "updatedPhotos";
90cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
91cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    // Aggregations
92cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang    private static final String KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID =
93cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            "aggregationSuggestionsRawContactId";
94cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
95a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
96a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
97fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
98fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Helpers
99fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
100fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private AggregationSuggestionEngine mAggregationSuggestionEngine;
101cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
102fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
103fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Contact editor state
104fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    //
105fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Joins
106fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private long mContactIdForJoin;
107fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private boolean mContactWritableForJoin;
108fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
109fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Used to store which raw contact editors have been expanded. Keyed on raw contact ids.
110fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private HashMap<Long, Boolean> mExpandedEditors = new HashMap<Long, Boolean>();
111fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang
112fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Photos
113fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    /**
114fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * The raw contact for which we started "take photo" or "choose photo from gallery" most
115fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * recently.  Used to restore {@link #mCurrentPhotoHandler} after orientation change.
116fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     */
117fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private long mRawContactIdRequestingPhoto;
11844cfc56d1701629070384364416c1311b780535dChiao Cheng
119fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    /**
120fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * The {@link PhotoHandler} for the photo editor for the {@link #mRawContactIdRequestingPhoto}
121fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * raw contact.
122fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     *
123fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * A {@link PhotoHandler} is created for each photo editor in {@link #bindPhotoHandler}, but
124fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * the only "active" one should get the activity result.  This member represents the active
125fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     * one.
126fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang     */
127fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private PhotoHandler mCurrentPhotoHandler;
128fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Uri mCurrentPhotoUri;
129fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    private Bundle mUpdatedPhotos = new Bundle();
130daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
131fb5dc6f857104c38ff49993d7498e8aa5fbc462eWalter Jang    // Aggregations
1329302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private long mAggregationSuggestionsRawContactId;
1339302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private View mAggregationSuggestionView;
1346c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private ListPopupWindow mAggregationSuggestionPopup;
1356c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1366c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private static final class AggregationSuggestionAdapter extends BaseAdapter {
1376c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final Activity mActivity;
1386c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final boolean mSetNewContact;
1396c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final AggregationSuggestionView.Listener mListener;
1406c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        private final List<Suggestion> mSuggestions;
1416c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1426c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public AggregationSuggestionAdapter(Activity activity, boolean setNewContact,
1436c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                AggregationSuggestionView.Listener listener, List<Suggestion> suggestions) {
1446c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mActivity = activity;
1456c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSetNewContact = setNewContact;
1466c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mListener = listener;
1476c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mSuggestions = suggestions;
1486c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
1496c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1506c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
1516c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public View getView(int position, View convertView, ViewGroup parent) {
1526c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            Suggestion suggestion = (Suggestion) getItem(position);
1536c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            LayoutInflater inflater = mActivity.getLayoutInflater();
1546c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            AggregationSuggestionView suggestionView =
1556c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                    (AggregationSuggestionView) inflater.inflate(
1566c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                            R.layout.aggregation_suggestions_item, null);
1576c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setNewContact(mSetNewContact);
1586c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.setListener(mListener);
1596c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.bindSuggestion(suggestion);
1606c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return suggestionView;
1616c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
1626c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1636c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
1646c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public long getItemId(int position) {
1656c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return position;
1666c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
1676c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1686c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
1696c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public Object getItem(int position) {
1706c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.get(position);
1716c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
1726c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1736c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
1746c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public int getCount() {
1756c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            return mSuggestions.size();
1766c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
1776c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    }
1786c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
1796c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    private OnItemClickListener mAggregationSuggestionItemClickListener =
1806c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            new OnItemClickListener() {
1816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        @Override
1826c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
1836c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            final AggregationSuggestionView suggestionView = (AggregationSuggestionView) view;
1846c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            suggestionView.handleItemClickEvent();
18586625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng            UiClosables.closeQuietly(mAggregationSuggestionPopup);
1866c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa            mAggregationSuggestionPopup = null;
1876c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        }
1886c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa    };
1896c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa
190cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
191cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
192cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
193b55107303cc46906c265582a8931172f13d684b6Walter Jang
194b55107303cc46906c265582a8931172f13d684b6Walter Jang    @Override
195b55107303cc46906c265582a8931172f13d684b6Walter Jang    protected void setEnabled(boolean enabled) {
196b55107303cc46906c265582a8931172f13d684b6Walter Jang        if (mContent != null) {
197b55107303cc46906c265582a8931172f13d684b6Walter Jang            int count = mContent.getChildCount();
198b55107303cc46906c265582a8931172f13d684b6Walter Jang            for (int i = 0; i < count; i++) {
199b55107303cc46906c265582a8931172f13d684b6Walter Jang                mContent.getChildAt(i).setEnabled(enabled);
20002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
20102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
202b55107303cc46906c265582a8931172f13d684b6Walter Jang        setAggregationSuggestionViewEnabled(enabled);
203b55107303cc46906c265582a8931172f13d684b6Walter Jang        final Activity activity = getActivity();
204b55107303cc46906c265582a8931172f13d684b6Walter Jang        if (activity != null) activity.invalidateOptionsMenu();
20502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
20602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
207cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
208f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onStop() {
209f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super.onStop();
21086625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng
21186625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng        UiClosables.closeQuietly(mAggregationSuggestionPopup);
21286625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng
213825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If anything was left unsaved, save it now but keep the editor open.
214f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
215623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            save(SaveMode.RELOAD);
216825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
217f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
218f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
219f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
22036184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    public void onDestroy() {
22136184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        super.onDestroy();
22236184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        if (mAggregationSuggestionEngine != null) {
22336184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee            mAggregationSuggestionEngine.quit();
22436184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee        }
22536184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    }
22636184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee
22736184f630cdb97d0a642de25f69962ef2abfedb1Yorke Lee    @Override
228cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
229cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
230cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
231f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
232e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
2333648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
234cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
235cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
236cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
237cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
238222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
239e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    public void onStart() {
240e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
241e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        super.onStart();
242e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
243e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
2443f990ba4e35a99078d831c041290e574a320caa5Walter Jang    @Override
245f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
246f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
247f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
248ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang        if (savedState != null) {
249cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Joins
250cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
251cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
252cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
253daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            mExpandedEditors = (HashMap<Long, Boolean>)
254daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                    savedState.getSerializable(KEY_EXPANDED_EDITORS);
255cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
256cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Photos
257cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mRawContactIdRequestingPhoto = savedState.getLong(
258cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
259cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI);
260cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
261cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
262cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            // Aggregations
263cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang            mAggregationSuggestionsRawContactId = savedState.getLong(
264cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                    KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID);
26544cfc56d1701629070384364416c1311b780535dChiao Cheng        }
266fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
267fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
268fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    @Override
2692b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro    public void onExternalEditorRequest(AccountWithDataSet account, Uri uri) {
270fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        mListener.onCustomEditContactActivityRequested(account, uri, null, false);
271fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
272fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
273daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    @Override
274daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    public void onEditorExpansionChanged() {
275daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        updatedExpandedEditorsMap();
276daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    }
277daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
278ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    @Override
2791ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    public void setIntentExtras(Bundle extras) {
2801ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        if (extras == null || extras.size() == 0) {
2811ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            return;
282bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
283916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
284a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
285851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        for (RawContactDelta state : mState) {
286851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = state.getAccountType(accountTypes);
28796e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (type.areContactsWritable()) {
2881ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                // Apply extras to the first writable raw contact only
289851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactModifier.parseExtras(mContext, type, state, extras);
2901ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                break;
2911ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            }
2921ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        }
293f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
294cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
295d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
296d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
297d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Some of old data are reused with new restriction enforced by the new account.
298d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
2992b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro     * @param oldState Old data being edited.
300d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param oldAccount Old account associated with oldState.
301d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param newAccount New account to be used.
302d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
303d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void rebindEditorsForNewContact(
304851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDelta oldState, AccountWithDataSet oldAccount,
305851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            AccountWithDataSet newAccount) {
306d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
30767e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner        AccountType oldAccountType = accountTypes.getAccountTypeForAccount(oldAccount);
30867e83223e954ed54898daa5e32400dbff6d3831aJay Shrauner        AccountType newAccountType = accountTypes.getAccountTypeForAccount(newAccount);
309d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
310d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccountType.getCreateContactActivityClassName() != null) {
311d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            Log.w(TAG, "external activity called in rebind situation");
312d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            if (mListener != null) {
313d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
314d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
315d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
31644cfc56d1701629070384364416c1311b780535dChiao Cheng            mExistingContactDataReady = false;
31744cfc56d1701629070384364416c1311b780535dChiao Cheng            mNewContactDataReady = false;
31844cfc56d1701629070384364416c1311b780535dChiao Cheng            mState = new RawContactDeltaList();
319b55107303cc46906c265582a8931172f13d684b6Walter Jang            setStateForNewContact(newAccount, newAccountType, oldState, oldAccountType);
32044cfc56d1701629070384364416c1311b780535dChiao Cheng            if (mIsEdit) {
321b55107303cc46906c265582a8931172f13d684b6Walter Jang                setStateForExistingContact(mDefaultDisplayName, mIsUserProfile, mRawContacts);
32244cfc56d1701629070384364416c1311b780535dChiao Cheng            }
323d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
324d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
325d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
326ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    @Override
327ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    protected void bindEditors() {
3285671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        // bindEditors() can only bind views if there is data in mState, so immediately return
3295671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        // if mState is null
33044cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
33144cfc56d1701629070384364416c1311b780535dChiao Cheng            return;
33244cfc56d1701629070384364416c1311b780535dChiao Cheng        }
33344cfc56d1701629070384364416c1311b780535dChiao Cheng
33444cfc56d1701629070384364416c1311b780535dChiao Cheng        // Check if delta list is ready.  Delta list is populated from existing data and when
33544cfc56d1701629070384364416c1311b780535dChiao Cheng        // editing an read-only contact, it's also populated with newly created data for the
33644cfc56d1701629070384364416c1311b780535dChiao Cheng        // blank form.  When the data is not ready, skip. This method will be called multiple times.
33744cfc56d1701629070384364416c1311b780535dChiao Cheng        if ((mIsEdit && !mExistingContactDataReady) || (mHasNewContact && !mNewContactDataReady)) {
3385671c7e7718c3285dc0391807401083986fcfd51Maurice Chu            return;
3395671c7e7718c3285dc0391807401083986fcfd51Maurice Chu        }
3405671c7e7718c3285dc0391807401083986fcfd51Maurice Chu
341f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
342f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
343cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
344f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
345f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
346cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
347f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
348f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
349a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
350a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        int numRawContacts = mState.size();
35144cfc56d1701629070384364416c1311b780535dChiao Cheng
352a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        for (int i = 0; i < numRawContacts; i++) {
353f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
354851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta rawContactDelta = mState.get(i);
355851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if (!rawContactDelta.isVisible()) continue;
356f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
357851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = rawContactDelta.getAccountType(accountTypes);
358851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final long rawContactId = rawContactDelta.getRawContactId();
359f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
36072af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            final BaseRawContactEditorView editor;
3612b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann            if (!type.areContactsWritable()) {
362fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                editor = (BaseRawContactEditorView) inflater.inflate(
3632b3ee0f34801444c7d775ce747125459f69712bbDaniel Lehmann                        R.layout.raw_contact_readonly_editor_view, mContent, false);
364fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            } else {
365fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view,
366fd70903236883f47b21f23b8cb49a1ccacdfcdf1Katherine Kuan                        mContent, false);
367cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
368daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            editor.setListener(this);
369daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(mContext)
370daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                    .getAccounts(true);
371daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            if (mHasNewContact && !mNewLocalProfile && accounts.size() > 1) {
372daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                addAccountSwitcher(mState.get(0), editor);
373d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
374a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan
375b55107303cc46906c265582a8931172f13d684b6Walter Jang            editor.setEnabled(isEnabled());
376cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
377daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            if (mExpandedEditors.containsKey(rawContactId)) {
378daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                editor.setCollapsed(mExpandedEditors.get(rawContactId));
379daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            } else {
380daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                // By default, only the first editor will be expanded.
381daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                editor.setCollapsed(i != 0);
382daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            }
383daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
384f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
3857d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
386851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile());
387daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            editor.setCollapsible(numRawContacts > 1);
388f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
3896fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            // Set up the photo handler.
3906fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            bindPhotoHandler(editor, type, mState);
3916fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
392c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            // If a new photo was chosen but not yet saved, we need to update the UI to
393c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            // reflect this.
394c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            final Uri photoUri = updatedPhotoUriForRawContact(rawContactId);
395c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            if (photoUri != null) editor.setFullSizedPhoto(photoUri);
39628eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
39772af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (editor instanceof RawContactEditorView) {
3982828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                final Activity activity = getActivity();
39972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
4005ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                EditorListener listener = new EditorListener() {
401f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
402f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
403f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    public void onRequest(int request) {
4042828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                        if (activity.isFinishing()) { // Make sure activity is still running.
4052828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                            return;
4062828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                        }
4072bbfae8f92d5c218c83a49621a4c8f98f4d7a394Isaac Katzenelson                        if (request == EditorListener.FIELD_CHANGED && !isEditingUserProfile()) {
4082828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                            acquireAggregationSuggestions(activity, rawContactEditor);
409d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                        } else if (request == EditorListener.EDITOR_FOCUS_CHANGED) {
410d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                            adjustNameFieldsHintDarkness(rawContactEditor);
41111bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                        }
412f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
413f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
414f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
4152293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                    public void onDeleteRequested(Editor removedEditor) {
416f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
4175ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                };
4185ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov
41944cfc56d1701629070384364416c1311b780535dChiao Cheng                final StructuredNameEditorView nameEditor = rawContactEditor.getNameEditor();
4205ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                if (mRequestFocus) {
4215ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    nameEditor.requestFocus();
4225ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    mRequestFocus = false;
4235ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                }
4245ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                nameEditor.setEditorListener(listener);
425688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                if (!TextUtils.isEmpty(mDefaultDisplayName)) {
426688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                    nameEditor.setDisplayName(mDefaultDisplayName);
427688c228b2d7cf0c812fb673451f24e7cb457d63bYorke Lee                }
428f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
4295ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView phoneticNameEditor =
4305ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                        rawContactEditor.getPhoneticNameEditor();
4315ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                phoneticNameEditor.setEditorListener(listener);
4327d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
4337d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
434d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                final TextFieldsEditorView nickNameEditor =
435d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                        rawContactEditor.getNickNameEditor();
436d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                nickNameEditor.setEditorListener(listener);
437d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell
4389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (rawContactId == mAggregationSuggestionsRawContactId) {
4392828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki                    acquireAggregationSuggestions(activity, rawContactEditor);
440f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
441d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell
442d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                adjustNameFieldsHintDarkness(rawContactEditor);
443f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
444cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
445f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
446eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = false;
447eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
448b55107303cc46906c265582a8931172f13d684b6Walter Jang        setGroupMetaData();
449e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
450f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
451f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
452a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
453a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        // Refresh Action Bar as the visibility of the join command
454825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Activity can be null if we have been detached from the Activity
455825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        final Activity activity = getActivity();
456825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (activity != null) activity.invalidateOptionsMenu();
457daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
458daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        updatedExpandedEditorsMap();
459daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    }
460daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell
461daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    /**
462d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     * Adjust how dark the hint text should be on all the names' text fields.
463d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     *
464d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     * @param rawContactEditor editor to update
465d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell     */
466d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell    private void adjustNameFieldsHintDarkness(RawContactEditorView rawContactEditor) {
467d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        // Check whether fields contain focus by calling findFocus() instead of hasFocus().
468d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        // The hasFocus() value is not necessarily up to date.
469d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        final boolean nameFieldsAreNotFocused
470d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                = rawContactEditor.getNameEditor().findFocus() == null
471d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                && rawContactEditor.getPhoneticNameEditor().findFocus() == null
472d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell                && rawContactEditor.getNickNameEditor().findFocus() == null;
473d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        rawContactEditor.getNameEditor().setHintColorDark(!nameFieldsAreNotFocused);
474d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        rawContactEditor.getPhoneticNameEditor().setHintColorDark(!nameFieldsAreNotFocused);
475d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell        rawContactEditor.getNickNameEditor().setHintColorDark(!nameFieldsAreNotFocused);
476d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell    }
477d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell
478d690dff231dd5a81b9bd7563838455f24e49c75cBrian Attwell    /**
479daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell     * Update the values in {@link #mExpandedEditors}.
480daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell     */
481daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell    private void updatedExpandedEditorsMap() {
482daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        for (int i = 0; i < mContent.getChildCount(); i++) {
483daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            final View childView = mContent.getChildAt(i);
484daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            if (childView instanceof BaseRawContactEditorView) {
485daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                BaseRawContactEditorView childEditor = (BaseRawContactEditorView) childView;
486daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                mExpandedEditors.put(childEditor.getRawContactId(), childEditor.isCollapsed());
487daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            }
488daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        }
4896fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    }
490eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
49128eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    /**
492c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell     * If we've stashed a temporary file containing a contact's new photo, return its URI.
49328eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus     * @param rawContactId identifies the raw-contact whose Bitmap we'll try to return.
494c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell     * @return Uru of photo for specified raw-contact, or null
495c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell     */
496c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell    private Uri updatedPhotoUriForRawContact(long rawContactId) {
497c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell        return (Uri) mUpdatedPhotos.get(String.valueOf(rawContactId));
49828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus    }
49928eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
5006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private void bindPhotoHandler(BaseRawContactEditorView editor, AccountType type,
501851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDeltaList state) {
5026fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        final int mode;
5037e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell        final boolean showIsPrimaryOption;
5046fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        if (type.areContactsWritable()) {
5056fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            if (editor.hasSetPhoto()) {
5067e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                mode = PhotoActionPopup.Modes.WRITE_ABLE_PHOTO;
5077e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                showIsPrimaryOption = hasMoreThanOnePhoto();
5086fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            } else {
509ced983d7a816256d93fdea1f81e63e4598c18875Josh Gargus                mode = PhotoActionPopup.Modes.NO_PHOTO;
5107e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                showIsPrimaryOption = false;
5116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
5127e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell        } else if (editor.hasSetPhoto() && hasMoreThanOnePhoto()) {
5137e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            mode = PhotoActionPopup.Modes.READ_ONLY_PHOTO;
5147e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            showIsPrimaryOption = true;
5156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        } else {
5167e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            // Read-only and either no photo or the only photo ==> no options
5177e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            editor.getPhotoEditor().setEditorListener(null);
5187e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            editor.getPhotoEditor().setShowPrimary(false);
5197e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            return;
5206fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        }
52191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        final PhotoHandler photoHandler = new PhotoHandler(mContext, editor, mode, state);
5226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        editor.getPhotoEditor().setEditorListener(
52391004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                (PhotoHandler.PhotoEditorListener) photoHandler.getListener());
5247e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell        editor.getPhotoEditor().setShowPrimary(showIsPrimaryOption);
5254bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki
5264bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        // Note a newly created raw contact gets some random negative ID, so any value is valid
5274bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        // here. (i.e. don't check against -1 or anything.)
5284bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        if (mRawContactIdRequestingPhoto == editor.getRawContactId()) {
5294bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mCurrentPhotoHandler = photoHandler;
5304bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        }
531cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
532cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
5330353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    private void saveDefaultAccountIfNecessary() {
5340353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Verify that this is a newly created contact, that the contact is composed of only
5350353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // 1 raw contact, and that the contact is not a user profile.
5360353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        if (!Intent.ACTION_INSERT.equals(mAction) && mState.size() == 1 &&
5370353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                !isEditingUserProfile()) {
5380353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan            return;
5390353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        }
5400353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
5410353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Find the associated account for this contact (retrieve it here because there are
5420353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // multiple paths to creating a contact and this ensures we always have the correct
5430353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // account).
544851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        final RawContactDelta rawContactDelta = mState.get(0);
545851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String name = rawContactDelta.getAccountName();
546851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String type = rawContactDelta.getAccountType();
547851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu        String dataSet = rawContactDelta.getDataSet();
5480353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
5490353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        AccountWithDataSet account = (name == null || type == null) ? null :
5500353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                new AccountWithDataSet(name, type, dataSet);
5510353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        mEditorUtils.saveDefaultAndAllAccounts(account);
5520353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan    }
5530353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
554d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void addAccountSwitcher(
555851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta currentState, BaseRawContactEditorView editor) {
5562b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro        final AccountWithDataSet currentAccount = new AccountWithDataSet(
557851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getAccountName(),
558851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getAccountType(),
559851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                currentState.getDataSet());
560d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final View accountView = editor.findViewById(R.id.account);
561daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        final View anchorView = editor.findViewById(R.id.account_selector_container);
562daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        if (accountView == null) {
563daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell            return;
564daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        }
565daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        anchorView.setVisibility(View.VISIBLE);
566d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        accountView.setOnClickListener(new View.OnClickListener() {
567d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            @Override
568d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            public void onClick(View v) {
569d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                final ListPopupWindow popup = new ListPopupWindow(mContext, null);
570a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                final AccountsListAdapter adapter =
5716f74c0f3313cbb08ee8a8fbb79bfefc5b03fe215Makoto Onuki                        new AccountsListAdapter(mContext,
5726f74c0f3313cbb08ee8a8fbb79bfefc5b03fe215Makoto Onuki                        AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, currentAccount);
573d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setWidth(anchorView.getWidth());
574d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAnchorView(anchorView);
575d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAdapter(adapter);
576d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setModal(true);
577d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
578d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
579d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    @Override
580d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    public void onItemClick(AdapterView<?> parent, View view, int position,
581d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            long id) {
58286625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng                        UiClosables.closeQuietly(popup);
5832b3f3c54d3beb017b2f59f19e9ce0ecc3e039dbcDave Santoro                        AccountWithDataSet newAccount = adapter.getItem(position);
584d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        if (!newAccount.equals(currentAccount)) {
585d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            rebindEditorsForNewContact(currentState, currentAccount, newAccount);
586d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        }
587d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    }
588d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                });
589d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.show();
590d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
591d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        });
592d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
593d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
594b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
595b55107303cc46906c265582a8931172f13d684b6Walter Jang    protected boolean doSaveAction(int saveMode) {
5960353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Store account as default account, only if this is a new contact
5970353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        saveDefaultAccountIfNecessary();
5980353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan
5990353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan        // Save contact
600ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus        Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
601ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
602ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
603ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus                mUpdatedPhotos);
604ebc17929007ecf12f25b8e90023766e8a083d11eJosh Gargus        mContext.startService(intent);
60587270e1b58e669354bb1571ced686421c56deb7aJosh Gargus
60687270e1b58e669354bb1571ced686421c56deb7aJosh Gargus        // Don't try to save the same photos twice.
60787270e1b58e669354bb1571ced686421c56deb7aJosh Gargus        mUpdatedPhotos = new Bundle();
60887270e1b58e669354bb1571ced686421c56deb7aJosh Gargus
609f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
610f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
611f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
612ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    @Override
6132b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    public void onJoinCompleted(Uri uri) {
61436d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri);
6152b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    }
6162b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov
617ba59deb669cf377bedf08af53c9196db3c1cc404Walter Jang    @Override
61836d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro    public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
61936d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            Uri contactLookupUri) {
620a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (hadChanges) {
62136d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro            if (saveSucceeded) {
622a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                if (saveMode != SaveMode.JOIN) {
623a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                    Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
624a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                }
625a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else {
626a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
627a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            }
628a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        }
629f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
63015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.CLOSE:
6319df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            case SaveMode.HOME:
632f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
63336d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                if (saveSucceeded && contactLookupUri != null) {
6343f990ba4e35a99078d831c041290e574a320caa5Walter Jang                    final Uri lookupUri = maybeConvertToLegacyLookupUri(
6353f990ba4e35a99078d831c041290e574a320caa5Walter Jang                            mContext, contactLookupUri, mLookupUri);
6363f990ba4e35a99078d831c041290e574a320caa5Walter Jang                    resultIntent = composeQuickContactsIntent(mContext, lookupUri);
637f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
638f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
639f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
640825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                // It is already saved, so prevent that it is saved again
641825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                mStatus = Status.CLOSING;
6425649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                if (mListener != null) mListener.onSaveFinished(resultIntent);
643f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
644a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
64515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.RELOAD:
646dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov            case SaveMode.JOIN:
64736d24d7ede42a252c82c4aa783b2231c5e2eea79Dave Santoro                if (saveSucceeded && contactLookupUri != null) {
648623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    // If it was a JOIN, we are now ready to bring up the join activity.
649e813f5e56ddc6395c5e08e9245e2c5ad41e91724Daniel Lehmann                    if (saveMode == SaveMode.JOIN && hasValidState()) {
650623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                        showJoinAggregateActivity(contactLookupUri);
651623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    }
652623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann
65315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If this was in INSERT, we are changing into an EDIT now.
65415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If it already was an EDIT, we are changing to the new Uri now
65544cfc56d1701629070384364416c1311b780535dChiao Cheng                    mState = new RawContactDeltaList();
6561015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov                    load(Intent.ACTION_EDIT, contactLookupUri, null);
657825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    mStatus = Status.LOADING;
65815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
65915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                }
66015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                break;
661a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
66215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.SPLIT:
663a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                mStatus = Status.CLOSING;
664a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                if (mListener != null) {
6658c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov                    mListener.onContactSplit(contactLookupUri);
666a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                } else {
667a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
668a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                }
669f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
670f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
671f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
672f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
673f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
674f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
675f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
676f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
677f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
678f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
67973a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov        if (contactLookupUri == null || !isAdded()) {
680f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
681f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
682f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
683f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
684623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        mContactWritableForJoin = isContactWritable();
685c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell        final Intent intent = new Intent(UiIntentActions.PICK_JOIN_CONTACT_ACTION);
686c3d202ccbaf93ddd8291672027e59f549c32eee3Brian Attwell        intent.putExtra(UiIntentActions.TARGET_CONTACT_ID_EXTRA_KEY, mContactIdForJoin);
687a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        startActivityForResult(intent, REQUEST_CODE_JOIN);
688f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
689f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
690f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
691f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
692f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
693f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
6942b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
695623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                contactId, mContactWritableForJoin,
6962b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
6972b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        mContext.startService(intent);
698f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
699f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
700f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
701ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     * Returns true if there is at least one writable raw contact in the current contact.
702ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     */
703ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    private boolean isContactWritable() {
704a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
705ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        int size = mState.size();
706ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        for (int i = 0; i < size; i++) {
707851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            RawContactDelta entity = mState.get(i);
708851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final AccountType type = entity.getAccountType(accountTypes);
70996e87fd6e808e9d853263ffeb5104f3253a18639Daniel Lehmann            if (type.areContactsWritable()) {
710ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov                return true;
711ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            }
712ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        }
713ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        return false;
714ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    }
715ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov
716f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
717f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
718f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
719f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected long getContactId() {
72044cfc56d1701629070384364416c1311b780535dChiao Cheng        for (RawContactDelta rawContact : mState) {
72144cfc56d1701629070384364416c1311b780535dChiao Cheng            Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
72244cfc56d1701629070384364416c1311b780535dChiao Cheng            if (contactId != null) {
72344cfc56d1701629070384364416c1311b780535dChiao Cheng                return contactId;
724f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
725f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
726f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return 0;
727f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
728f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
729f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
730f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Triggers an asynchronous search for aggregation suggestions.
731f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
7322828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki    private void acquireAggregationSuggestions(Context context,
7332828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki            RawContactEditorView rawContactEditor) {
7349302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        long rawContactId = rawContactEditor.getRawContactId();
7359302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (mAggregationSuggestionsRawContactId != rawContactId
7369302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                && mAggregationSuggestionView != null) {
7379302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
7389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView = null;
7399302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionEngine.reset();
7409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
7419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
7429302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionsRawContactId = rawContactId;
7439302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
744f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine == null) {
7452828c48cc4537fe981918f80297d5408bedc87b5Makoto Onuki            mAggregationSuggestionEngine = new AggregationSuggestionEngine(context);
746f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.setListener(this);
747f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.start();
748f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
749f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
750916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        mAggregationSuggestionEngine.setContactId(getContactId());
751916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
752392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        LabeledEditorView nameEditor = rawContactEditor.getNameEditor();
753f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mAggregationSuggestionEngine.onNameChange(nameEditor.getValues());
754f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
755f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
756f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
757f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onAggregationSuggestionChange() {
758288532cddfccdc3793dd748d1c75750e2f46cb53Yorke Lee        Activity activity = getActivity();
759288532cddfccdc3793dd748d1c75750e2f46cb53Yorke Lee        if ((activity != null && activity.isFinishing())
76044cfc56d1701629070384364416c1311b780535dChiao Cheng                || !isVisible() ||  mState.isEmpty() || mStatus != Status.EDITING) {
76102cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov            return;
76202cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov        }
76302cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov
76486625158bdc52855c37e96bf098ba7a213c810d7Chiao Cheng        UiClosables.closeQuietly(mAggregationSuggestionPopup);
765f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
7666c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        if (mAggregationSuggestionEngine.getSuggestedContactCount() == 0) {
767f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
768f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
769f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
7706c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final RawContactEditorView rawContactView =
7716c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
77202a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        if (rawContactView == null) {
77302a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki            return; // Raw contact deleted?
77402a54ebd3185948e2c1c0f39b7718cb9abaea934Makoto Onuki        }
7756c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        final View anchorView = rawContactView.findViewById(R.id.anchor_view);
7766c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup = new ListPopupWindow(mContext, null);
7776c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAnchorView(anchorView);
7786c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setWidth(anchorView.getWidth());
7796c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
7806c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setAdapter(
7816c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                new AggregationSuggestionAdapter(getActivity(),
7826c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        mState.size() == 1 && mState.get(0).isContactInsert(),
7836c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa                        this, mAggregationSuggestionEngine.getSuggestions()));
7846c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.setOnItemClickListener(mAggregationSuggestionItemClickListener);
7856c8c0777c823e2a2fef69299c0b36ca4a40e1feaDaisuke Miyakawa        mAggregationSuggestionPopup.show();
786bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
787bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
788bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
789bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
790bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        long rawContactIds[] = new long[rawContactIdList.size()];
791bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        for (int i = 0; i < rawContactIds.length; i++) {
792bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            rawContactIds[i] = rawContactIdList.get(i);
793bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
794bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        JoinSuggestedContactDialogFragment dialog =
795bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new JoinSuggestedContactDialogFragment();
796bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
797bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putLongArray("rawContactIds", rawContactIds);
798bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
799bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
80074f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        try {
80174f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            dialog.show(getFragmentManager(), "join");
80274f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        } catch (Exception ex) {
80374f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            // No problem - the activity is no longer available to display the dialog
80474f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        }
805bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
806bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
807bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
808bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
809bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
810bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
811bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
8124292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
813bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
814bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
815bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
816f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            @Override
817bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
818bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
819bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
820bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                long rawContactIds[] =
821bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getLongArray("rawContactIds");
822bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doJoinSuggestedContact(rawContactIds);
823bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
824bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
825bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
826bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
827bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
828bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
829bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
830bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
831bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
832bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Joins the suggested contact (specified by the id's of constituent raw
833bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * contacts), save all changes, and stay in the editor.
834bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
835bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doJoinSuggestedContact(long[] rawContactIds) {
836cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
837cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov            return;
838cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        }
839cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov
840bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mState.setJoinWithRawContacts(rawContactIds);
8419df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.RELOAD);
842bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
843bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
844bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
845bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onEditAction(Uri contactLookupUri) {
846bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        SuggestionEditConfirmationDialogFragment dialog =
847bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new SuggestionEditConfirmationDialogFragment();
848bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
849bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putParcelable("contactUri", contactLookupUri);
850bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
851bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
852bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.show(getFragmentManager(), "edit");
853bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
854bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
855bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
856bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
857bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
858bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
859bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
8604292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
861bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
862bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
863bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
864f30723782e801deaf159aea2443e9507596ef11dDaniel Lehmann                            @Override
865bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
866bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
867bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
868bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                Uri contactUri =
869bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getParcelable("contactUri");
870bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doEditSuggestedContact(contactUri);
871bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
872bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
873bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
874bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
875bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
876bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
877bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
878bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
879bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
880bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Abandons the currently edited contact and switches to editing the suggested
881bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * one, transferring all the data there
882bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
883bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doEditSuggestedContact(Uri contactUri) {
884bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        if (mListener != null) {
885a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            // make sure we don't save this contact when closing down
886a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            mStatus = Status.CLOSING;
887bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            mListener.onEditOtherContactRequested(
888bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    contactUri, mState.get(0).getContentValues());
889bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
890bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
891bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
892a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    public void setAggregationSuggestionViewEnabled(boolean enabled) {
893a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (mAggregationSuggestionView == null) {
894a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            return;
895a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
896a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
897a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
898a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov                R.id.aggregation_suggestions);
899a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        int count = itemList.getChildCount();
900a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        for (int i = 0; i < count; i++) {
901a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            itemList.getChildAt(i).setEnabled(enabled);
902a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
903a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    }
904a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
905f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
906f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
907cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Joins
908cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
909cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
910cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
911daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell        outState.putSerializable(KEY_EXPANDED_EDITORS, mExpandedEditors);
912cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
913cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Photos
914cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
915cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelable(KEY_CURRENT_PHOTO_URI, mCurrentPhotoUri);
916cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
917cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
918cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        // Aggregations
919cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang        outState.putLong(KEY_AGGREGATION_SUGGESTIONS_RAW_CONTACT_ID,
920cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang                mAggregationSuggestionsRawContactId);
921cf718aa47c11453925bb20f7970ca7c897f6e376Walter Jang
922f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
923f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
924f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
925d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
926f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
927f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (mStatus == Status.SUB_ACTIVITY) {
928f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.EDITING;
929f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        }
930f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
9316fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        // See if the photo selection handler handles this result.
93291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        if (mCurrentPhotoHandler != null && mCurrentPhotoHandler.handlePhotoActivityResult(
9336fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                requestCode, resultCode, data)) {
9346fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            return;
9356fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        }
936f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
9376fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        switch (requestCode) {
938a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_JOIN: {
9390353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                // Ignore failed requests
9400353a24d97cc0266eb9bf0ee6c7d6821aeb1896eKatherine Kuan                if (resultCode != Activity.RESULT_OK) return;
941f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
942f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
943f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
944f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
9454a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                break;
946f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
947ed8f6c9744dd38e089598acfba6fb90446954e6eWalter Jang            default: {
948ed8f6c9744dd38e089598acfba6fb90446954e6eWalter Jang                super.onActivityResult(requestCode, resultCode, data);
949d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell                break;
950d257a90e1a9a439da44a97d328c3a933d54f2caeBrian Attwell            }
951f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
952cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
9539cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
954c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    /**
955c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
956c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     */
957637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee    private void setPhoto(long rawContact, Bitmap photo, Uri photoUri) {
958bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
959e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
960e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus        if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) {
961e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus            // This is unexpected.
962e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus            Log.w(TAG, "Invalid bitmap passed to setPhoto()");
963e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus        }
964e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
9659302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestingEditor != null) {
966c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell            requestingEditor.setPhotoEntry(photo);
9677e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            // Immediately set all other photos as non-primary. Otherwise the UI can display
9687e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            // multiple photos as "Primary photo".
9697e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            for (int i = 0; i < mContent.getChildCount(); i++) {
9707e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                final View childView = mContent.getChildAt(i);
9717e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                if (childView instanceof BaseRawContactEditorView
9727e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                        && childView != requestingEditor) {
9737e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                    final BaseRawContactEditorView rawContactEditor
9747e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                            = (BaseRawContactEditorView) childView;
9757e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                    rawContactEditor.getPhotoEditor().setSuperPrimary(false);
9767e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                }
9777e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            }
9789302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        } else {
9799302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            Log.w(TAG, "The contact that requested the photo is no longer present.");
9809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
981e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus
982637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        mUpdatedPhotos.putParcelable(String.valueOf(rawContact), photoUri);
9839302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
9849302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
9859302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    /**
9869302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     * Finds raw contact editor view for the given rawContactId.
9879302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     */
988bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
989c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        for (int i = 0; i < mContent.getChildCount(); i++) {
990c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            final View childView = mContent.getChildAt(i);
99172af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
99272af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
9939302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (editor.getRawContactId() == rawContactId) {
9949302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    return editor;
995c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                }
996c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
997c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        }
9989302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return null;
999c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    }
1000c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1001fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
1002fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     * Returns true if there is currently more than one photo on screen.
1003fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1004fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    private boolean hasMoreThanOnePhoto() {
1005fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int countWithPicture = 0;
100691004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        final int numEntities = mState.size();
100791004b37683c15650eccde68ff04defcf94a1c84Maurice Chu        for (int i = 0; i < numEntities; i++) {
1008851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            final RawContactDelta entity = mState.get(i);
1009851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu            if (entity.isVisible()) {
101091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                final ValuesDelta primary = entity.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
1011851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                if (primary != null && primary.getPhoto() != null) {
1012fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    countWithPicture++;
101391004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                } else {
1014851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                    final long rawContactId = entity.getRawContactId();
1015637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                    final Uri uri = mUpdatedPhotos.getParcelable(String.valueOf(rawContactId));
1016637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                    if (uri != null) {
1017637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                        try {
1018637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                            mContext.getContentResolver().openInputStream(uri);
101991004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                            countWithPicture++;
1020637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                        } catch (FileNotFoundException e) {
102191004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                        }
102291004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                    }
102391004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                }
102491004b37683c15650eccde68ff04defcf94a1c84Maurice Chu
102591004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                if (countWithPicture > 1) {
102691004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                    return true;
1027fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
1028fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1029fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1030fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        return false;
10319cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1032222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1033a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    @Override
1034a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    public void onSplitContactConfirmed() {
103544cfc56d1701629070384364416c1311b780535dChiao Cheng        if (mState.isEmpty()) {
1036b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // This may happen when this Fragment is recreated by the system during users
1037b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // confirming the split action (and thus this method is called just before onCreate()),
1038b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            // for example.
1039b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            Log.e(TAG, "mState became null during the user's confirming split action. " +
1040b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa                    "Cannot perform the save action.");
1041b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa            return;
1042b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa        }
1043b9e60280603f2fa57083c13952e4b25e2585b833Daisuke Miyakawa
1044a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        mState.markRawContactsForSplitting();
10459df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.SPLIT);
1046a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    }
1047a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
10486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    /**
10496fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * Custom photo handler for the editor.  The inner listener that this creates also has a
10506fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * reference to the editor and acts as an {@link EditorListener}, and uses that editor to hold
10516fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     * state information in several of the listener methods.
10526fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro     */
10536fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro    private final class PhotoHandler extends PhotoSelectionHandler {
105428eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
105528eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus        final long mRawContactId;
1056e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        private final BaseRawContactEditorView mEditor;
10574bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki        private final PhotoActionListener mPhotoEditorListener;
105828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
10596fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode,
1060851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu                RawContactDeltaList state) {
10617e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            super(context, editor.getPhotoEditor().getChangeAnchorView(), photoMode, false, state);
1062e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            mEditor = editor;
106328eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus            mRawContactId = editor.getRawContactId();
10649a409d474b2b4f2e4261657f864eeb866fcb8816Daniel Lehmann            mPhotoEditorListener = new PhotoEditorListener();
1065e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        }
1066e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus
1067e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        @Override
1068e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        public PhotoActionListener getListener() {
10699a409d474b2b4f2e4261657f864eeb866fcb8816Daniel Lehmann            return mPhotoEditorListener;
1070e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        }
1071e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus
1072e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus        @Override
1073637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee        public void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) {
10744bff8fb686f2ac5500109a32cca9270965c620d6Makoto Onuki            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
107591004b37683c15650eccde68ff04defcf94a1c84Maurice Chu            mCurrentPhotoHandler = this;
1076e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            mStatus = Status.SUB_ACTIVITY;
1077637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            mCurrentPhotoUri = photoUri;
1078e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus            ContactEditorFragment.this.startActivityForResult(intent, requestCode);
10799442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
10809442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
10816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro        private final class PhotoEditorListener extends PhotoSelectionHandler.PhotoActionListener
10826fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                implements EditorListener {
1083fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
10846fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
10856fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onRequest(int request) {
10866fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (!hasValidState()) return;
1087a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
10886fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                if (request == EditorListener.REQUEST_PICK_PHOTO) {
10896fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    onClick(mEditor.getPhotoEditor());
10909442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                }
10917e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                if (request == EditorListener.REQUEST_PICK_PRIMARY_PHOTO) {
10927e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                    useAsPrimaryChosen();
10937e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell                }
10949442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
1095a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
10966fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
10976fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onDeleteRequested(Editor removedEditor) {
10986fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // The picture cannot be deleted, it can only be removed, which is handled by
10996fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // onRemovePictureChosen()
11006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
1101a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
11026fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            /**
11036fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             * User has chosen to set the selected photo as the (super) primary photo
11046fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             */
11057e67082d3f7c4ab56945040c0e4617b71c7e5f0bBrian Attwell            public void useAsPrimaryChosen() {
11066fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Set the IsSuperPrimary for each editor
11076fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                int count = mContent.getChildCount();
11086fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                for (int i = 0; i < count; i++) {
11096fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    final View childView = mContent.getChildAt(i);
11106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    if (childView instanceof BaseRawContactEditorView) {
11116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        final BaseRawContactEditorView editor =
11126fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                                (BaseRawContactEditorView) childView;
11136fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        final PhotoEditorView photoEditor = editor.getPhotoEditor();
11146fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                        photoEditor.setSuperPrimary(editor == mEditor);
11156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                    }
11166fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                }
111791004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
11186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
11199442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
11206fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            /**
11216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             * User has chosen to remove a picture
11226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro             */
11236fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
11246fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onRemovePictureChosen() {
1125c300521331c04767cd19dfe05ab77567514bbaa0Brian Attwell                mEditor.setPhotoEntry(null);
112628eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus
112728eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                // Prevent bitmap from being restored if rotate the device.
112828eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                // (only if we first chose a new photo before removing it)
112928eadab78531e22a0d9fa22fbbcd61c451005890Josh Gargus                mUpdatedPhotos.remove(String.valueOf(mRawContactId));
113091004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
11316fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
11326fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
11336fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
1134637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            public void onPhotoSelected(Uri uri) throws FileNotFoundException {
1135637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(mContext, uri);
1136637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                setPhoto(mRawContactId, bitmap, uri);
113791004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                mCurrentPhotoHandler = null;
113891004b37683c15650eccde68ff04defcf94a1c84Maurice Chu                bindEditors();
11396fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
11406fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
11416fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
1142637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee            public Uri getCurrentPhotoUri() {
1143637a38ec9de6b1f434d7a13105f2e747faae5107Yorke Lee                return mCurrentPhotoUri;
11446fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            }
11456fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro
11466fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            @Override
11476fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro            public void onPhotoSelectionDismissed() {
11486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro                // Nothing to do.
11499442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
11504a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        }
11514a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann    }
11522ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1153