ContactEditorFragment.java revision c863b0171f2a54a0ee71b34b33034aeea2464cca
1cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann/*
2ef3f8f045ed4150caa64749742227acd0e6b85d8Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project
3cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
4cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License");
5cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * you may not use this file except in compliance with the License.
6cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * You may obtain a copy of the License at
7cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
8cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *      http://www.apache.org/licenses/LICENSE-2.0
9cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann *
10cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Unless required by applicable law or agreed to in writing, software
11cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS,
12cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * See the License for the specific language governing permissions and
14cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * limitations under the License
15cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */
16cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor;
18cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1918ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.ContactLoader;
2018ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.ContactSaveService;
2118ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.GroupMetaDataLoader;
22cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.R;
232b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport com.android.contacts.activities.ContactEditorActivity;
24d21ddb2c96e71f43eaf7addc25e163181d1ca87dDmitri Plotnikovimport com.android.contacts.activities.JoinContactActivity;
2518ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
2618ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.Editor.EditorListener;
274597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport com.android.contacts.model.AccountType;
28a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikovimport com.android.contacts.model.AccountTypeManager;
29f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityDelta;
30f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityDelta.ValuesDelta;
31ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmannimport com.android.contacts.model.EntityDeltaList;
32f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityModifier;
3335769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmannimport com.android.contacts.model.GoogleAccountType;
34f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
35f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account;
36cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity;
37bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.AlertDialog;
38bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.Dialog;
39bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.DialogFragment;
40222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.Fragment;
41222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager;
42222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
43cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ActivityNotFoundException;
44cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
45cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues;
46cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
47e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader;
48bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface;
49e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikovimport android.content.Entity;
50cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader;
52f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor;
53f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
54f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.graphics.Rect;
55f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.media.MediaScannerConnection;
56cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
57cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
58f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.Environment;
599767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock;
60f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.provider.ContactsContract;
61cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
62362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Event;
63362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Note;
64362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Organization;
65cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
6641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName;
67362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
68362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website;
69f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
702013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmannimport android.provider.ContactsContract.Intents;
71f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
72f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.MediaStore;
7341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikovimport android.text.TextUtils;
74cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log;
75cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater;
76cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu;
77cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater;
78cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem;
79cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View;
80cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup;
81f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.view.ViewGroup.LayoutParams;
82bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.view.ViewGroup.MarginLayoutParams;
83f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.view.ViewStub;
8480d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
85cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
86cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
87f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File;
88f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.text.SimpleDateFormat;
89cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList;
90f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
91f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator;
92f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Date;
93f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
95a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmannpublic class ContactEditorFragment extends Fragment implements
969442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        SplitContactConfirmationDialogFragment.Listener, SelectAccountDialogFragment.Listener,
97fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
98fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        ExternalRawContactEditorView.Listener {
99cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
100cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private static final String TAG = "ContactEditorFragment";
101cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int LOADER_DATA = 1;
103e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private static final int LOADER_GROUPS = 2;
104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
105d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_URI = "uri";
106d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_ACTION = "action";
107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_EDIT_STATE = "state";
108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
1129302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions";
11302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private static final String KEY_ENABLED = "enabled";
114ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov    private static final String KEY_STATUS = "status";
115f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
116a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
117a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
11815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    /**
1197d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * An intent extra that forces the editor to add the edited contact
1207d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * to the default group (e.g. "My Contacts").
1217d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     */
1227d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
1237d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
1247d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    /**
12515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     * Modes that specify what the AsyncTask has to perform after saving
12615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     */
1279df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public interface SaveMode {
12815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
12915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Close the editor after saving
13015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
13115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int CLOSE = 0;
13215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
13315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
13415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Reload the data so that the user can continue editing
13515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
13615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int RELOAD = 1;
13715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
13815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
13915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Split the contact after saving
14015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int SPLIT = 2;
14215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
14315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
14415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Join another contact after saving
14515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int JOIN = 3;
1479df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov
1489df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        /**
1499df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         * Navigate to Contacts Home activity after saving.
1509df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         */
1519df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        public static final int HOME = 4;
15215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    }
153a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
154825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private interface Status {
155825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
156825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * The loader is fetching data
157825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
158825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int LOADING = 0;
159825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
160825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
161825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * Not currently busy. We are waiting for the user to enter data
162825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
163825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int EDITING = 1;
164825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
165825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
166f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * The data is currently being saved. This is used to prevent more
167f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * auto-saves (they shouldn't overlap)
168825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
169825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int SAVING = 2;
170825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
171825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
172f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * Prevents any more savings (this is used if Save/Close or Revert was
173f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * executed by the user)
174825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
175825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int CLOSING = 3;
176f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
177f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        /**
178f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * Prevents saving while running a child activity.
179f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         */
180f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        public static final int SUB_ACTIVITY = 4;
181825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    }
182825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
183a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_JOIN = 0;
184a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1;
185a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 2;
186f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
187c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private Bitmap mPhoto = null;
188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mRawContactIdRequestingPhoto = -1;
189c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private long mRawContactIdRequestingPhotoAfterLoad = -1;
190cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
191f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
192f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
193f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int ICON_SIZE = 96;
194f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final File PHOTO_DIR = new File(
196f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Environment.getExternalStorageDirectory() + "/DCIM/Camera");
197f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
198e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private Cursor mGroupMetaData;
199e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
200f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
201f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * A delay in milliseconds used for bringing aggregation suggestions to
202f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * the visible part of the screen. The reason this has to be done after
203f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * a delay is a race condition with the soft keyboard.  The keyboard
204f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * may expand to display its own autocomplete suggestions, which will
205f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * reduce the visible area of the screen.  We will yield to the keyboard
206f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * hoping that the delay is sufficient.  If not - part of the
207f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * suggestion will be hidden, which is not fatal.
208f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
209f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTION_SCROLL_DELAY = 200;
210f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
211f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private File mCurrentPhotoFile;
212cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
213cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Context mContext;
214f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mAction;
215b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann    private Uri mLookupUri;
216f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Bundle mIntentExtras;
217cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Listener mListener;
218cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
219f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mContactIdForJoin;
220cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
221f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private LinearLayout mContent;
222ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    private EntityDeltaList mState;
223cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
224f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
225cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2269767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann    private long mLoaderStartTime;
2279767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann
228825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private int mStatus;
229825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
230f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private AggregationSuggestionEngine mAggregationSuggestionEngine;
2319302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private long mAggregationSuggestionsRawContactId;
2329302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private View mAggregationSuggestionView;
233f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
2347d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    private boolean mAutoAddToDefaultGroup;
2357d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
23602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private boolean mEnabled = true;
23702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
238cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
239cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
240cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
24102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public void setEnabled(boolean enabled) {
24202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mEnabled != enabled) {
24302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = enabled;
24402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (mContent != null) {
24502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                int count = mContent.getChildCount();
24602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                for (int i = 0; i < count; i++) {
24702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                    mContent.getChildAt(i).setEnabled(enabled);
24802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                }
24902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
250a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            setAggregationSuggestionViewEnabled(enabled);
25102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            final Activity activity = getActivity();
25202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (activity != null) activity.invalidateOptionsMenu();
25302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
25402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
25502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
256cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
257cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public void onAttach(Activity activity) {
258cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        super.onAttach(activity);
259cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        mContext = activity;
260cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
261cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
262cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
263f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onStop() {
264f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super.onStop();
265f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine != null) {
266f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.quit();
267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
268248fba273e867616b1f8973dac6ce3e5ee1ba544Dmitri Plotnikov
269825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If anything was left unsaved, save it now but keep the editor open.
270f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
2719df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            save(SaveMode.RELOAD);
272825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
276cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
277cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
278cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
279f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
280e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
2813648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
282cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
283825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If we are in an orientation change, we already have mState (it was loaded by onCreate)
284825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (mState != null) {
285825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            bindEditors();
286825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
287825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
288cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
289cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
290cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
291222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
292222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    public void onActivityCreated(Bundle savedInstanceState) {
293222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        super.onActivityCreated(savedInstanceState);
294222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
295825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")");
296222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
297825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Handle initial actions only when existing state missing
2984a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        final boolean hasIncomingState = savedInstanceState != null;
299825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
300825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (!hasIncomingState) {
301825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            if (Intent.ACTION_EDIT.equals(mAction)) {
302825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit);
303825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
304825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            } else if (Intent.ACTION_INSERT.equals(mAction)) {
305825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert);
306825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
3072013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                final Account account = mIntentExtras == null ? null :
3082013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    (Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT);
3092013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann
3102013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                if (account != null) {
3112013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // Account specified in Intent
31240bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    createContact(account);
3132013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                } else {
3142013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // No Account specified. Let the user choose
31540bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    // Load Accounts async so that we can present them
31640bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    selectAccountAndCreateContact();
3172013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                }
318a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else if (ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(mAction)) {
319a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                // do nothing
320825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            } else throw new IllegalArgumentException("Unknown Action String " + mAction +
321825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
322825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
323222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    }
324222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
325e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    @Override
326e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    public void onStart() {
327e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
328e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        super.onStart();
329e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
330e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
3311015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov    public void load(String action, Uri lookupUri, Bundle intentExtras) {
332f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mAction = action;
333b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        mLookupUri = lookupUri;
334f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mIntentExtras = intentExtras;
3357d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov        mAutoAddToDefaultGroup = mIntentExtras != null
3367d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                && mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
337f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
338f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
339f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void setListener(Listener value) {
340f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mListener = value;
341cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
342cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
343cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
344f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
345d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        if (savedState != null) {
346d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // Restore mUri before calling super.onCreate so that onInitializeLoaders
347d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // would already have a uri and an action to work with
348b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            mLookupUri = savedState.getParcelable(KEY_URI);
349d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mAction = savedState.getString(KEY_ACTION);
350d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        }
351d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
352f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
353f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
354f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (savedState == null) {
355f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // If savedState is non-null, onRestoreInstanceState() will restore the generator.
356f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = new ViewIdGenerator();
357f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
358825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            // Read state from savedState. No loading involved here
359ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
360f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mRawContactIdRequestingPhoto = savedState.getLong(
361f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
362f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
363f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE);
364f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (fileName != null) {
365f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                mCurrentPhotoFile = new File(fileName);
366cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
367f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
3689302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS);
36902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = savedState.getBoolean(KEY_ENABLED);
370ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov            mStatus = savedState.getInt(KEY_STATUS);
371cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
372cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
373cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
374bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann    public void setData(ContactLoader.Result data) {
375d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        // If we have already loaded data, we do not want to change it here to not confuse the user
376d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        if (mState != null) {
377d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            Log.v(TAG, "Ignoring background change. This will have to be rebased later");
378d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            return;
379d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        }
380d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann
381fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        // See if this edit operation needs to be redirected to a custom editor
382fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        ArrayList<Entity> entities = data.getEntities();
383fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        if (entities.size() == 1) {
384fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            Entity entity = entities.get(0);
385fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            ContentValues entityValues = entity.getEntityValues();
386fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
387a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov            AccountType accountType = AccountTypeManager.getInstance(mContext).getAccountType(type);
388fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (accountType.getEditContactActivityClassName() != null) {
389fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                if (mListener != null) {
390fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    String name = entityValues.getAsString(RawContacts.ACCOUNT_NAME);
391fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
392fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    mListener.onCustomEditContactActivityRequested(new Account(name, type),
393fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
394fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            mIntentExtras, true);
395fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                }
396fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                return;
397fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
398fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
399fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
400fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        bindEditorsForExistingContact(data);
401fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
402fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
403fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    @Override
404fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    public void onExternalEditorRequest(Account account, Uri uri) {
405fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        mListener.onCustomEditContactActivityRequested(account, uri, null, false);
406fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
407fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
408fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    private void bindEditorsForExistingContact(ContactLoader.Result data) {
40902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        setEnabled(true);
41002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
411a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        mState = EntityDeltaList.fromIterator(data.getEntities().iterator());
4121ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        setIntentExtras(mIntentExtras);
4131ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        mIntentExtras = null;
414e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov
4151ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        bindEditors();
4161ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    }
4171ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov
4181ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    /**
4191ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     * Merges extras from the intent.
4201ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     */
4211ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    public void setIntentExtras(Bundle extras) {
4221ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        if (extras == null || extras.size() == 0) {
4231ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            return;
424bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
425916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
426a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
4271ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        for (EntityDelta state : mState) {
4281ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
429b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type = accountTypes.getAccountType(accountType);
43069f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (!type.readOnly) {
4311ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                // Apply extras to the first writable raw contact only
43269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                EntityModifier.parseExtras(mContext, type, state, extras);
4331ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                break;
4341ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            }
4351ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        }
436f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
437cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
43840bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov    private void selectAccountAndCreateContact() {
439a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final ArrayList<Account> accounts =
440a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov                AccountTypeManager.getInstance(mContext).getAccounts(true);
441f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // No Accounts available.  Create a phone-local contact.
442f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (accounts.isEmpty()) {
44340bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov            createContact(null);
444f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;  // Don't show a dialog.
445f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
446cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
447f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // In the common case of a single account being writable, auto-select
448f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // it without showing a dialog.
449f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (accounts.size() == 1) {
45040bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov            createContact(accounts.get(0));
451f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;  // Don't show a dialog.
452f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
453f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
45440bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov        final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment();
4554a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.setTargetFragment(this, 0);
4564a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
457cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
458cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
459cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    /**
460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param account may be null to signal a device-local contact should
461f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *     be created.
462cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann     */
46340bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov    private void createContact(Account account) {
464a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
465b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        final AccountType accountType =
466b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                accountTypes.getAccountType(account != null ? account.type : null);
467fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
468b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        if (accountType.getCreateContactActivityClassName() != null) {
469fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (mListener != null) {
470fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                mListener.onCustomCreateContactActivityRequested(account, mIntentExtras);
471fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
472fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        } else {
473b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            bindEditorsForNewContact(account, accountType);
474fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
475fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
476fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
47769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov    private void bindEditorsForNewContact(Account account, final AccountType accountType) {
478a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        mStatus = Status.EDITING;
479a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
480f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ContentValues values = new ContentValues();
481f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (account != null) {
482f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.put(RawContacts.ACCOUNT_NAME, account.name);
483f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.put(RawContacts.ACCOUNT_TYPE, account.type);
484f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
485f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_NAME);
486f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_TYPE);
487cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
488cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
489f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Parse any values from incoming intent
490f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
49169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.parseExtras(mContext, accountType, insert, mIntentExtras);
492f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
49369f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        // Ensure we have some default fields (if the account type does not support a field,
494362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmann        // ensureKind will not add it, so it is safe to add e.g. Event)
49569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, Phone.CONTENT_ITEM_TYPE);
49669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, Email.CONTENT_ITEM_TYPE);
49769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, Note.CONTENT_ITEM_TYPE);
49869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, Organization.CONTENT_ITEM_TYPE);
49969f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, Event.CONTENT_ITEM_TYPE);
50069f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, Website.CONTENT_ITEM_TYPE);
50169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        EntityModifier.ensureKindExists(insert, accountType, StructuredPostal.CONTENT_ITEM_TYPE);
502f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
503f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mState == null) {
504f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Create state if none exists yet
505ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = EntityDeltaList.fromSingle(insert);
506f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
507f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add contact onto end of existing state
508f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mState.add(insert);
509cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
510f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
511f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
512cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
513cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
514f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void bindEditors() {
515f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
516f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
517cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
518f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
519f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
520cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
521f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
522f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
523a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
524f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int size = mState.size();
525f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        for (int i = 0; i < size; i++) {
526f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
527f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final EntityDelta entity = mState.get(i);
528f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ValuesDelta values = entity.getValues();
529f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!values.isVisible()) continue;
530f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
531f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
532b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type = accountTypes.getAccountType(accountType);
533f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final long rawContactId = values.getAsLong(RawContacts._ID);
534f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
53572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            final BaseRawContactEditorView editor;
53669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (type.isExternal()) {
537fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                editor = (BaseRawContactEditorView) inflater.inflate(
538fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                        R.layout.external_raw_contact_editor_view, mContent, false);
539fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                ((ExternalRawContactEditorView) editor).setListener(this);
540fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            } else {
541f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann                editor = (BaseRawContactEditorView)
542f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann                        inflater.inflate(R.layout.raw_contact_editor_view, mContent, false);
543cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
54402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            editor.setEnabled(mEnabled);
545cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
546f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
5477d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
54869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            editor.setState(entity, type, mViewIdGenerator);
549f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
5509442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            editor.getPhotoEditor().setEditorListener(
55169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                    new PhotoEditorListener(editor, type.readOnly));
55272af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (editor instanceof RawContactEditorView) {
55372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
554392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann                final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor();
555f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                nameEditor.setEditorListener(new EditorListener() {
556f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
557f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
558f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    public void onRequest(int request) {
55941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                        onContactNameChange(request, rawContactEditor, nameEditor);
560f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
561f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
562f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
5634a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                    public void onDeleted(Editor removedEditor) {
564f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
565f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                });
566f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
5677d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
5687d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
5699302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (rawContactId == mAggregationSuggestionsRawContactId) {
570f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    acquireAggregationSuggestions(rawContactEditor);
571f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
572f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
573cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
574f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
575e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        bindGroupMetaData();
576e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
577f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
578f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
579a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
580a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        // Refresh Action Bar as the visibility of the join command
581825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Activity can be null if we have been detached from the Activity
582825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        final Activity activity = getActivity();
583825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (activity != null) activity.invalidateOptionsMenu();
584cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
585cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
586e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private void bindGroupMetaData() {
587e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        if (mGroupMetaData == null) {
588e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            return;
589e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
590e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
591e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        int editorCount = mContent.getChildCount();
592e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        for (int i = 0; i < editorCount; i++) {
59372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i);
594e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            editor.setGroupMetaData(mGroupMetaData);
595e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
596e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
597e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
598b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
599eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
600f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        inflater.inflate(R.menu.edit, menu);
601cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
602cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
603b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
604eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onPrepareOptionsMenu(Menu menu) {
605f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1);
60602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        int size = menu.size();
60702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        for (int i = 0; i < size; i++) {
60802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            menu.getItem(i).setEnabled(mEnabled);
60902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
610cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
611cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
612b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
613cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public boolean onOptionsItemSelected(MenuItem item) {
614cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (item.getItemId()) {
615f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_done:
6169df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                return save(SaveMode.CLOSE);
617f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_discard:
618d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                return revert();
619f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_delete:
620f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doDeleteAction();
621f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_split:
622f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSplitContactAction();
623f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_join:
624f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doJoinContactAction();
625f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
626f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
627f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
628cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
629f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
630f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Delete the entire contact currently being edited, which usually asks for
631f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * user confirmation before continuing.
632f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
633f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doDeleteAction() {
634f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState())
635f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
636cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
637b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        // TODO: Make sure Insert turns into Edit if/once it is autosaved
638b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        if (Intent.ACTION_INSERT.equals(mAction)) {
639b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            if (mListener != null) mListener.onReverted();
640cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        } else {
641b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            if (mListener != null) mListener.onDeleteRequested(mLookupUri);
642cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
643f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
644f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
645f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
646f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSplitContactAction() {
647f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
648f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
649a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        final SplitContactConfirmationDialogFragment dialog =
6504a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                new SplitContactConfirmationDialogFragment();
6514a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.setTargetFragment(this, 0);
6524a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG);
653f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
654f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
655f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
656f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doJoinContactAction() {
6574c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        if (!hasValidState()) {
6584c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov            return false;
6594c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
6604c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
6614c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // If we just started creating a new contact and haven't added any data, it's too
6624c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // early to do a join
663a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
664a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (mState.size() == 1 && mState.get(0).isContactInsert()
665a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                && !EntityModifier.hasChanges(mState, accountTypes)) {
666a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact,
667a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                            Toast.LENGTH_LONG).show();
668a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            return true;
6694c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
6704c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
6719df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        return save(SaveMode.JOIN);
672f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
673f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
674f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
675f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap.
676f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
677f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getPhotoPickIntent() {
678f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
679f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setType("image/*");
680f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
681f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
682f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
683f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputX", ICON_SIZE);
684f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputY", ICON_SIZE);
685f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
686f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
687f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
688f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
689f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
690f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Check if our internal {@link #mState} is valid, usually checked before
691f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * performing user actions.
692f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
693f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean hasValidState() {
694f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return mState != null && mState.size() > 0;
695f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
696f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
697f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
698f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Create a file name for the icon photo using current time.
699f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
700f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String getPhotoFileName() {
701f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Date date = new Date(System.currentTimeMillis());
702f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
703f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return dateFormat.format(date) + ".jpg";
704f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
705f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
706f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
707f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for capturing a photo and storing it in a temporary file.
708f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
709f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getTakePickIntent(File f) {
710f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
711f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
712f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
713f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
714f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
715f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
716f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Sends a newly acquired photo to Gallery for cropping
717f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
718f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    protected void doCropPhoto(File f) {
719f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
720f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add the image to the media store
721f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            MediaScannerConnection.scanFile(
722f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mContext,
723f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { f.getAbsolutePath() },
724f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { null },
725f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    null);
726f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
727f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Launch gallery to crop the photo
728f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = getCropImageIntent(Uri.fromFile(f));
729f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.SUB_ACTIVITY;
730a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
731f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (Exception e) {
732f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Log.e(TAG, "Cannot crop image", e);
733f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
734cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
735cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
736cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
737f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
738f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for image cropping.
739f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
740f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getCropImageIntent(Uri photoUri) {
741f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent("com.android.camera.action.CROP");
742f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setDataAndType(photoUri, "image/*");
743f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
744f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
745f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
746f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputX", ICON_SIZE);
747f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputY", ICON_SIZE);
748f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
749f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
750f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
751f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
752f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
753f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Saves or creates the contact based on the mode, and if successful
754f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * finishes the activity.
755f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
7569df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public boolean save(int saveMode) {
757a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
758f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
759f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
760f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
7618c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        // If we are about to close the editor - there is no need to refresh the data
762a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
7639d2bcfb40d0ee107886eb99eba13a840e944ba43Dianne Hackborn            getLoaderManager().destroyLoader(LOADER_DATA);
7648c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        }
7658c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov
766825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.SAVING;
7676cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
768a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
769a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (!EntityModifier.hasChanges(mState, accountTypes)) {
770a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            onSaveCompleted(false, saveMode, mLookupUri);
7716cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov            return true;
7726cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov        }
7736cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
774a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        setEnabled(false);
775f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
776a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState,
777a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                SAVE_MODE_EXTRA_KEY, saveMode, getActivity().getClass(),
778a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                ContactEditorActivity.ACTION_SAVE_COMPLETED);
779a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        getActivity().startService(intent);
780f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
781f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
782f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
783d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    public static class CancelEditDialogFragment extends DialogFragment {
784d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
785d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public static void show(ContactEditorFragment fragment) {
786d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment dialog = new CancelEditDialogFragment();
787d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.setTargetFragment(fragment, 0);
788d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.show(fragment.getFragmentManager(), "cancelEditor");
789d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
790d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
791d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        @Override
792d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
793d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            AlertDialog dialog = new AlertDialog.Builder(getActivity())
7944292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
795d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setTitle(R.string.cancel_confirmation_dialog_title)
796d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setMessage(R.string.cancel_confirmation_dialog_message)
797d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setPositiveButton(R.string.discard,
798d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
799d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            @Override
800d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
801d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                                ((ContactEditorFragment)getTargetFragment()).doRevertAction();
802d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            }
803d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        }
804d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    )
805d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setNegativeButton(android.R.string.cancel, null)
806d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .create();
807d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            return dialog;
808d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
809d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
810d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
811d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private boolean revert() {
812c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
813c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov        if (mState == null || !EntityModifier.hasChanges(mState, accountTypes)) {
814d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            doRevertAction();
815d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        } else {
816d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment.show(this);
817d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
818d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        return true;
819d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
820d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
821d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private void doRevertAction() {
822825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // When this Fragment is closed we don't want it to auto-save
823825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.CLOSING;
82422fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        if (mListener != null) mListener.onReverted();
825f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
826f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
8272b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    public void onJoinCompleted(Uri uri) {
828a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        onSaveCompleted(false, SaveMode.RELOAD, uri);
8292b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    }
8302b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov
831a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public void onSaveCompleted(boolean hadChanges, int saveMode, Uri contactLookupUri) {
832a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        boolean success = contactLookupUri != null;
833a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        Log.d(TAG, "onSaveCompleted(" + saveMode + ", " + contactLookupUri);
834a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (hadChanges) {
835a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            if (success) {
836a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                if (saveMode != SaveMode.JOIN) {
837a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                    Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
838a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                }
839a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else {
840a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
841a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            }
842a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        }
843f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
84415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.CLOSE:
8459df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            case SaveMode.HOME:
846f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
847f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final int resultCode;
848f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (success && contactLookupUri != null) {
849b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                    final String requestAuthority =
850b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                            mLookupUri == null ? null : mLookupUri.getAuthority();
851f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
852f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final String legacyAuthority = "contacts";
853f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
854f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = new Intent();
855f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (legacyAuthority.equals(requestAuthority)) {
856f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Build legacy Uri when requested by caller
857f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final long contactId = ContentUris.parseId(Contacts.lookupContact(
858f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                mContext.getContentResolver(), contactLookupUri));
859f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyContentUri = Uri.parse("content://contacts/people");
860f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyUri = ContentUris.withAppendedId(
861f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                legacyContentUri, contactId);
862f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(legacyUri);
863f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    } else {
864f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Otherwise pass back a lookup-style Uri
865f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(contactLookupUri);
866f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
867f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
868f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultCode = Activity.RESULT_OK;
869f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
870f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultCode = Activity.RESULT_CANCELED;
871f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
872f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
873825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                // It is already saved, so prevent that it is saved again
874825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                mStatus = Status.CLOSING;
8759df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                if (mListener != null) mListener.onSaveFinished(resultCode, resultIntent,
8769df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                        saveMode == SaveMode.HOME);
877f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
878a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
87915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.RELOAD:
880dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov            case SaveMode.JOIN:
88115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                if (success && contactLookupUri != null) {
88215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If this was in INSERT, we are changing into an EDIT now.
88315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If it already was an EDIT, we are changing to the new Uri now
88415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    mState = null;
8851015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov                    load(Intent.ACTION_EDIT, contactLookupUri, null);
886825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    mStatus = Status.LOADING;
88715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
888dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov
889dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov                    // If it was a JOIN, we are now ready to bring up the join activity.
890dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov                    if (saveMode == SaveMode.JOIN) {
891dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov                        showJoinAggregateActivity(contactLookupUri);
892dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov                    }
89315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                }
89415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                break;
895a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
89615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.SPLIT:
897a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                mStatus = Status.CLOSING;
898a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                if (mListener != null) {
8998c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov                    mListener.onContactSplit(contactLookupUri);
900a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                } else {
901a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
902a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                }
903f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
904f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
905f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
906f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
907f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
908f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
909f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
910f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
911f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
912f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
91373a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov        if (contactLookupUri == null || !isAdded()) {
914f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
915f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
916f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
917f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
918f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT);
919f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin);
920a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        startActivityForResult(intent, REQUEST_CODE_JOIN);
921f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
922f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
923f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
924f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
925f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
926f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
9272b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
9282b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                contactId, isContactWritable(),
9292b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
9302b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        mContext.startService(intent);
931f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
932f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
933f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
934ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     * Returns true if there is at least one writable raw contact in the current contact.
935ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     */
936ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    private boolean isContactWritable() {
937a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
938ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        int size = mState.size();
939ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        for (int i = 0; i < size; i++) {
940ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            ValuesDelta values = mState.get(i).getValues();
941ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
942b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type = accountTypes.getAccountType(accountType);
94369f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (!type.readOnly) {
944ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov                return true;
945ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            }
946ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        }
947ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        return false;
948ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    }
949ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov
950cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public static interface Listener {
951cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
95222fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was not found, so somehow close this fragment. This is raised after a contact
95322fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * is removed via Menu/Delete (unless it was a new contact)
954cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
95522fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onContactNotFound();
956f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
957f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
9588c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov         * Contact was split, so we can close now.
959a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * @param newLookupUri The lookup uri of the new contact that should be shown to the user.
960a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * The editor tries best to chose the most natural contact here.
961f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
9628c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov        void onContactSplit(Uri newLookupUri);
963f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
964f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
965f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User was presented with an account selection and couldn't decide.
966f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
96722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onAccountSelectorAborted();
968f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
969f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
970f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User has tapped Revert, close the fragment now.
971f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
97222fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onReverted();
973f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
974f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
975f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Set the Title (e.g. of the Activity)
976f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
977f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void setTitleTo(int resourceId);
978f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
979f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
98022fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was saved and the Fragment can now be closed safely.
981f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
9829df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        void onSaveFinished(int resultCode, Intent resultIntent, boolean navigateHome);
983b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann
984b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        /**
985b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann         * User decided to delete the contact.
986b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann         */
987a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        void onDeleteRequested(Uri lookupUri);
988e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov
989e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov        /**
990e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * User switched to editing a different contact (a suggestion from the
991e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * aggregation engine).
992e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         */
993e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov        void onEditOtherContactRequested(
994e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov                Uri contactLookupUri, ArrayList<ContentValues> contentValues);
995fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
996fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
997fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * Contact is being created for an external account that provides its own
998fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * new contact activity.
999fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
1000fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        void onCustomCreateContactActivityRequested(Account account, Bundle intentExtras);
1001fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1002fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1003fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * The edited raw contact belongs to an external account that provides
1004fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * its own edit activity.
1005fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *
1006fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * @param redirect indicates that the current editor should be closed
1007fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *            before the custom editor is shown.
1008fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
1009fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        void onCustomEditContactActivityRequested(Account account, Uri rawContactUri,
1010fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                Bundle intentExtras, boolean redirect);
1011f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1012f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1013f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private class EntityDeltaComparator implements Comparator<EntityDelta> {
1014f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1015f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Compare EntityDeltas for sorting the stack of editors.
1016f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
10174a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        @Override
1018f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public int compare(EntityDelta one, EntityDelta two) {
1019f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check direct equality
1020f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (one.equals(two)) {
1021f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 0;
1022f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1023f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1024a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov            final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1025b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            String accountType2 = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
1026b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type1 = accountTypes.getAccountType(accountType2);
1027b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            accountType2 = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
1028b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type2 = accountTypes.getAccountType(accountType2);
1029f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1030f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check read-only
1031b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            if (type1.readOnly && !type2.readOnly) {
1032f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1033b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            } else if (!type1.readOnly && type2.readOnly) {
1034f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1035f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1036f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1037f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account type
1038f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean skipAccountTypeCheck = false;
1039b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount1 = type1 instanceof GoogleAccountType;
1040b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount2 = type2 instanceof GoogleAccountType;
104169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (isGoogleAccount1 && !isGoogleAccount2) {
1042f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
104369f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (!isGoogleAccount1 && isGoogleAccount2) {
1044f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
104569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (isGoogleAccount1 && isGoogleAccount2){
1046f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                skipAccountTypeCheck = true;
1047f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1048f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1049f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            int value;
1050f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!skipAccountTypeCheck) {
1051b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                if (type1.accountType == null) {
10522776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                    return 1;
10532776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                }
1054b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                value = type1.accountType.compareTo(type2.accountType);
1055f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (value != 0) {
1056f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    return value;
1057f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1058f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1059f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1060f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account name
1061f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta oneValues = one.getValues();
1062f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME);
1063f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneAccount == null) oneAccount = "";
1064f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta twoValues = two.getValues();
1065f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME);
1066f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (twoAccount == null) twoAccount = "";
1067f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            value = oneAccount.compareTo(twoAccount);
1068f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (value != 0) {
1069f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return value;
1070f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1071f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1072f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Both are in the same account, fall back to contact ID
1073f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long oneId = oneValues.getAsLong(RawContacts._ID);
1074f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long twoId = twoValues.getAsLong(RawContacts._ID);
1075f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneId == null) {
1076f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1077f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoId == null) {
1078f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1079f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1080f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1081f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return (int)(oneId - twoId);
1082f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1083f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1084f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1085f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1086f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
1087f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1088f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected long getContactId() {
1089f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        for (EntityDelta rawContact : mState) {
1090f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
1091f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            if (contactId != null) {
1092f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                return contactId;
1093f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
1094f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1095f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return 0;
1096f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1097f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
109841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
109972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann    private void onContactNameChange(int request, final RawContactEditorView rawContactEditor,
1100392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann            TextFieldsEditorView nameEditor) {
110141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
110241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        switch (request) {
110341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            case EditorListener.EDITOR_FORM_CHANGED:
11040b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov                if (nameEditor.hasShortAndLongForms()) {
11050b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov                    if (nameEditor.areOptionalFieldsVisible()) {
11060b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov                        switchFromFullNameToStructuredName(nameEditor);
11070b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov                    } else {
11080b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov                        switchFromStructuredNameToFullName(nameEditor);
11090b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov                    }
111041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                }
111141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                break;
111241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
111341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            case EditorListener.FIELD_CHANGED:
1114dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov                if (nameEditor.hasShortAndLongForms()) {
1115dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov                    if (nameEditor.areOptionalFieldsVisible()) {
1116dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov                        eraseFullName(nameEditor.getValues());
1117dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov                    } else {
1118dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov                        eraseStructuredName(nameEditor.getValues());
1119dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov                    }
112041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                }
112141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                acquireAggregationSuggestions(rawContactEditor);
112241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                break;
112341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }
112441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    }
112541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
1126392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void switchFromFullNameToStructuredName(LabeledEditorView nameEditor) {
112741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        ValuesDelta values = nameEditor.getValues();
112841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
112941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
113041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        if (displayName == null) {
113141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            displayName = "";
113241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }
113341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
113441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name")
113541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                .appendQueryParameter(StructuredName.DISPLAY_NAME, displayName).build();
113641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{
113741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                StructuredName.PREFIX,
113841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                StructuredName.GIVEN_NAME,
113941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                StructuredName.MIDDLE_NAME,
114041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                StructuredName.FAMILY_NAME,
114141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                StructuredName.SUFFIX,
114241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }, null, null, null);
114341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
114441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        try {
114541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            if (cursor.moveToFirst()) {
114641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                eraseFullName(values);
114741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                values.put(StructuredName.PREFIX, cursor.getString(0));
114841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                values.put(StructuredName.GIVEN_NAME, cursor.getString(1));
114941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                values.put(StructuredName.MIDDLE_NAME, cursor.getString(2));
115041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                values.put(StructuredName.FAMILY_NAME, cursor.getString(3));
115141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                values.put(StructuredName.SUFFIX, cursor.getString(4));
115241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            }
115341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        } finally {
115441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            cursor.close();
115541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }
115641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    }
115741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
1158392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann    private void switchFromStructuredNameToFullName(LabeledEditorView nameEditor) {
115941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        ValuesDelta values = nameEditor.getValues();
116041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
116141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        Uri.Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath(
116241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                "complete_name");
116341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        appendQueryParameter(builder, values, StructuredName.PREFIX);
116441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        appendQueryParameter(builder, values, StructuredName.GIVEN_NAME);
116541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        appendQueryParameter(builder, values, StructuredName.MIDDLE_NAME);
116641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        appendQueryParameter(builder, values, StructuredName.FAMILY_NAME);
116741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        appendQueryParameter(builder, values, StructuredName.SUFFIX);
116841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        Uri uri = builder.build();
116941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{
117041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                StructuredName.DISPLAY_NAME,
117141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }, null, null, null);
117241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
117341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        try {
117441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            if (cursor.moveToFirst()) {
117541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                eraseStructuredName(values);
117641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov                values.put(StructuredName.DISPLAY_NAME, cursor.getString(0));
117741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            }
117841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        } finally {
117941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            cursor.close();
118041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }
118141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    }
118241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
118341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    private void eraseFullName(ValuesDelta values) {
118441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        values.putNull(StructuredName.DISPLAY_NAME);
118541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    }
118641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
118741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    private void eraseStructuredName(ValuesDelta values) {
118841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        values.putNull(StructuredName.PREFIX);
118941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        values.putNull(StructuredName.GIVEN_NAME);
119041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        values.putNull(StructuredName.MIDDLE_NAME);
119141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        values.putNull(StructuredName.FAMILY_NAME);
119241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        values.putNull(StructuredName.SUFFIX);
119341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    }
119441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
119541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    private void appendQueryParameter(Uri.Builder builder, ValuesDelta values, String field) {
119641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        String value = values.getAsString(field);
119741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        if (!TextUtils.isEmpty(value)) {
119841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov            builder.appendQueryParameter(field, value);
119941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov        }
120041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov    }
120141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov
1202f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1203f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Triggers an asynchronous search for aggregation suggestions.
1204f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
120572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann    public void acquireAggregationSuggestions(RawContactEditorView rawContactEditor) {
12069302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        long rawContactId = rawContactEditor.getRawContactId();
12079302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (mAggregationSuggestionsRawContactId != rawContactId
12089302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                && mAggregationSuggestionView != null) {
12099302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
12109302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView = null;
12119302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionEngine.reset();
12129302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
12139302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12149302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionsRawContactId = rawContactId;
12159302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1216f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine == null) {
1217f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine = new AggregationSuggestionEngine(getActivity());
1218f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.setListener(this);
1219f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.start();
1220f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1221f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1222916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        mAggregationSuggestionEngine.setContactId(getContactId());
1223916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
1224392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        LabeledEditorView nameEditor = rawContactEditor.getNameEditor();
1225f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mAggregationSuggestionEngine.onNameChange(nameEditor.getValues());
1226f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1227f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1228f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
1229f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onAggregationSuggestionChange() {
1230a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!isAdded() || mState == null || mStatus != Status.EDITING) {
123102cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov            return;
123202cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov        }
123302cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov
1234bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        RawContactEditorView rawContactView =
1235bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
12369302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (rawContactView == null) {
12379302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            return;
12389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1239f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
12409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        ViewStub stub = (ViewStub)rawContactView.findViewById(R.id.aggregation_suggestion_stub);
1241f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (stub != null) {
1242f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            stub.inflate();
1243f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1244f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
12459302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        // Only request the view on screen when it is first displayed
12469302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        boolean requestOnScreen = mAggregationSuggestionView == null;
12479302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionView = rawContactView.findViewById(R.id.aggregation_suggestion);
1248f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1249f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        int count = mAggregationSuggestionEngine.getSuggestedContactCount();
1250f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (count == 0) {
12519302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
1252f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
1253f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1254f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
12559302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        List<Suggestion> suggestions = mAggregationSuggestionEngine.getSuggestions();
12569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12579302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
12589302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                R.id.aggregation_suggestions);
1259f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        itemList.removeAllViews();
1260f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1261f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        LayoutInflater inflater = getActivity().getLayoutInflater();
1262f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1263f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        for (Suggestion suggestion : suggestions) {
1264f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            AggregationSuggestionView suggestionView =
1265f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    (AggregationSuggestionView) inflater.inflate(
1266f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            R.layout.aggregation_suggestions_item, null);
1267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            suggestionView.setLayoutParams(
1268f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    new LinearLayout.LayoutParams(
1269f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
1270c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            suggestionView.setNewContact(mState.size() == 1 && mState.get(0).isContactInsert());
1271bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            suggestionView.setListener(this);
12729302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            suggestionView.bindSuggestion(suggestion);
1273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            itemList.addView(suggestionView);
1274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
12759302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1276bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        adjustAggregationSuggestionViewLayout(rawContactView);
1277a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        setAggregationSuggestionViewEnabled(mEnabled);
12789302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionView.setVisibility(View.VISIBLE);
12799302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestOnScreen) {
12819302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mContent.postDelayed(new Runnable() {
12829302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12839302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                @Override
12849302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                public void run() {
12859302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    requestAggregationSuggestionOnScreen(mAggregationSuggestionView);
12869302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                }
12879302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            }, AGGREGATION_SUGGESTION_SCROLL_DELAY);
12889302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1289f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1290f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1291f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1292bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Adjusts the layout of the aggregation suggestion view so that it is placed directly
1293bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * underneath and have the same width as the last text editor of the contact name editor.
1294bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1295bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    private void adjustAggregationSuggestionViewLayout(RawContactEditorView rawContactView) {
1296392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        TextFieldsEditorView nameEditor = rawContactView.getNameEditor();
1297bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Rect rect = new Rect();
1298bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        nameEditor.acquireEditorBounds(rect);
1299bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        MarginLayoutParams layoutParams =
1300bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                (MarginLayoutParams) mAggregationSuggestionView.getLayoutParams();
1301bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        layoutParams.leftMargin = rect.left;
1302bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        layoutParams.width = rect.width();
1303bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mAggregationSuggestionView.setLayoutParams(layoutParams);
1304bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1305bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1306bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1307bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
1308bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        long rawContactIds[] = new long[rawContactIdList.size()];
1309bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        for (int i = 0; i < rawContactIds.length; i++) {
1310bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            rawContactIds[i] = rawContactIdList.get(i);
1311bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1312bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        JoinSuggestedContactDialogFragment dialog =
1313bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new JoinSuggestedContactDialogFragment();
1314bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1315bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putLongArray("rawContactIds", rawContactIds);
1316bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1317bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
131874f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        try {
131974f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            dialog.show(getFragmentManager(), "join");
132074f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        } catch (Exception ex) {
132174f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            // No problem - the activity is no longer available to display the dialog
132274f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        }
1323bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1324bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1325bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
1326bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1327bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1328bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1329bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
13304292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1331bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setTitle(R.string.aggregation_suggestion_join_dialog_title)
1332bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
1333bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1334bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1335bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1336bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1337bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1338bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                long rawContactIds[] =
1339bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getLongArray("rawContactIds");
1340bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doJoinSuggestedContact(rawContactIds);
1341bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1342bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1343bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1344bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1345bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1346bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1347bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1348bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1349bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1350bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Joins the suggested contact (specified by the id's of constituent raw
1351bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * contacts), save all changes, and stay in the editor.
1352bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1353bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doJoinSuggestedContact(long[] rawContactIds) {
1354cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1355cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov            return;
1356cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        }
1357cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov
1358bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mState.setJoinWithRawContacts(rawContactIds);
13599df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.RELOAD);
1360bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1361bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1362bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1363bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onEditAction(Uri contactLookupUri) {
1364bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        SuggestionEditConfirmationDialogFragment dialog =
1365bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new SuggestionEditConfirmationDialogFragment();
1366bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1367bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putParcelable("contactUri", contactLookupUri);
1368bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1369bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
1370bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.show(getFragmentManager(), "edit");
1371bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1372bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1373bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
1374bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1375bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1376bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1377bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
13784292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1379bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setTitle(R.string.aggregation_suggestion_edit_dialog_title)
1380bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
1381bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1382bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1383bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1384bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1385bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1386bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                Uri contactUri =
1387bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getParcelable("contactUri");
1388bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doEditSuggestedContact(contactUri);
1389bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1390bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1391bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1392bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1393bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1394bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1395bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1396bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1397bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1398bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Abandons the currently edited contact and switches to editing the suggested
1399bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * one, transferring all the data there
1400bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1401bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doEditSuggestedContact(Uri contactUri) {
1402bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        if (mListener != null) {
1403bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            mListener.onEditOtherContactRequested(
1404bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    contactUri, mState.get(0).getContentValues());
1405bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1406bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1407bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1408bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1409f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Scrolls the editor if necessary to reveal the aggregation suggestion that is
1410f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * shown below the name editor. Makes sure that the currently focused field
1411f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * remains visible.
1412f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1413f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private void requestAggregationSuggestionOnScreen(final View view) {
1414f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Rect rect = getRelativeBounds(mContent, view);
1415f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        View focused = mContent.findFocus();
1416f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (focused != null) {
1417f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            rect.union(getRelativeBounds(mContent, focused));
1418f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1419f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mContent.requestRectangleOnScreen(rect);
1420f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1421f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1422a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    public void setAggregationSuggestionViewEnabled(boolean enabled) {
1423a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (mAggregationSuggestionView == null) {
1424a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            return;
1425a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1426a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1427a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
1428a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov                R.id.aggregation_suggestions);
1429a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        int count = itemList.getChildCount();
1430a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        for (int i = 0; i < count; i++) {
1431a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            itemList.getChildAt(i).setEnabled(enabled);
1432a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1433a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    }
1434a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1435f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1436f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Computes bounds of the supplied view relative to its ascendant.
1437f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1438f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private Rect getRelativeBounds(View ascendant, View view) {
1439f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Rect rect = new Rect();
1440f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
1441f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1442f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        View parent = (View) view.getParent();
1443f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        while (parent != ascendant) {
1444f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            rect.offset(parent.getLeft(), parent.getTop());
1445f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            parent = (View) parent.getParent();
1446f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1447f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return rect;
1448f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1449f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1450f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
1451f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
1452b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        outState.putParcelable(KEY_URI, mLookupUri);
1453d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putString(KEY_ACTION, mAction);
1454d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
1455f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (hasValidState()) {
1456f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Store entities with modifications
1457f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putParcelable(KEY_EDIT_STATE, mState);
1458f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1459f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
1461f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
1462f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mCurrentPhotoFile != null) {
1463f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
1464f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1465f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
14669302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId);
146702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        outState.putBoolean(KEY_ENABLED, mEnabled);
1468ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov        outState.putInt(KEY_STATUS, mStatus);
1469f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
1470f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1471f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1472d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
1473f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
1474f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (mStatus == Status.SUB_ACTIVITY) {
1475f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.EDITING;
1476f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        }
1477f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
1478f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Ignore failed requests
1479f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (resultCode != Activity.RESULT_OK) return;
1480f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (requestCode) {
1481a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: {
1482c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                // As we are coming back to this view, the editor will be reloaded automatically,
1483c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                // which will cause the photo that is set here to disappear. To prevent this,
14844a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                // we remember to set a flag which is interpreted after loading.
14854a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                // This photo is set here already to reduce flickering.
1486c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mPhoto = data.getParcelableExtra("data");
1487c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                setPhoto(mRawContactIdRequestingPhoto, mPhoto);
1488c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhotoAfterLoad = mRawContactIdRequestingPhoto;
1489c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhoto = -1;
1490f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1491f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1492f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1493a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_CAMERA_WITH_DATA: {
1494f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                doCropPhoto(mCurrentPhotoFile);
1495f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1496f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1497a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_JOIN: {
1498f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
1499f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
1500f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
1501f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
15024a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                break;
1503f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1504f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1505cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
15069cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
1507c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    /**
1508c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
1509c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     */
1510c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private void setPhoto(long rawContact, Bitmap photo) {
1511bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
15129302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestingEditor != null) {
15139302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            requestingEditor.setPhotoBitmap(photo);
15149302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        } else {
15159302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            Log.w(TAG, "The contact that requested the photo is no longer present.");
15169302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
15179302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
15189302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
15199302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    /**
15209302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     * Finds raw contact editor view for the given rawContactId.
15219302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     */
1522bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
1523c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        for (int i = 0; i < mContent.getChildCount(); i++) {
1524c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            final View childView = mContent.getChildAt(i);
152572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
152672af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
15279302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (editor.getRawContactId() == rawContactId) {
15289302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    return editor;
1529c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                }
1530c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1531c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        }
15329302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return null;
1533c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    }
1534c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1535fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
1536fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     * Returns true if there is currently more than one photo on screen.
1537fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1538fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    private boolean hasMoreThanOnePhoto() {
1539fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int count = mContent.getChildCount();
1540fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int countWithPicture = 0;
1541fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        for (int i = 0; i < count; i++) {
1542fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            final View childView = mContent.getChildAt(i);
1543fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
1544fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
1545fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                if (editor.hasSetPhoto()) {
1546fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    countWithPicture++;
1547fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    if (countWithPicture > 1) return true;
1548fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
1549fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1550fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1551fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
1552fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        return false;
15539cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1554222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1555222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    /**
1556222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     * The listener for the data loader
1557222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     */
1558222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener =
1559222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            new LoaderCallbacks<ContactLoader.Result>() {
1560222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1561222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
1562222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            mLoaderStartTime = SystemClock.elapsedRealtime();
1563b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            return new ContactLoader(mContext, mLookupUri);
1564222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1565222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1566222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1567222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
1568222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long loaderCurrentTime = SystemClock.elapsedRealtime();
1569222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
15705da9363bc4f2e04dc388579e1df979a5843e25e6Dmitri Plotnikov            if (data == ContactLoader.Result.NOT_FOUND || data == ContactLoader.Result.ERROR) {
1571222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                // Item has been deleted
1572222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                Log.i(TAG, "No contact found. Closing activity");
157322fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann                if (mListener != null) mListener.onContactNotFound();
1574222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                return;
1575222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            }
1576222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1577825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            mStatus = Status.EDITING;
15786caccaeeed943db323be89853a108f422e670760Dmitri Plotnikov            mLookupUri = data.getLookupUri();
1579222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataStartTime = SystemClock.elapsedRealtime();
1580222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            setData(data);
1581222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataEndTime = SystemClock.elapsedRealtime();
1582c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1583c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            // If we are coming back from the photo trimmer, this will be set.
1584c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            if (mRawContactIdRequestingPhotoAfterLoad != -1) {
1585c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                setPhoto(mRawContactIdRequestingPhotoAfterLoad, mPhoto);
1586c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhotoAfterLoad = -1;
1587c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mPhoto = null;
1588c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1589222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
1590222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
15914ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
15924ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<ContactLoader.Result> loader) {
15934ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1594222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    };
1595a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
1596e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    /**
1597e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov     * The listener for the group meta data loader
1598e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov     */
1599e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
1600e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            new LoaderCallbacks<Cursor>() {
1601e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1602e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1603e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public CursorLoader onCreateLoader(int id, Bundle args) {
1604e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            return new GroupMetaDataLoader(mContext);
1605e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
1606e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1607e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1608e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1609e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            mGroupMetaData = data;
1610e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            bindGroupMetaData();
1611e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
16124ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
16134ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<Cursor> loader) {
16144ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1615e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    };
1616e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1617a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    @Override
1618a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    public void onSplitContactConfirmed() {
1619a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        mState.markRawContactsForSplitting();
16209df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.SPLIT);
1621a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    }
1622a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
1623a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    /**
16249442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann     * Account was chosen in the selector. Create a RawContact for this account now
1625fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1626fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    @Override
162740bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov    public void onAccountChosen(Account account) {
162840bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov        createContact(account);
1629fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    }
1630fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
1631fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
16329442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann     * The account selector has been aborted. If we are in "New" mode, we have to close now
1633fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1634fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    @Override
16359442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann    public void onAccountSelectorCancelled() {
16369442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        if (!hasValidState() && mListener != null) {
16379442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mListener.onAccountSelectorAborted();
16389442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
16399442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann    }
16409442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16419442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann    private final class PhotoEditorListener
16429442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            implements EditorListener, PhotoActionPopup.Listener {
16439442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        private final BaseRawContactEditorView mEditor;
164469f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        private final boolean mAccountReadOnly;
16459442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
164669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        private PhotoEditorListener(BaseRawContactEditorView editor, boolean accountReadOnly) {
16479442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mEditor = editor;
164869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            mAccountReadOnly = accountReadOnly;
16499442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
16509442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16519442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16529442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onRequest(int request) {
16539442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            if (!hasValidState()) return;
16549442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16559442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            if (request == EditorListener.REQUEST_PICK_PHOTO) {
16569442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Determine mode
16579442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final int mode;
165869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                if (mAccountReadOnly) {
16599442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    if (mEditor.hasSetPhoto() && hasMoreThanOnePhoto()) {
16609442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        mode = PhotoActionPopup.MODE_READ_ONLY_ALLOW_PRIMARY;
16619442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    } else {
16629442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        // Read-only and either no photo or the only photo ==> no options
16639442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        return;
16649442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    }
16659442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                } else {
16669442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    if (mEditor.hasSetPhoto()) {
16679442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        if (hasMoreThanOnePhoto()) {
16689442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                            mode = PhotoActionPopup.MODE_PHOTO_ALLOW_PRIMARY;
16699442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        } else {
16709442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                            mode = PhotoActionPopup.MODE_PHOTO_DISALLOW_PRIMARY;
16719442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        }
16729442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    } else {
16739442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        mode = PhotoActionPopup.MODE_NO_PHOTO;
16749442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    }
1675fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
16769442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                PhotoActionPopup.createPopupMenu(mContext, mEditor.getPhotoEditor(), this, mode)
16779442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        .show();
1678fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1679fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1680fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
16819442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16829442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onDeleted(Editor removedEditor) {
16839442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
1684a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
16859442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
16869442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * User has chosen to set the selected photo as the (super) primary photo
16879442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
16889442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16899442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onUseAsPrimaryChosen() {
16909442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            // Set the IsSuperPrimary for each editor
16919442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            int count = mContent.getChildCount();
16929442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            for (int i = 0; i < count; i++) {
16939442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final View childView = mContent.getChildAt(i);
16949442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                if (childView instanceof BaseRawContactEditorView) {
16959442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
16969442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    final PhotoEditorView photoEditor = editor.getPhotoEditor();
16979442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    photoEditor.setSuperPrimary(editor == mEditor);
16989442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                }
16999442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
1700a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        }
1701a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17029442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17039442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * User has chosen to remove a picture
17049442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17059442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17069442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onRemovePictureChose() {
17079442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mEditor.setPhotoBitmap(null);
1708a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        }
1709a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17109442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17119442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * Launches Camera to take a picture and store it in a file.
17129442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17139442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17149442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onTakePhotoChosen() {
17159442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
17169442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            try {
17179442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Launch camera to take photo for selected contact
17189442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                PHOTO_DIR.mkdirs();
17199442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
17209442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final Intent intent = getTakePickIntent(mCurrentPhotoFile);
17219442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
1722f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov                mStatus = Status.SUB_ACTIVITY;
17239442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                startActivityForResult(intent, REQUEST_CODE_CAMERA_WITH_DATA);
17249442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            } catch (ActivityNotFoundException e) {
17259442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                Toast.makeText(mContext, R.string.photoPickerNotFoundText,
17269442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        Toast.LENGTH_LONG).show();
17279442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
17289442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
1729a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17309442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17319442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * Launches Gallery to pick a photo.
17329442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17339442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17349442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onPickFromGalleryChosen() {
17359442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
17369442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            try {
17379442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Launch picker to choose photo for selected contact
17389442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final Intent intent = getPhotoPickIntent();
1739f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov                mStatus = Status.SUB_ACTIVITY;
17409442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
17419442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            } catch (ActivityNotFoundException e) {
17429442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                Toast.makeText(mContext, R.string.photoPickerNotFoundText,
17439442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        Toast.LENGTH_LONG).show();
17449442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
17454a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        }
17464a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann    }
17472ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1748