ContactEditorFragment.java revision 2293e55d550fbc9974d1185960715e59acb14a85
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;
34d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport com.android.contacts.util.AccountsListAdapter;
35f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
36f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account;
37cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity;
38bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.AlertDialog;
39bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.Dialog;
40bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.DialogFragment;
41222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.Fragment;
42222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager;
43222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
44cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ActivityNotFoundException;
45cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
46cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues;
47cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
48e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader;
49bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface;
50e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikovimport android.content.Entity;
51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader;
53f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor;
54f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
55f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.graphics.Rect;
56f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.media.MediaScannerConnection;
57cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
58cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
59f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.Environment;
609767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock;
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;
66362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
67362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website;
68f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
690a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoroimport android.provider.ContactsContract.DisplayPhoto;
70be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuanimport android.provider.ContactsContract.Groups;
712013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmannimport android.provider.ContactsContract.Intents;
72f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
73f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.MediaStore;
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;
84d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.AdapterView;
8580d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
86d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.ListPopupWindow;
87cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
88cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
89f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File;
90f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.text.SimpleDateFormat;
91cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList;
92f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
93f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator;
94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Date;
95f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List;
96f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
97a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmannpublic class ContactEditorFragment extends Fragment implements
98d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        SplitContactConfirmationDialogFragment.Listener,
99fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener,
100fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        ExternalRawContactEditorView.Listener {
101cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
102cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private static final String TAG = "ContactEditorFragment";
103cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int LOADER_DATA = 1;
105e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private static final int LOADER_GROUPS = 2;
106f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
107d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_URI = "uri";
108d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_ACTION = "action";
109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_EDIT_STATE = "state";
110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
113f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
114623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann    private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin";
1159302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions";
11602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private static final String KEY_ENABLED = "enabled";
117ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov    private static final String KEY_STATUS = "status";
118f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
119a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
120a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
12115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    /**
1227d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * An intent extra that forces the editor to add the edited contact
1237d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     * to the default group (e.g. "My Contacts").
1247d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov     */
1257d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory";
1267d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
1277d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    /**
12815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     * Modes that specify what the AsyncTask has to perform after saving
12915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann     */
130c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    // TODO: Move this into a common utils class or the save service because the contact and
131c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan    // group editors need to use this interface definition
1329df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public interface SaveMode {
13315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
13415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Close the editor after saving
13515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
13615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int CLOSE = 0;
13715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
13815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
13915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Reload the data so that the user can continue editing
14015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int RELOAD = 1;
14215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
14315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
14415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Split the contact after saving
14515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
14615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int SPLIT = 2;
14715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann
14815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        /**
14915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         * Join another contact after saving
15015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann         */
15115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann        public static final int JOIN = 3;
1529df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov
1539df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        /**
1549df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         * Navigate to Contacts Home activity after saving.
1559df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov         */
1569df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        public static final int HOME = 4;
15715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann    }
158a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
159825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private interface Status {
160825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
161825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * The loader is fetching data
162825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
163825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int LOADING = 0;
164825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
165825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
166825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         * Not currently busy. We are waiting for the user to enter data
167825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
168825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int EDITING = 1;
169825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
170825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
171f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * The data is currently being saved. This is used to prevent more
172f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * auto-saves (they shouldn't overlap)
173825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
174825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int SAVING = 2;
175825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
176825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        /**
177a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * Prevents any more saves. This is used if in the following cases:
178a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After Save/Close
179a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After Revert
180a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann         * - After the user has accepted an edit suggestion
181825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann         */
182825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        public static final int CLOSING = 3;
183f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
184f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        /**
185f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         * Prevents saving while running a child activity.
186f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov         */
187f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        public static final int SUB_ACTIVITY = 4;
188825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    }
189825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
190a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_JOIN = 0;
191a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1;
192a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 2;
193f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
194c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private Bitmap mPhoto = null;
195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mRawContactIdRequestingPhoto = -1;
196c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private long mRawContactIdRequestingPhotoAfterLoad = -1;
197cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
198f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
199f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final File PHOTO_DIR = new File(
201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Environment.getExternalStorageDirectory() + "/DCIM/Camera");
202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
203e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private Cursor mGroupMetaData;
204e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
205f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
206f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * A delay in milliseconds used for bringing aggregation suggestions to
207f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * the visible part of the screen. The reason this has to be done after
208f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * a delay is a race condition with the soft keyboard.  The keyboard
209f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * may expand to display its own autocomplete suggestions, which will
210f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * reduce the visible area of the screen.  We will yield to the keyboard
211f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * hoping that the delay is sufficient.  If not - part of the
212f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * suggestion will be hidden, which is not fatal.
213f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
214f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private static final int AGGREGATION_SUGGESTION_SCROLL_DELAY = 200;
215f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
216f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private File mCurrentPhotoFile;
217cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2180a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    // Height/width (in pixels) to request for the photo - queried from the provider.
2190a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    private int mPhotoPickSize;
2200a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro
221cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Context mContext;
222f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mAction;
223b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann    private Uri mLookupUri;
224f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Bundle mIntentExtras;
225cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Listener mListener;
226cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
227f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mContactIdForJoin;
228623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann    private boolean mContactWritableForJoin;
229cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
230f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private LinearLayout mContent;
231ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    private EntityDeltaList mState;
232cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
233f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
234cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
2359767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann    private long mLoaderStartTime;
2369767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann
237825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann    private int mStatus;
238825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
239f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private AggregationSuggestionEngine mAggregationSuggestionEngine;
2409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private long mAggregationSuggestionsRawContactId;
2419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    private View mAggregationSuggestionView;
242f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
2437d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov    private boolean mAutoAddToDefaultGroup;
2447d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
24502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    private boolean mEnabled = true;
246eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov    private boolean mRequestFocus;
24702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
248cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
249cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
250cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
25102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    public void setEnabled(boolean enabled) {
25202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        if (mEnabled != enabled) {
25302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = enabled;
25402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (mContent != null) {
25502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                int count = mContent.getChildCount();
25602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                for (int i = 0; i < count; i++) {
25702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                    mContent.getChildAt(i).setEnabled(enabled);
25802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov                }
25902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            }
260a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            setAggregationSuggestionViewEnabled(enabled);
26102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            final Activity activity = getActivity();
26202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            if (activity != null) activity.invalidateOptionsMenu();
26302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
26402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov    }
26502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
266cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
267cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public void onAttach(Activity activity) {
268cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        super.onAttach(activity);
269cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        mContext = activity;
2700a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        loadPhotoPickSize();
271cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
272cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
273cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onStop() {
275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        super.onStop();
276f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine != null) {
277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.quit();
278f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
279248fba273e867616b1f8973dac6ce3e5ee1ba544Dmitri Plotnikov
280825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If anything was left unsaved, save it now but keep the editor open.
281f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
282623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            save(SaveMode.RELOAD);
283825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
284f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
285f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
286f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
287cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
288cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
289cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
291e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
2923648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
293cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
294825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // If we are in an orientation change, we already have mState (it was loaded by onCreate)
295825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (mState != null) {
296825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            bindEditors();
297825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
298825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
299cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
300cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
301cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
302222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
303222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    public void onActivityCreated(Bundle savedInstanceState) {
304222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        super.onActivityCreated(savedInstanceState);
305222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
306825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")");
307222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
308825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Handle initial actions only when existing state missing
3094a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        final boolean hasIncomingState = savedInstanceState != null;
310825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
311825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (!hasIncomingState) {
312825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            if (Intent.ACTION_EDIT.equals(mAction)) {
313825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit);
314825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
315825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            } else if (Intent.ACTION_INSERT.equals(mAction)) {
316825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert);
317825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann
3182013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                final Account account = mIntentExtras == null ? null :
3192013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    (Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT);
3202013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann
3212013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                if (account != null) {
3222013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // Account specified in Intent
32340bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    createContact(account);
3242013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                } else {
3252013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                    // No Account specified. Let the user choose
32640bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov                    // Load Accounts async so that we can present them
327d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    createContact();
3282013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann                }
329a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else if (ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(mAction)) {
330a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                // do nothing
331825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            } else throw new IllegalArgumentException("Unknown Action String " + mAction +
332825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
333825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        }
334222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    }
335222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
336e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    @Override
337e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    public void onStart() {
338e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener);
339e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        super.onStart();
340e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
341e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
3421015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov    public void load(String action, Uri lookupUri, Bundle intentExtras) {
343f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mAction = action;
344b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        mLookupUri = lookupUri;
345f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mIntentExtras = intentExtras;
3467d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov        mAutoAddToDefaultGroup = mIntentExtras != null
3477d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                && mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY);
348f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
349f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
350f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void setListener(Listener value) {
351f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mListener = value;
352cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
353cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
354cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
355f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
356d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        if (savedState != null) {
357d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // Restore mUri before calling super.onCreate so that onInitializeLoaders
358d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // would already have a uri and an action to work with
359b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            mLookupUri = savedState.getParcelable(KEY_URI);
360d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mAction = savedState.getString(KEY_ACTION);
361d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        }
362d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
363f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
364f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
365f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (savedState == null) {
366f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // If savedState is non-null, onRestoreInstanceState() will restore the generator.
367f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = new ViewIdGenerator();
368f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
369825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            // Read state from savedState. No loading involved here
370ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
371f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mRawContactIdRequestingPhoto = savedState.getLong(
372f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
373f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
374f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE);
375f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (fileName != null) {
376f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                mCurrentPhotoFile = new File(fileName);
377cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
379623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann            mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN);
3809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS);
38102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            mEnabled = savedState.getBoolean(KEY_ENABLED);
382ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov            mStatus = savedState.getInt(KEY_STATUS);
383cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
384cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
385cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
386bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann    public void setData(ContactLoader.Result data) {
387d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        // If we have already loaded data, we do not want to change it here to not confuse the user
388d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        if (mState != null) {
389d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            Log.v(TAG, "Ignoring background change. This will have to be rebased later");
390d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann            return;
391d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann        }
392d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann
393fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        // See if this edit operation needs to be redirected to a custom editor
394fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        ArrayList<Entity> entities = data.getEntities();
395fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        if (entities.size() == 1) {
396fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            Entity entity = entities.get(0);
397fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            ContentValues entityValues = entity.getEntityValues();
398fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
399a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov            AccountType accountType = AccountTypeManager.getInstance(mContext).getAccountType(type);
400fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (accountType.getEditContactActivityClassName() != null) {
401fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                if (mListener != null) {
402fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    String name = entityValues.getAsString(RawContacts.ACCOUNT_NAME);
403fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
404fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                    mListener.onCustomEditContactActivityRequested(new Account(name, type),
405fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
406fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                            mIntentExtras, true);
407fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                }
408fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                return;
409fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
410fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
411fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
412fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        bindEditorsForExistingContact(data);
413fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
414fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
415fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    @Override
416fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    public void onExternalEditorRequest(Account account, Uri uri) {
417fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        mListener.onCustomEditContactActivityRequested(account, uri, null, false);
418fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
419fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
420fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    private void bindEditorsForExistingContact(ContactLoader.Result data) {
42102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        setEnabled(true);
42202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov
423a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        mState = EntityDeltaList.fromIterator(data.getEntities().iterator());
4241ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        setIntentExtras(mIntentExtras);
4251ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        mIntentExtras = null;
426e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov
427eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
428eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
4291ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        bindEditors();
4301ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    }
4311ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov
4321ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    /**
4331ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     * Merges extras from the intent.
4341ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov     */
4351ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov    public void setIntentExtras(Bundle extras) {
4361ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        if (extras == null || extras.size() == 0) {
4371ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            return;
438bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
439916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
440a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
4411ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        for (EntityDelta state : mState) {
4421ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
443b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type = accountTypes.getAccountType(accountType);
44469f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (!type.readOnly) {
4451ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                // Apply extras to the first writable raw contact only
44669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                EntityModifier.parseExtras(mContext, type, state, extras);
4471ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov                break;
4481ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov            }
4491ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov        }
450f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
451cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
452d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
453d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Shows the account creation screen. An account associated with the contact is automatically
454d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * selected. If there's no available account, device-local contact should be created.
455d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
456d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void createContact() {
457a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final ArrayList<Account> accounts =
458a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov                AccountTypeManager.getInstance(mContext).getAccounts(true);
459f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // No Accounts available.  Create a phone-local contact.
460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (accounts.isEmpty()) {
46140bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov            createContact(null);
462f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;  // Don't show a dialog.
463f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
464cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
465d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // We have an account switcher in "create-account" screen, so don't need to ask a user to
466d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        // select an account here.
467d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        createContact(accounts.get(0));
468cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
469cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
470d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
471cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    /**
472d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Shows account creation screen associated with a given account.
473d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
474d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param account may be null to signal a device-local contact should be created.
475cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann     */
47640bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov    private void createContact(Account account) {
477a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
478b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        final AccountType accountType =
479b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                accountTypes.getAccountType(account != null ? account.type : null);
480fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
481b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov        if (accountType.getCreateContactActivityClassName() != null) {
482fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            if (mListener != null) {
483fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                mListener.onCustomCreateContactActivityRequested(account, mIntentExtras);
484fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            }
485fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        } else {
486b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            bindEditorsForNewContact(account, accountType);
487fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        }
488fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov    }
489fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
490d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    /**
491d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Removes a current editor ({@link #mState}) and rebinds new editor for a new account.
492d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * Some of old data are reused with new restriction enforced by the new account.
493d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     *
494d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param oldState Old data being editted.
495d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param oldAccount Old account associated with oldState.
496d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     * @param newAccount New account to be used.
497d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa     */
498d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void rebindEditorsForNewContact(
499d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            EntityDelta oldState, Account oldAccount, Account newAccount) {
500d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
501d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountType oldAccountType = accountTypes.getAccountType(oldAccount.type);
502d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        AccountType newAccountType = accountTypes.getAccountType(newAccount.type);
503d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
504d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccountType.getCreateContactActivityClassName() != null) {
505d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            Log.w(TAG, "external activity called in rebind situation");
506d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            if (mListener != null) {
507d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras);
508d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
509d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
510d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            mState = null;
511d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType);
512d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
513d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
514d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
51569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov    private void bindEditorsForNewContact(Account account, final AccountType accountType) {
516d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        bindEditorsForNewContact(account, accountType, null, null);
517d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
518d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
519d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void bindEditorsForNewContact(Account newAccount, final AccountType newAccountType,
520d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            EntityDelta oldState, AccountType oldAccountType) {
521a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        mStatus = Status.EDITING;
522a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
523f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ContentValues values = new ContentValues();
524d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (newAccount != null) {
525d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            values.put(RawContacts.ACCOUNT_NAME, newAccount.name);
526d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            values.put(RawContacts.ACCOUNT_TYPE, newAccount.type);
527f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
528f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_NAME);
529f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_TYPE);
530cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
531cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
532f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
533d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        if (oldState == null) {
534d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            // Parse any values from incoming intent
535d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            EntityModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
536d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        } else {
537d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            EntityModifier.migrateStateForNewContact(mContext, oldState, insert,
538d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    oldAccountType, newAccountType);
539d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        }
540f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
54169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        // Ensure we have some default fields (if the account type does not support a field,
542362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmann        // ensureKind will not add it, so it is safe to add e.g. Event)
543d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
544d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
545d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
546d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
547d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        EntityModifier.ensureKindExists(insert, newAccountType, StructuredPostal.CONTENT_ITEM_TYPE);
548f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
549f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mState == null) {
550f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Create state if none exists yet
551ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = EntityDeltaList.fromSingle(insert);
552f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
553f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add contact onto end of existing state
554f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mState.add(insert);
555cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
556f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
557eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = true;
558eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
559f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
560cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
561cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
562f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void bindEditors() {
563f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
564f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
565cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
566f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
567f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
568cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
569f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
570f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
571a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
572a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        int numRawContacts = mState.size();
573a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        for (int i = 0; i < numRawContacts; i++) {
574f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
575f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final EntityDelta entity = mState.get(i);
576f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ValuesDelta values = entity.getValues();
577f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!values.isVisible()) continue;
578f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
579f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
580b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type = accountTypes.getAccountType(accountType);
581f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final long rawContactId = values.getAsLong(RawContacts._ID);
582f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
58372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            final BaseRawContactEditorView editor;
58469f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (type.isExternal()) {
585fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                editor = (BaseRawContactEditorView) inflater.inflate(
586fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                        R.layout.external_raw_contact_editor_view, mContent, false);
587fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                ((ExternalRawContactEditorView) editor).setListener(this);
588fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov            } else {
589a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                final RawContactEditorView rawContactEditor = (RawContactEditorView)
590f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann                        inflater.inflate(R.layout.raw_contact_editor_view, mContent, false);
591a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                // For existing contacts, only show the account header if there is more than 1 raw
592a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                // contact in the aggregate contact.
593a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                if (Intent.ACTION_EDIT.equals(mAction)) {
594a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                    rawContactEditor.setAccountHeaderVisible(numRawContacts > 1);
595a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                }
596a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan                editor = rawContactEditor;
597cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
598a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan            if (Intent.ACTION_INSERT.equals(mAction) && numRawContacts == 1) {
599d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                final ArrayList<Account> accounts =
600d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        AccountTypeManager.getInstance(mContext).getAccounts(true);
601d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                if (accounts.size() > 1) {
602d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    addAccountSwitcher(mState.get(0), editor);
603a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan                } else {
604a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan                    disableAccountSwitcher(editor);
605d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                }
606d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
607a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan
60802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            editor.setEnabled(mEnabled);
609cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
610f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
6117d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
61269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            editor.setState(entity, type, mViewIdGenerator);
613f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
6149442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            editor.getPhotoEditor().setEditorListener(
61569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                    new PhotoEditorListener(editor, type.readOnly));
61672af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (editor instanceof RawContactEditorView) {
61772af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
6185ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                EditorListener listener = new EditorListener() {
619f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
620f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
621f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    public void onRequest(int request) {
62211bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                        if (request == EditorListener.FIELD_CHANGED) {
62311bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                            acquireAggregationSuggestions(rawContactEditor);
62411bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov                        }
625f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
626f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
627f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    @Override
6282293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan                    public void onDeleteRequested(Editor removedEditor) {
629f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    }
6305ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                };
6315ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov
6325ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor();
6335ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                if (mRequestFocus) {
6345ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    nameEditor.requestFocus();
6355ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                    mRequestFocus = false;
6365ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                }
6375ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                nameEditor.setEditorListener(listener);
638f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
6395ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                final TextFieldsEditorView phoneticNameEditor =
6405ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                        rawContactEditor.getPhoneticNameEditor();
6415ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov                phoneticNameEditor.setEditorListener(listener);
6427d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov                rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
6437d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov
6449302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (rawContactId == mAggregationSuggestionsRawContactId) {
645f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    acquireAggregationSuggestions(rawContactEditor);
646f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                }
647f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
648cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
649f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
650eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov        mRequestFocus = false;
651eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
652e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        bindGroupMetaData();
653e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
654f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
655f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
656a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
657a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        // Refresh Action Bar as the visibility of the join command
658825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // Activity can be null if we have been detached from the Activity
659825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        final Activity activity = getActivity();
660825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        if (activity != null) activity.invalidateOptionsMenu();
661eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov
662cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
663cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
664e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private void bindGroupMetaData() {
665e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        if (mGroupMetaData == null) {
666e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            return;
667e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
668e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
669e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        int editorCount = mContent.getChildCount();
670e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        for (int i = 0; i < editorCount; i++) {
67172af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i);
672e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            editor.setGroupMetaData(mGroupMetaData);
673e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
674e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    }
675e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
676d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    private void addAccountSwitcher(
677d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            final EntityDelta currentState, BaseRawContactEditorView editor) {
678d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        ValuesDelta values = currentState.getValues();
679d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final Account currentAccount = new Account(
680d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                values.getAsString(RawContacts.ACCOUNT_NAME),
681d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                values.getAsString(RawContacts.ACCOUNT_TYPE));
682d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final View accountView = editor.findViewById(R.id.account);
683d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        final View anchorView = editor.findViewById(R.id.anchor_for_account_switcher);
684d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        accountView.setOnClickListener(new View.OnClickListener() {
685d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            @Override
686d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            public void onClick(View v) {
687d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                final ListPopupWindow popup = new ListPopupWindow(mContext, null);
688a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                final AccountsListAdapter adapter =
689a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa                        new AccountsListAdapter(mContext, true, currentAccount);
690d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setWidth(anchorView.getWidth());
691d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAnchorView(anchorView);
692d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setAdapter(adapter);
693d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setModal(true);
694d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
695d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.setOnItemClickListener(new AdapterView.OnItemClickListener() {
696d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    @Override
697d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    public void onItemClick(AdapterView<?> parent, View view, int position,
698d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            long id) {
699d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        popup.dismiss();
700d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        Account newAccount = adapter.getItem(position);
701d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        if (!newAccount.equals(currentAccount)) {
702d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                            rebindEditorsForNewContact(currentState, currentAccount, newAccount);
703d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                        }
704d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                    }
705d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                });
706d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa                popup.show();
707d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa            }
708d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa        });
709d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa    }
710d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa
711a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan    private void disableAccountSwitcher(BaseRawContactEditorView editor) {
712a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        // Remove the pressed state from the account header because the user cannot switch accounts
713a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        // on an existing contact
714a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        final View accountView = editor.findViewById(R.id.account);
715a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan        accountView.setBackgroundDrawable(null);
716a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan        accountView.setEnabled(false);
717a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan    }
718a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan
719b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
720eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
721c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan        inflater.inflate(R.menu.edit_contact, menu);
722cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
723cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
724b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
725eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onPrepareOptionsMenu(Menu menu) {
7269b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // This supports the keyboard shortcut to save changes to a contact but shouldn't be visible
7279b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // because the custom action bar contains the "save" button now (not the overflow menu).
7289b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        // TODO: Find a better way to handle shortcuts, i.e. onKeyDown()?
7299b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        menu.findItem(R.id.menu_done).setVisible(false);
7309b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
731f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1);
73202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        int size = menu.size();
73302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        for (int i = 0; i < size; i++) {
73402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov            menu.getItem(i).setEnabled(mEnabled);
73502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        }
736cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
737cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
738b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
739cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public boolean onOptionsItemSelected(MenuItem item) {
740cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (item.getItemId()) {
741f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_done:
7429df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov                return save(SaveMode.CLOSE);
743f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_discard:
744d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                return revert();
745f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_split:
746f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSplitContactAction();
747f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_join:
748f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doJoinContactAction();
749f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
750f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
751f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
752cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
753f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSplitContactAction() {
754f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
755f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
756a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        final SplitContactConfirmationDialogFragment dialog =
7574a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                new SplitContactConfirmationDialogFragment();
7584a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.setTargetFragment(this, 0);
7594a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG);
760f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
761f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
762f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
763f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doJoinContactAction() {
7644c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        if (!hasValidState()) {
7654c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov            return false;
7664c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
7674c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
7684c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // If we just started creating a new contact and haven't added any data, it's too
7694c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        // early to do a join
770a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
771a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (mState.size() == 1 && mState.get(0).isContactInsert()
772a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                && !EntityModifier.hasChanges(mState, accountTypes)) {
773a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact,
774a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                            Toast.LENGTH_LONG).show();
775a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            return true;
7764c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov        }
7774c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov
7789df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        return save(SaveMode.JOIN);
779f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
780f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
7810a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    private void loadPhotoPickSize() {
7820a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        Cursor c = mContext.getContentResolver().query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
7830a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro                new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null);
7840a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        try {
7850a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro            c.moveToFirst();
7860a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro            mPhotoPickSize = c.getInt(0);
7870a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        } finally {
7880a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro            c.close();
7890a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        }
7900a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    }
7910a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro
792f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
793f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap.
794f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
7950a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    public Intent getPhotoPickIntent() {
796f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
797f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setType("image/*");
798f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
799f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
800f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
8010a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputX", mPhotoPickSize);
8020a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputY", mPhotoPickSize);
803f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
804f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
805f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
806f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
807f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
808f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Check if our internal {@link #mState} is valid, usually checked before
809f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * performing user actions.
810f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
811f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean hasValidState() {
812f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return mState != null && mState.size() > 0;
813f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
814f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
815f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
816f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Create a file name for the icon photo using current time.
817f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
818f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String getPhotoFileName() {
819f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Date date = new Date(System.currentTimeMillis());
820f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
821f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return dateFormat.format(date) + ".jpg";
822f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
823f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
824f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
825f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for capturing a photo and storing it in a temporary file.
826f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
827f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getTakePickIntent(File f) {
828f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
829f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
830f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
831f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
832f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
833f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
834f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Sends a newly acquired photo to Gallery for cropping
835f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
836f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    protected void doCropPhoto(File f) {
837f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
838f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add the image to the media store
839f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            MediaScannerConnection.scanFile(
840f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mContext,
841f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { f.getAbsolutePath() },
842f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { null },
843f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    null);
844f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
845f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Launch gallery to crop the photo
846f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = getCropImageIntent(Uri.fromFile(f));
847f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.SUB_ACTIVITY;
848a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
849f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (Exception e) {
850f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Log.e(TAG, "Cannot crop image", e);
851f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
852cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
853cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
854cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
855f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
856f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for image cropping.
857f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
8580a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro    public Intent getCropImageIntent(Uri photoUri) {
859f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent("com.android.camera.action.CROP");
860f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setDataAndType(photoUri, "image/*");
861f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
862f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
863f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
8640a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputX", mPhotoPickSize);
8650a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro        intent.putExtra("outputY", mPhotoPickSize);
866f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
867f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
868f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
869f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
870f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
871f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Saves or creates the contact based on the mode, and if successful
872f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * finishes the activity.
873f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
8749df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov    public boolean save(int saveMode) {
875a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
876f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
877f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
878f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
8798c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        // If we are about to close the editor - there is no need to refresh the data
880a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) {
8819d2bcfb40d0ee107886eb99eba13a840e944ba43Dianne Hackborn            getLoaderManager().destroyLoader(LOADER_DATA);
8828c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov        }
8838c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov
884825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.SAVING;
8856cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
886a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
887a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (!EntityModifier.hasChanges(mState, accountTypes)) {
888a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            onSaveCompleted(false, saveMode, mLookupUri);
8896cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov            return true;
8906cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov        }
8916cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov
892a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        setEnabled(false);
893f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
894a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState,
895a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                SAVE_MODE_EXTRA_KEY, saveMode, getActivity().getClass(),
896a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                ContactEditorActivity.ACTION_SAVE_COMPLETED);
897a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        getActivity().startService(intent);
898f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
899f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
900f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
901d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    public static class CancelEditDialogFragment extends DialogFragment {
902d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
903d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public static void show(ContactEditorFragment fragment) {
904d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment dialog = new CancelEditDialogFragment();
905d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.setTargetFragment(fragment, 0);
906d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            dialog.show(fragment.getFragmentManager(), "cancelEditor");
907d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
908d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
909d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        @Override
910d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
911d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            AlertDialog dialog = new AlertDialog.Builder(getActivity())
9124292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
913d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setTitle(R.string.cancel_confirmation_dialog_title)
914d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setMessage(R.string.cancel_confirmation_dialog_message)
915d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setPositiveButton(R.string.discard,
916d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
917d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            @Override
918d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
919d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                                ((ContactEditorFragment)getTargetFragment()).doRevertAction();
920d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                            }
921d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                        }
922d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    )
923d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .setNegativeButton(android.R.string.cancel, null)
924d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov                    .create();
925d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            return dialog;
926d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
927d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
928d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
929d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private boolean revert() {
930c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
931c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov        if (mState == null || !EntityModifier.hasChanges(mState, accountTypes)) {
932d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            doRevertAction();
933d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        } else {
934d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov            CancelEditDialogFragment.show(this);
935d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        }
936d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov        return true;
937d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    }
938d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov
939d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov    private void doRevertAction() {
940825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        // When this Fragment is closed we don't want it to auto-save
941825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann        mStatus = Status.CLOSING;
94222fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        if (mListener != null) mListener.onReverted();
943f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
944f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
9459b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    public void doSaveAction() {
9469b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan        save(SaveMode.CLOSE);
9479b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan    }
9489b3dfd0bc36568558bfdc32a5d4c30f2d0df5fedKatherine Kuan
9492b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    public void onJoinCompleted(Uri uri) {
950a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        onSaveCompleted(false, SaveMode.RELOAD, uri);
9512b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov    }
9522b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov
953a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov    public void onSaveCompleted(boolean hadChanges, int saveMode, Uri contactLookupUri) {
954a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        boolean success = contactLookupUri != null;
955a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        Log.d(TAG, "onSaveCompleted(" + saveMode + ", " + contactLookupUri);
956a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        if (hadChanges) {
957a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            if (success) {
958a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                if (saveMode != SaveMode.JOIN) {
959a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                    Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
960a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                }
961a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            } else {
962a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
963a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov            }
964a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov        }
965f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
96615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.CLOSE:
9679df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov            case SaveMode.HOME:
968f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
969f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (success && contactLookupUri != null) {
970b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                    final String requestAuthority =
971b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann                            mLookupUri == null ? null : mLookupUri.getAuthority();
972f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
973f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final String legacyAuthority = "contacts";
974f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
975f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = new Intent();
9765649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                    resultIntent.setAction(Intent.ACTION_VIEW);
977f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (legacyAuthority.equals(requestAuthority)) {
978f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Build legacy Uri when requested by caller
979f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final long contactId = ContentUris.parseId(Contacts.lookupContact(
980f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                mContext.getContentResolver(), contactLookupUri));
981f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyContentUri = Uri.parse("content://contacts/people");
982f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyUri = ContentUris.withAppendedId(
983f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                legacyContentUri, contactId);
984f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(legacyUri);
985f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    } else {
986f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Otherwise pass back a lookup-style Uri
987f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(contactLookupUri);
988f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
989f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
990f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
991f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
992f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
993825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                // It is already saved, so prevent that it is saved again
994825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                mStatus = Status.CLOSING;
9955649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan                if (mListener != null) mListener.onSaveFinished(resultIntent);
996f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
997a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
99815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.RELOAD:
999dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov            case SaveMode.JOIN:
100015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                if (success && contactLookupUri != null) {
1001623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    // If it was a JOIN, we are now ready to bring up the join activity.
1002623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    if (saveMode == SaveMode.JOIN) {
1003623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                        showJoinAggregateActivity(contactLookupUri);
1004623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                    }
1005623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann
100615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If this was in INSERT, we are changing into an EDIT now.
100715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    // If it already was an EDIT, we are changing to the new Uri now
100815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    mState = null;
10091015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov                    load(Intent.ACTION_EDIT, contactLookupUri, null);
1010825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann                    mStatus = Status.LOADING;
101115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
101215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                }
101315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann                break;
1014a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov
101515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann            case SaveMode.SPLIT:
1016a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov                mStatus = Status.CLOSING;
1017a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                if (mListener != null) {
10188c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov                    mListener.onContactSplit(contactLookupUri);
1019a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                } else {
1020a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                    Log.d(TAG, "No listener registered, can not call onSplitFinished");
1021a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann                }
1022f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1023f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1024f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1025f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1026f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1027f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
1028f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
1029f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
1030f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1031f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
103273a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov        if (contactLookupUri == null || !isAdded()) {
1033f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
1034f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1035f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1036f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
1037623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        mContactWritableForJoin = isContactWritable();
1038f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT);
1039f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin);
1040a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        startActivityForResult(intent, REQUEST_CODE_JOIN);
1041f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1042f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1043f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1044f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
1045f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1046f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
10472b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin,
1048623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann                contactId, mContactWritableForJoin,
10492b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov                ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED);
10502b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov        mContext.startService(intent);
1051f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1052f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1053f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1054ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     * Returns true if there is at least one writable raw contact in the current contact.
1055ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov     */
1056ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    private boolean isContactWritable() {
1057a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1058ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        int size = mState.size();
1059ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        for (int i = 0; i < size; i++) {
1060ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            ValuesDelta values = mState.get(i).getValues();
1061ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
1062b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type = accountTypes.getAccountType(accountType);
106369f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (!type.readOnly) {
1064ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov                return true;
1065ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov            }
1066ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        }
1067ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov        return false;
1068ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov    }
1069ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov
1070cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public static interface Listener {
1071cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
107222fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was not found, so somehow close this fragment. This is raised after a contact
107322fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * is removed via Menu/Delete (unless it was a new contact)
1074cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
107522fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onContactNotFound();
1076f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1077f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
10788c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov         * Contact was split, so we can close now.
1079a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * @param newLookupUri The lookup uri of the new contact that should be shown to the user.
1080a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann         * The editor tries best to chose the most natural contact here.
1081f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
10828c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov        void onContactSplit(Uri newLookupUri);
1083f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1084f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1085f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User has tapped Revert, close the fragment now.
1086f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
108722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann        void onReverted();
1088f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1089f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1090f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Set the Title (e.g. of the Activity)
1091f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
1092f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void setTitleTo(int resourceId);
1093f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1094f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
109522fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann         * Contact was saved and the Fragment can now be closed safely.
1096f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
10975649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan        void onSaveFinished(Intent resultIntent);
1098b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann
1099b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        /**
1100e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * User switched to editing a different contact (a suggestion from the
1101e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         * aggregation engine).
1102e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov         */
1103e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov        void onEditOtherContactRequested(
1104e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov                Uri contactLookupUri, ArrayList<ContentValues> contentValues);
1105fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1106fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1107fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * Contact is being created for an external account that provides its own
1108fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * new contact activity.
1109fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
1110fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        void onCustomCreateContactActivityRequested(Account account, Bundle intentExtras);
1111fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov
1112fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        /**
1113fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * The edited raw contact belongs to an external account that provides
1114fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * its own edit activity.
1115fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *
1116fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         * @param redirect indicates that the current editor should be closed
1117fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         *            before the custom editor is shown.
1118fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov         */
1119fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov        void onCustomEditContactActivityRequested(Account account, Uri rawContactUri,
1120fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov                Bundle intentExtras, boolean redirect);
1121f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1122f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1123f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private class EntityDeltaComparator implements Comparator<EntityDelta> {
1124f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
1125f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Compare EntityDeltas for sorting the stack of editors.
1126f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
11274a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        @Override
1128f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public int compare(EntityDelta one, EntityDelta two) {
1129f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check direct equality
1130f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (one.equals(two)) {
1131f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 0;
1132f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1133f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1134a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov            final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
1135b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            String accountType2 = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
1136b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type1 = accountTypes.getAccountType(accountType2);
1137b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            accountType2 = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
1138b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            final AccountType type2 = accountTypes.getAccountType(accountType2);
1139f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1140f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check read-only
1141b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            if (type1.readOnly && !type2.readOnly) {
1142f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1143b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            } else if (!type1.readOnly && type2.readOnly) {
1144f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1145f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1146f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1147f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account type
1148f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean skipAccountTypeCheck = false;
1149b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount1 = type1 instanceof GoogleAccountType;
1150b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov            boolean isGoogleAccount2 = type2 instanceof GoogleAccountType;
115169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            if (isGoogleAccount1 && !isGoogleAccount2) {
1152f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
115369f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (!isGoogleAccount1 && isGoogleAccount2) {
1154f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
115569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            } else if (isGoogleAccount1 && isGoogleAccount2){
1156f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                skipAccountTypeCheck = true;
1157f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1158f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1159f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            int value;
1160f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!skipAccountTypeCheck) {
1161b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                if (type1.accountType == null) {
11622776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                    return 1;
11632776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                }
1164b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov                value = type1.accountType.compareTo(type2.accountType);
1165f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (value != 0) {
1166f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    return value;
1167f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1168f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1169f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1170f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account name
1171f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta oneValues = one.getValues();
1172f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME);
1173f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneAccount == null) oneAccount = "";
1174f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta twoValues = two.getValues();
1175f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME);
1176f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (twoAccount == null) twoAccount = "";
1177f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            value = oneAccount.compareTo(twoAccount);
1178f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (value != 0) {
1179f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return value;
1180f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1181f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1182f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Both are in the same account, fall back to contact ID
1183f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long oneId = oneValues.getAsLong(RawContacts._ID);
1184f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long twoId = twoValues.getAsLong(RawContacts._ID);
1185f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneId == null) {
1186f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1187f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoId == null) {
1188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1189f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1190f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1191f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return (int)(oneId - twoId);
1192f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1193f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1194f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1196f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Returns the contact ID for the currently edited contact or 0 if the contact is new.
1197f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1198f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    protected long getContactId() {
1199c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov        if (mState != null) {
1200c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov            for (EntityDelta rawContact : mState) {
1201c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
1202c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                if (contactId != null) {
1203c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                    return contactId;
1204c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov                }
1205f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            }
1206f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1207f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return 0;
1208f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1209f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1210f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1211f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Triggers an asynchronous search for aggregation suggestions.
1212f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
121372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann    public void acquireAggregationSuggestions(RawContactEditorView rawContactEditor) {
12149302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        long rawContactId = rawContactEditor.getRawContactId();
12159302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (mAggregationSuggestionsRawContactId != rawContactId
12169302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                && mAggregationSuggestionView != null) {
12179302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
12189302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView = null;
12199302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionEngine.reset();
12209302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
12219302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12229302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionsRawContactId = rawContactId;
12239302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1224f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (mAggregationSuggestionEngine == null) {
1225f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine = new AggregationSuggestionEngine(getActivity());
1226f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.setListener(this);
1227f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            mAggregationSuggestionEngine.start();
1228f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1229f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1230916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov        mAggregationSuggestionEngine.setContactId(getContactId());
1231916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov
1232392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        LabeledEditorView nameEditor = rawContactEditor.getNameEditor();
1233f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mAggregationSuggestionEngine.onNameChange(nameEditor.getValues());
1234f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1235f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1236f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    @Override
1237f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    public void onAggregationSuggestionChange() {
1238a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (!isAdded() || mState == null || mStatus != Status.EDITING) {
123902cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov            return;
124002cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov        }
124102cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov
1242bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        RawContactEditorView rawContactView =
1243bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId);
12449302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (rawContactView == null) {
12459302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            return;
12469302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1247f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
12489302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        ViewStub stub = (ViewStub)rawContactView.findViewById(R.id.aggregation_suggestion_stub);
1249f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (stub != null) {
1250f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            stub.inflate();
1251f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1252f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
12539302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        // Only request the view on screen when it is first displayed
12549302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        boolean requestOnScreen = mAggregationSuggestionView == null;
12559302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionView = rawContactView.findViewById(R.id.aggregation_suggestion);
1256f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1257f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        int count = mAggregationSuggestionEngine.getSuggestedContactCount();
1258f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (count == 0) {
12599302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mAggregationSuggestionView.setVisibility(View.GONE);
1260f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            return;
1261f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1262f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
12639302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        List<Suggestion> suggestions = mAggregationSuggestionEngine.getSuggestions();
12649302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12659302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
12669302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                R.id.aggregation_suggestions);
1267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        itemList.removeAllViews();
1268f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1269f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        LayoutInflater inflater = getActivity().getLayoutInflater();
1270f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1271f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        for (Suggestion suggestion : suggestions) {
1272f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            AggregationSuggestionView suggestionView =
1273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    (AggregationSuggestionView) inflater.inflate(
1274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            R.layout.aggregation_suggestions_item, null);
1275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            suggestionView.setLayoutParams(
1276f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                    new LinearLayout.LayoutParams(
1277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov                            LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
1278c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov            suggestionView.setNewContact(mState.size() == 1 && mState.get(0).isContactInsert());
1279bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            suggestionView.setListener(this);
12809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            suggestionView.bindSuggestion(suggestion);
1281f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            itemList.addView(suggestionView);
1282f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
12839302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
1284bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        adjustAggregationSuggestionViewLayout(rawContactView);
1285a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        setAggregationSuggestionViewEnabled(mEnabled);
12869302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        mAggregationSuggestionView.setVisibility(View.VISIBLE);
12879302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12889302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestOnScreen) {
12899302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            mContent.postDelayed(new Runnable() {
12909302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
12919302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                @Override
12929302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                public void run() {
12939302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    requestAggregationSuggestionOnScreen(mAggregationSuggestionView);
12949302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                }
12959302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            }, AGGREGATION_SUGGESTION_SCROLL_DELAY);
12969302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
1297f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1298f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1299f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1300bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Adjusts the layout of the aggregation suggestion view so that it is placed directly
1301bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * underneath and have the same width as the last text editor of the contact name editor.
1302bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1303bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    private void adjustAggregationSuggestionViewLayout(RawContactEditorView rawContactView) {
1304392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann        TextFieldsEditorView nameEditor = rawContactView.getNameEditor();
1305bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Rect rect = new Rect();
1306bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        nameEditor.acquireEditorBounds(rect);
1307bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        MarginLayoutParams layoutParams =
1308bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                (MarginLayoutParams) mAggregationSuggestionView.getLayoutParams();
1309bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        layoutParams.leftMargin = rect.left;
1310bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        layoutParams.width = rect.width();
1311bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mAggregationSuggestionView.setLayoutParams(layoutParams);
1312bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1313bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1314bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1315bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onJoinAction(long contactId, List<Long> rawContactIdList) {
1316bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        long rawContactIds[] = new long[rawContactIdList.size()];
1317bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        for (int i = 0; i < rawContactIds.length; i++) {
1318bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            rawContactIds[i] = rawContactIdList.get(i);
1319bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1320bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        JoinSuggestedContactDialogFragment dialog =
1321bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new JoinSuggestedContactDialogFragment();
1322bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1323bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putLongArray("rawContactIds", rawContactIds);
1324bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1325bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
132674f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        try {
132774f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            dialog.show(getFragmentManager(), "join");
132874f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        } catch (Exception ex) {
132974f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov            // No problem - the activity is no longer available to display the dialog
133074f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov        }
1331bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1332bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1333bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class JoinSuggestedContactDialogFragment extends DialogFragment {
1334bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1335bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1336bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1337bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
13384292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1339bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setTitle(R.string.aggregation_suggestion_join_dialog_title)
1340bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_join_dialog_message)
1341bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1342bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1343bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1344bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1345bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1346bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                long rawContactIds[] =
1347bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getLongArray("rawContactIds");
1348bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doJoinSuggestedContact(rawContactIds);
1349bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1350bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1351bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1352bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1353bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1354bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1355bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1356bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1357bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1358bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Joins the suggested contact (specified by the id's of constituent raw
1359bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * contacts), save all changes, and stay in the editor.
1360bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1361bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doJoinSuggestedContact(long[] rawContactIds) {
1362cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        if (!hasValidState() || mStatus != Status.EDITING) {
1363cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov            return;
1364cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov        }
1365cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov
1366bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        mState.setJoinWithRawContacts(rawContactIds);
13679df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.RELOAD);
1368bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1369bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1370bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    @Override
1371bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public void onEditAction(Uri contactLookupUri) {
1372bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        SuggestionEditConfirmationDialogFragment dialog =
1373bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                new SuggestionEditConfirmationDialogFragment();
1374bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        Bundle args = new Bundle();
1375bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        args.putParcelable("contactUri", contactLookupUri);
1376bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setArguments(args);
1377bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.setTargetFragment(this, 0);
1378bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        dialog.show(getFragmentManager(), "edit");
1379bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1380bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1381bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public static class SuggestionEditConfirmationDialogFragment extends DialogFragment {
1382bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1383bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        @Override
1384bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        public Dialog onCreateDialog(Bundle savedInstanceState) {
1385bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            return new AlertDialog.Builder(getActivity())
13864292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov                    .setIconAttribute(android.R.attr.alertDialogIcon)
1387bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setTitle(R.string.aggregation_suggestion_edit_dialog_title)
1388bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setMessage(R.string.aggregation_suggestion_edit_dialog_message)
1389bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setPositiveButton(android.R.string.yes,
1390bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        new DialogInterface.OnClickListener() {
1391bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            public void onClick(DialogInterface dialog, int whichButton) {
1392bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                ContactEditorFragment targetFragment =
1393bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        (ContactEditorFragment) getTargetFragment();
1394bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                Uri contactUri =
1395bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                        getArguments().getParcelable("contactUri");
1396bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                                targetFragment.doEditSuggestedContact(contactUri);
1397bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                            }
1398bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                        }
1399bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    )
1400bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .setNegativeButton(android.R.string.no, null)
1401bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    .create();
1402bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1403bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1404bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1405bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1406bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * Abandons the currently edited contact and switches to editing the suggested
1407bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     * one, transferring all the data there
1408bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov     */
1409bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    protected void doEditSuggestedContact(Uri contactUri) {
1410bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        if (mListener != null) {
1411a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            // make sure we don't save this contact when closing down
1412a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann            mStatus = Status.CLOSING;
1413bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov            mListener.onEditOtherContactRequested(
1414bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov                    contactUri, mState.get(0).getContentValues());
1415bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        }
1416bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    }
1417bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov
1418bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    /**
1419f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Scrolls the editor if necessary to reveal the aggregation suggestion that is
1420f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * shown below the name editor. Makes sure that the currently focused field
1421f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * remains visible.
1422f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1423f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private void requestAggregationSuggestionOnScreen(final View view) {
1424f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Rect rect = getRelativeBounds(mContent, view);
1425f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        View focused = mContent.findFocus();
1426f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        if (focused != null) {
1427f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            rect.union(getRelativeBounds(mContent, focused));
1428f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1429f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        mContent.requestRectangleOnScreen(rect);
1430f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1431f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1432a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    public void setAggregationSuggestionViewEnabled(boolean enabled) {
1433a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        if (mAggregationSuggestionView == null) {
1434a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            return;
1435a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1436a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1437a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById(
1438a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov                R.id.aggregation_suggestions);
1439a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        int count = itemList.getChildCount();
1440a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        for (int i = 0; i < count; i++) {
1441a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov            itemList.getChildAt(i).setEnabled(enabled);
1442a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov        }
1443a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov    }
1444a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov
1445f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    /**
1446f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     * Computes bounds of the supplied view relative to its ascendant.
1447f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov     */
1448f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    private Rect getRelativeBounds(View ascendant, View view) {
1449f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        Rect rect = new Rect();
1450f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
1451f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1452f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        View parent = (View) view.getParent();
1453f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        while (parent != ascendant) {
1454f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            rect.offset(parent.getLeft(), parent.getTop());
1455f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov            parent = (View) parent.getParent();
1456f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        }
1457f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov        return rect;
1458f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov    }
1459f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov
1460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
1461f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
1462b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann        outState.putParcelable(KEY_URI, mLookupUri);
1463d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putString(KEY_ACTION, mAction);
1464d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
1465f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (hasValidState()) {
1466f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Store entities with modifications
1467f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putParcelable(KEY_EDIT_STATE, mState);
1468f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1469f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1470f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
1471f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
1472f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mCurrentPhotoFile != null) {
1473f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
1474f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1475f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
1476623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin);
14779302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId);
147802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov        outState.putBoolean(KEY_ENABLED, mEnabled);
1479ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov        outState.putInt(KEY_STATUS, mStatus);
1480f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
1481f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1482f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1483d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
1484f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
1485f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        if (mStatus == Status.SUB_ACTIVITY) {
1486f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov            mStatus = Status.EDITING;
1487f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov        }
1488f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov
1489f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Ignore failed requests
1490f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (resultCode != Activity.RESULT_OK) return;
1491f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (requestCode) {
1492a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: {
1493c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                // As we are coming back to this view, the editor will be reloaded automatically,
1494c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                // which will cause the photo that is set here to disappear. To prevent this,
14954a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                // we remember to set a flag which is interpreted after loading.
14964a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                // This photo is set here already to reduce flickering.
1497c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mPhoto = data.getParcelableExtra("data");
1498c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                setPhoto(mRawContactIdRequestingPhoto, mPhoto);
1499c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhotoAfterLoad = mRawContactIdRequestingPhoto;
1500c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhoto = -1;
1501f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1502f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1503f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1504a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_CAMERA_WITH_DATA: {
1505f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                doCropPhoto(mCurrentPhotoFile);
1506f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1507f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1508a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann            case REQUEST_CODE_JOIN: {
1509f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
1510f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
1511f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
1512f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
15134a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann                break;
1514f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1515f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1516cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
15179cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
1518c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    /**
1519c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     * Sets the photo stored in mPhoto and writes it to the RawContact with the given id
1520c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann     */
1521c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    private void setPhoto(long rawContact, Bitmap photo) {
1522bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov        BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact);
15239302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        if (requestingEditor != null) {
15249302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            requestingEditor.setPhotoBitmap(photo);
15259302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        } else {
15269302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov            Log.w(TAG, "The contact that requested the photo is no longer present.");
15279302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        }
15289302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    }
15299302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov
15309302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov    /**
15319302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     * Finds raw contact editor view for the given rawContactId.
15329302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov     */
1533bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov    public BaseRawContactEditorView getRawContactEditorView(long rawContactId) {
1534c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        for (int i = 0; i < mContent.getChildCount(); i++) {
1535c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            final View childView = mContent.getChildAt(i);
153672af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
153772af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
15389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                if (editor.getRawContactId() == rawContactId) {
15399302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov                    return editor;
1540c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                }
1541c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1542c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann        }
15439302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov        return null;
1544c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann    }
1545c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1546fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    /**
1547fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     * Returns true if there is currently more than one photo on screen.
1548fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann     */
1549fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann    private boolean hasMoreThanOnePhoto() {
1550fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int count = mContent.getChildCount();
1551fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        int countWithPicture = 0;
1552fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        for (int i = 0; i < count; i++) {
1553fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            final View childView = mContent.getChildAt(i);
1554fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            if (childView instanceof BaseRawContactEditorView) {
1555fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
1556fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                if (editor.hasSetPhoto()) {
1557fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    countWithPicture++;
1558fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                    if (countWithPicture > 1) return true;
1559fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
1560fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1561fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1562fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
1563fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        return false;
15649cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1565222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1566222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    /**
1567222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     * The listener for the data loader
1568222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     */
1569222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener =
1570222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            new LoaderCallbacks<ContactLoader.Result>() {
1571222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1572222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
1573222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            mLoaderStartTime = SystemClock.elapsedRealtime();
1574b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann            return new ContactLoader(mContext, mLookupUri);
1575222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1576222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1577222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1578222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
1579222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long loaderCurrentTime = SystemClock.elapsedRealtime();
1580222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
15815da9363bc4f2e04dc388579e1df979a5843e25e6Dmitri Plotnikov            if (data == ContactLoader.Result.NOT_FOUND || data == ContactLoader.Result.ERROR) {
1582222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                // Item has been deleted
1583222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                Log.i(TAG, "No contact found. Closing activity");
158422fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann                if (mListener != null) mListener.onContactNotFound();
1585222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                return;
1586222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            }
1587222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1588825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann            mStatus = Status.EDITING;
15896caccaeeed943db323be89853a108f422e670760Dmitri Plotnikov            mLookupUri = data.getLookupUri();
1590222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataStartTime = SystemClock.elapsedRealtime();
1591222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            setData(data);
1592222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataEndTime = SystemClock.elapsedRealtime();
1593c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann
1594c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            // If we are coming back from the photo trimmer, this will be set.
1595c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            if (mRawContactIdRequestingPhotoAfterLoad != -1) {
1596c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                setPhoto(mRawContactIdRequestingPhotoAfterLoad, mPhoto);
1597c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mRawContactIdRequestingPhotoAfterLoad = -1;
1598c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann                mPhoto = null;
1599c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann            }
1600222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
1601222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
16024ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
1603623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann        @Override
16044ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<ContactLoader.Result> loader) {
16054ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1606222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    };
1607a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
1608e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    /**
1609be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan     * The listener for the group meta data loader for all groups.
1610e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov     */
1611e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener =
1612e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            new LoaderCallbacks<Cursor>() {
1613e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1614e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1615e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public CursorLoader onCreateLoader(int id, Bundle args) {
1616be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan            return new GroupMetaDataLoader(mContext, Groups.CONTENT_URI);
1617e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
1618e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1619e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        @Override
1620e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1621e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            mGroupMetaData = data;
1622e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov            bindGroupMetaData();
1623e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov        }
16244ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn
16254ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        public void onLoaderReset(Loader<Cursor> loader) {
16264ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn        }
1627e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov    };
1628e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov
1629a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    @Override
1630a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    public void onSplitContactConfirmed() {
1631a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        mState.markRawContactsForSplitting();
16329df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov        save(SaveMode.SPLIT);
1633a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann    }
1634a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
16359442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann    private final class PhotoEditorListener
16369442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            implements EditorListener, PhotoActionPopup.Listener {
16379442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        private final BaseRawContactEditorView mEditor;
163869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        private final boolean mAccountReadOnly;
16399442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
164069f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov        private PhotoEditorListener(BaseRawContactEditorView editor, boolean accountReadOnly) {
16419442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mEditor = editor;
164269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov            mAccountReadOnly = accountReadOnly;
16439442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
16449442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16459442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16469442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onRequest(int request) {
16479442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            if (!hasValidState()) return;
16489442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
16499442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            if (request == EditorListener.REQUEST_PICK_PHOTO) {
16509442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Determine mode
16519442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final int mode;
165269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov                if (mAccountReadOnly) {
16539442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    if (mEditor.hasSetPhoto() && hasMoreThanOnePhoto()) {
16549442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        mode = PhotoActionPopup.MODE_READ_ONLY_ALLOW_PRIMARY;
16559442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    } else {
16569442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        // Read-only and either no photo or the only photo ==> no options
16579442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        return;
16589442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    }
16599442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                } else {
16609442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    if (mEditor.hasSetPhoto()) {
16619442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        if (hasMoreThanOnePhoto()) {
16629442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                            mode = PhotoActionPopup.MODE_PHOTO_ALLOW_PRIMARY;
16639442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        } else {
16649442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                            mode = PhotoActionPopup.MODE_PHOTO_DISALLOW_PRIMARY;
16659442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        }
16669442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    } else {
16679442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        mode = PhotoActionPopup.MODE_NO_PHOTO;
16689442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    }
1669fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann                }
16709442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                PhotoActionPopup.createPopupMenu(mContext, mEditor.getPhotoEditor(), this, mode)
16719442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        .show();
1672fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann            }
1673fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann        }
1674fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann
16759442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16762293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        public void onDeleteRequested(Editor removedEditor) {
16772293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            // The picture cannot be deleted, it can only be removed, which is handled by
16782293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan            // onRemovePictureChosen()
16799442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
1680a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
16819442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
16829442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * User has chosen to set the selected photo as the (super) primary photo
16839442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
16849442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
16859442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onUseAsPrimaryChosen() {
16869442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            // Set the IsSuperPrimary for each editor
16879442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            int count = mContent.getChildCount();
16889442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            for (int i = 0; i < count; i++) {
16899442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final View childView = mContent.getChildAt(i);
16909442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                if (childView instanceof BaseRawContactEditorView) {
16919442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
16929442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    final PhotoEditorView photoEditor = editor.getPhotoEditor();
16939442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                    photoEditor.setSuperPrimary(editor == mEditor);
16949442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                }
16959442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
1696a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        }
1697a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
16989442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
16999442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * User has chosen to remove a picture
17009442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17019442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17022293e55d550fbc9974d1185960715e59acb14a85Katherine Kuan        public void onRemovePictureChosen() {
17039442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mEditor.setPhotoBitmap(null);
1704a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann        }
1705a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17069442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17079442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * Launches Camera to take a picture and store it in a file.
17089442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17099442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17109442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onTakePhotoChosen() {
17119442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
17129442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            try {
17139442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Launch camera to take photo for selected contact
17149442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                PHOTO_DIR.mkdirs();
17159442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
17169442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final Intent intent = getTakePickIntent(mCurrentPhotoFile);
17179442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann
1718f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov                mStatus = Status.SUB_ACTIVITY;
17199442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                startActivityForResult(intent, REQUEST_CODE_CAMERA_WITH_DATA);
17209442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            } catch (ActivityNotFoundException e) {
17219442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                Toast.makeText(mContext, R.string.photoPickerNotFoundText,
17229442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        Toast.LENGTH_LONG).show();
17239442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
17249442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        }
1725a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann
17269442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        /**
17279442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         * Launches Gallery to pick a photo.
17289442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann         */
17299442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        @Override
17309442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann        public void onPickFromGalleryChosen() {
17319442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
17329442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            try {
17339442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                // Launch picker to choose photo for selected contact
17349442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                final Intent intent = getPhotoPickIntent();
1735f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov                mStatus = Status.SUB_ACTIVITY;
17369442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA);
17379442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            } catch (ActivityNotFoundException e) {
17389442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                Toast.makeText(mContext, R.string.photoPickerNotFoundText,
17399442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann                        Toast.LENGTH_LONG).show();
17409442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann            }
17414a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann        }
17424a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann    }
17432ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1744