ContactEditorFragment.java revision 222744ea3cd7233677f0ef88804eb3e2db710e43
1cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann/*
2cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Copyright (C) 2010 Google Inc.
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
17cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannpackage com.android.contacts.views.editor;
18cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
19f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.JoinContactActivity;
20cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.R;
21cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.model.ContactsSource;
22f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.Editor;
23f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityDelta;
24f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityModifier;
25ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmannimport com.android.contacts.model.EntityDeltaList;
26f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.GoogleSource;
27cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.model.Sources;
28f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.ContactsSource.EditType;
29f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.Editor.EditorListener;
30f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityDelta.ValuesDelta;
31f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.ui.ViewIdGenerator;
32f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.ui.widget.BaseContactEditorView;
33f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.ui.widget.PhotoEditorView;
34f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.util.EmptyService;
35f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.util.WeakAsyncTask;
36bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmannimport com.android.contacts.views.ContactLoader;
37f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
38f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account;
39cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity;
40cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.AlertDialog;
41cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Dialog;
42222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.Fragment;
43222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager;
44222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks;
45cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ActivityNotFoundException;
46f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentProviderOperation;
47f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentProviderResult;
48f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentResolver;
49cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris;
50cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues;
51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context;
52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.DialogInterface;
53cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent;
54cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader;
55f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.OperationApplicationException;
56f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentProviderOperation.Builder;
57f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.DialogInterface.OnDismissListener;
58f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor;
59f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap;
60f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.media.MediaScannerConnection;
61cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri;
62f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.AsyncTask;
63cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle;
64f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.Environment;
65f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.RemoteException;
669767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock;
67f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.provider.ContactsContract;
68f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.provider.MediaStore;
69f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.provider.ContactsContract.AggregationExceptions;
70cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.Contacts;
71cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.RawContacts;
72cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email;
73cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone;
74cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log;
75f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.view.ContextThemeWrapper;
76cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater;
77cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu;
78cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater;
79cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem;
80cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View;
81cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup;
82f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.widget.ArrayAdapter;
8380d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout;
84f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.widget.ListAdapter;
85f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.widget.TextView;
86cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast;
87cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
88f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File;
89f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.text.SimpleDateFormat;
90cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList;
91f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections;
92f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator;
93f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Date;
94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
95222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannpublic class ContactEditorFragment extends Fragment {
96cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
97cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private static final String TAG = "ContactEditorFragment";
98cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
99f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int LOADER_DATA = 1;
100f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
101d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_URI = "uri";
102d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    private static final String KEY_ACTION = "action";
103f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_EDIT_STATE = "state";
104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
105f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
106f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_QUERY_SELECTION = "queryselection";
108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_QUERY_SELECTION_ARGS = "queryselectionargs";
109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static final int SAVE_MODE_DEFAULT = 0;
112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static final int SAVE_MODE_SPLIT = 1;
113f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static final int SAVE_MODE_JOIN = 2;
114f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
115f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mRawContactIdRequestingPhoto = -1;
116cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
117f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
118f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
119f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final String BUNDLE_SELECT_ACCOUNT_LIST = "account_list";
120f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
121f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final int ICON_SIZE = 96;
122f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
123f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private static final File PHOTO_DIR = new File(
124f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Environment.getExternalStorageDirectory() + "/DCIM/Camera");
125f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
126f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private File mCurrentPhotoFile;
127cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
128cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Context mContext;
129f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mAction;
130f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Uri mUri;
131f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mMimeType;
132f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Bundle mIntentExtras;
133cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    private Listener mListener;
134cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
135f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String mQuerySelection;
136f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String[] mQuerySelectionArgs;
137cc8bfc88f5c066b4e1b8d4a08eee52164decf24fDaniel Lehmann
138f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private long mContactIdForJoin;
139cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
140f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private LinearLayout mContent;
141ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    private EntityDeltaList mState;
142cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
143f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private ViewIdGenerator mViewIdGenerator;
144cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1459767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann    private long mLoaderStartTime;
1469767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann
147cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public ContactEditorFragment() {
148cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
149cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
150cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
151cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public void onAttach(Activity activity) {
152cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        super.onAttach(activity);
153cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        mContext = activity;
154cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
155cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
156cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
157cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
158cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false);
159cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
160f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent = (LinearLayout) view.findViewById(R.id.editors);
161e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann
1623648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann        setHasOptionsMenu(true);
163cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
164cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        return view;
165cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
166cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
167222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    @Override
168222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    public void onActivityCreated(Bundle savedInstanceState) {
169222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        super.onActivityCreated(savedInstanceState);
170222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
171222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        if (Intent.ACTION_EDIT.equals(mAction)) {
172222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit);
173222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener);
174222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        } else if (Intent.ACTION_INSERT.equals(mAction)) {
175222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert);
176222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
177222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            doAddAction();
178222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        } else throw new IllegalArgumentException("Unknown Action String " + mAction +
179222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT);
180222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    }
181222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
182f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void load(String action, Uri uri, String mimeType, Bundle intentExtras) {
183f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mAction = action;
184f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mUri = uri;
185f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mMimeType = mimeType;
186f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mIntentExtras = intentExtras;
187f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
189f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void setListener(Listener value) {
190f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mListener = value;
191cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
192cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
193cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    @Override
194f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onCreate(Bundle savedState) {
195d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        if (savedState != null) {
196d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // Restore mUri before calling super.onCreate so that onInitializeLoaders
197d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            // would already have a uri and an action to work with
198d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mUri = savedState.getParcelable(KEY_URI);
199d364314c460152db7089b304beec81b3675893baDmitri Plotnikov            mAction = savedState.getString(KEY_ACTION);
200d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        }
201d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onCreate(savedState);
203f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (savedState == null) {
205f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // If savedState is non-null, onRestoreInstanceState() will restore the generator.
206f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = new ViewIdGenerator();
207f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
208f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Read modifications from instance
209ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
210f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mRawContactIdRequestingPhoto = savedState.getLong(
211f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
212f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
213f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE);
214f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (fileName != null) {
215f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                mCurrentPhotoFile = new File(fileName);
216cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
217f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mQuerySelection = savedState.getString(KEY_QUERY_SELECTION);
218f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mQuerySelectionArgs = savedState.getStringArray(KEY_QUERY_SELECTION_ARGS);
219f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
220cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
221cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
222cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
223bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann    public void setData(ContactLoader.Result data) {
224ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann        mState = EntityDeltaList.fromIterator(data.getEntities().iterator());
225bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        // TODO: Merge in Intent parameters can only be done on the first load.
226bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        // The behaviour for subsequent loads is probably broken, so fix this
227bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        final boolean hasExtras = mIntentExtras != null && mIntentExtras.size() > 0;
228bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        final boolean hasState = mState.size() > 0;
229bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        if (hasExtras && hasState) {
230bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            // Find source defining the first RawContact found
231bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            // TODO: Test this. Can we actually always use the first RawContact. This seems wrong
232bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            final EntityDelta state = mState.get(0);
233bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
234bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            final Sources sources = Sources.getInstance(mContext);
235bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            final ContactsSource source = sources.getInflatedSource(accountType,
236bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann                    ContactsSource.LEVEL_CONSTRAINTS);
237bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann            EntityModifier.parseExtras(mContext, source, state, mIntentExtras);
238bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann        }
239f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
240f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
241cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
242f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void selectAccountAndCreateContact(ArrayList<Account> accounts, boolean isNewContact) {
243f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // No Accounts available.  Create a phone-local contact.
244f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (accounts.isEmpty()) {
245f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            createContact(null, isNewContact);
246f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;  // Don't show a dialog.
247f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
248cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
249f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // In the common case of a single account being writable, auto-select
250f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // it without showing a dialog.
251f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (accounts.size() == 1) {
252f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            createContact(accounts.get(0), isNewContact);
253f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;  // Don't show a dialog.
254f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
255f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
256f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Bundle bundle = new Bundle();
257f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bundle.putParcelableArrayList(BUNDLE_SELECT_ACCOUNT_LIST, accounts);
258f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        getActivity().showDialog(R.id.edit_dialog_select_account, bundle);
259cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
260cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
261cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    /**
262f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param account may be null to signal a device-local contact should
263f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *     be created.
264f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param prefillFromIntent If this is set, the intent extras will be used to prefill the fields
265cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann     */
266f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void createContact(Account account, boolean prefillFromIntent) {
267cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        final Sources sources = Sources.getInstance(mContext);
268f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ContentValues values = new ContentValues();
269f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (account != null) {
270f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.put(RawContacts.ACCOUNT_NAME, account.name);
271f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.put(RawContacts.ACCOUNT_TYPE, account.type);
272f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
273f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_NAME);
274f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            values.putNull(RawContacts.ACCOUNT_TYPE);
275cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
276cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
277f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Parse any values from incoming intent
278f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
279f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ContactsSource source = sources.getInflatedSource(
280f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                account != null ? account.type : null,
281f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                ContactsSource.LEVEL_CONSTRAINTS);
282f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityModifier.parseExtras(mContext, source, insert,
283f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                prefillFromIntent ? mIntentExtras : null);
284f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
285f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Ensure we have some default fields
286f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityModifier.ensureKindExists(insert, source, Phone.CONTENT_ITEM_TYPE);
287f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        EntityModifier.ensureKindExists(insert, source, Email.CONTENT_ITEM_TYPE);
288f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
289f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mState == null) {
290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Create state if none exists yet
291ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            mState = EntityDeltaList.fromSingle(insert);
292f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else {
293f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add contact onto end of existing state
294f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mState.add(insert);
295cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
296f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
297f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        bindEditors();
298cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
299cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
300f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void bindEditors() {
301f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Sort the editors
302f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Collections.sort(mState, mComparator);
303cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
304f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Remove any existing editors and rebuild any visible
305f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.removeAllViews();
306cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
307f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
308f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Context.LAYOUT_INFLATER_SERVICE);
309f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Sources sources = Sources.getInstance(mContext);
310f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int size = mState.size();
311f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        for (int i = 0; i < size; i++) {
312f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO ensure proper ordering of entities in the list
313f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final EntityDelta entity = mState.get(i);
314f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ValuesDelta values = entity.getValues();
315f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!values.isVisible()) continue;
316f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
317f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
318f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ContactsSource source = sources.getInflatedSource(accountType,
319f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    ContactsSource.LEVEL_CONSTRAINTS);
320f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final long rawContactId = values.getAsLong(RawContacts._ID);
321f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
322f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final BaseContactEditorView editor;
323f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!source.readOnly) {
324f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                editor = (BaseContactEditorView) inflater.inflate(R.layout.item_contact_editor,
325f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        mContent, false);
326f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else {
327f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                editor = (BaseContactEditorView) inflater.inflate(
328f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        R.layout.item_read_only_contact_editor, mContent, false);
329cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
330f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final PhotoEditorView photoEditor = editor.getPhotoEditor();
331f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            photoEditor.setEditorListener(new PhotoListener(rawContactId, source.readOnly,
332f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    photoEditor));
333cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
334f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContent.addView(editor);
335f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            editor.setState(entity, source, mViewIdGenerator);
336cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
337f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
338f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Show editor now that we've loaded state
339f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContent.setVisibility(View.VISIBLE);
340cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
341cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
342b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
343eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
344f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        inflater.inflate(R.menu.edit, menu);
345cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
346cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
347b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
348eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn    public void onPrepareOptionsMenu(Menu menu) {
349f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1);
350cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
351cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
352b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann    @Override
353cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public boolean onOptionsItemSelected(MenuItem item) {
354cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (item.getItemId()) {
355f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_done:
356f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSaveAction(SAVE_MODE_DEFAULT);
357f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_discard:
358f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doRevertAction();
359f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_add:
360f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doAddAction();
361f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_delete:
362f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doDeleteAction();
363f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_split:
364f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doSplitContactAction();
365f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.menu_join:
366f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return doJoinContactAction();
367f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
368f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
369f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
370cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
371f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doAddAction() {
372f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Load Accounts async so that we can present them
373f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        AsyncTask<Void, Void, ArrayList<Account>> loadAccountsTask =
374f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                new AsyncTask<Void, Void, ArrayList<Account>>() {
375f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    @Override
376f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    protected ArrayList<Account> doInBackground(Void... params) {
377f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        return Sources.getInstance(mContext).getAccounts(true);
378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
379f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    @Override
380f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    protected void onPostExecute(ArrayList<Account> result) {
381f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        selectAccountAndCreateContact(result, true);
382f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
383f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        };
384f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        loadAccountsTask.execute();
385cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
386f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
387f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
388cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
389f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
390f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Delete the entire contact currently being edited, which usually asks for
391f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * user confirmation before continuing.
392f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
393f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doDeleteAction() {
394f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState())
395f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
396f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int readOnlySourcesCnt = 0;
397f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int writableSourcesCnt = 0;
398f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // TODO: This shouldn't be called from the UI thread
399f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Sources sources = Sources.getInstance(mContext);
400f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        for (EntityDelta delta : mState) {
401f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final String accountType = delta.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
402f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ContactsSource contactsSource = sources.getInflatedSource(accountType,
403f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    ContactsSource.LEVEL_CONSTRAINTS);
404f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (contactsSource != null && contactsSource.readOnly) {
405f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                readOnlySourcesCnt += 1;
406f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else {
407f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                writableSourcesCnt += 1;
408cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
409cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
410cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
411f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (readOnlySourcesCnt > 0 && writableSourcesCnt > 0) {
412f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().showDialog(R.id.edit_dialog_confirm_readonly_delete);
413f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else if (readOnlySourcesCnt > 0 && writableSourcesCnt == 0) {
414f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().showDialog(R.id.edit_dialog_confirm_readonly_hide);
415f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } else if (readOnlySourcesCnt == 0 && writableSourcesCnt > 1) {
416f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().showDialog(R.id.edit_dialog_confirm_multiple_delete);
417cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        } else {
418f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().showDialog(R.id.edit_dialog_confirm_delete);
419cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
420f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
421f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
422f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
423f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
424f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Pick a specific photo to be added under the currently selected tab.
425f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
426f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /* package */ boolean doPickPhotoAction(long rawContactId) {
427f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
428f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
429f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mRawContactIdRequestingPhoto = rawContactId;
430f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
431f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        getActivity().showDialog(R.id.edit_dialog_pick_photo);
432f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return false;
433f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
434cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
435cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public Dialog onCreateDialog(int id, Bundle bundle) {
436cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        switch (id) {
437f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_confirm_delete:
438cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                return new AlertDialog.Builder(mContext)
439cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setTitle(R.string.deleteConfirmation_title)
440cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setIcon(android.R.drawable.ic_dialog_alert)
441cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setMessage(R.string.deleteConfirmation)
442cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setNegativeButton(android.R.string.cancel, null)
443f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        .setPositiveButton(android.R.string.ok, new DeleteClickListener())
444cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setCancelable(false)
445cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .create();
446f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_confirm_readonly_delete:
447cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                return new AlertDialog.Builder(mContext)
448cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setTitle(R.string.deleteConfirmation_title)
449cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setIcon(android.R.drawable.ic_dialog_alert)
450cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setMessage(R.string.readOnlyContactDeleteConfirmation)
451cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setNegativeButton(android.R.string.cancel, null)
452f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        .setPositiveButton(android.R.string.ok, new DeleteClickListener())
453cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setCancelable(false)
454cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .create();
455f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_confirm_multiple_delete:
456cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                return new AlertDialog.Builder(mContext)
457cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setTitle(R.string.deleteConfirmation_title)
458cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setIcon(android.R.drawable.ic_dialog_alert)
459cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setMessage(R.string.multipleContactDeleteConfirmation)
460cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setNegativeButton(android.R.string.cancel, null)
461f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        .setPositiveButton(android.R.string.ok, new DeleteClickListener())
462cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setCancelable(false)
463cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .create();
464f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_confirm_readonly_hide:
465cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                return new AlertDialog.Builder(mContext)
466cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setTitle(R.string.deleteConfirmation_title)
467cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setIcon(android.R.drawable.ic_dialog_alert)
468cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .setMessage(R.string.readOnlyContactWarning)
469f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        .setPositiveButton(android.R.string.ok, new DeleteClickListener())
470f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        .setCancelable(false)
471cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                        .create();
472f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_pick_photo:
473f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return createPickPhotoDialog();
474f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_split:
475f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return createSplitDialog();
476f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_dialog_select_account:
477f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return createSelectAccountDialog(bundle);
478f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            default:
479f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return null;
480f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
481f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
482f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
483f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Dialog createSelectAccountDialog(Bundle bundle) {
484f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ArrayList<Account> accounts = bundle.getParcelableArrayList(
485f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                BUNDLE_SELECT_ACCOUNT_LIST);
486f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Wrap our context to inflate list items using correct theme
487f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Context dialogContext = new ContextThemeWrapper(mContext,
488f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                android.R.style.Theme_Light);
489f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final LayoutInflater dialogInflater =
490f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                (LayoutInflater)dialogContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
491f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
492f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Sources sources = Sources.getInstance(mContext);
493f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
494f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ArrayAdapter<Account> accountAdapter = new ArrayAdapter<Account>(mContext,
495f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                android.R.layout.simple_list_item_2, accounts) {
496f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            @Override
497f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            public View getView(int position, View convertView, ViewGroup parent) {
498f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (convertView == null) {
499f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    convertView = dialogInflater.inflate(android.R.layout.simple_list_item_2,
500f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            parent, false);
501f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
502f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
503f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                // TODO: show icon along with title
504f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
505f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
506f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
507f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Account account = this.getItem(position);
508f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final ContactsSource source = sources.getInflatedSource(account.type,
509f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        ContactsSource.LEVEL_SUMMARY);
510f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
511f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                text1.setText(account.name);
512f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                text2.setText(source.getDisplayLabel(mContext));
513f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
514f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return convertView;
515f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
516f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        };
517f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
518f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final DialogInterface.OnClickListener clickListener =
519f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                new DialogInterface.OnClickListener() {
520f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            public void onClick(DialogInterface dialog, int which) {
521f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                dialog.dismiss();
522f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
523f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                // Create new contact based on selected source
524f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Account account = accountAdapter.getItem(which);
525f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                createContact(account, false);
526cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
527f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        };
528f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
529f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final DialogInterface.OnCancelListener cancelListener =
530f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                new DialogInterface.OnCancelListener() {
531f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            public void onCancel(DialogInterface dialog) {
532f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                // If nothing remains, close activity
533f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (!hasValidState()) {
534f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mListener.closeBecauseAccountSelectorAborted();
535cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann                }
536cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann            }
537f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        };
538f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
539f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
540f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setTitle(R.string.dialog_new_contact_account);
541f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setSingleChoiceItems(accountAdapter, 0, clickListener);
542f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setOnCancelListener(cancelListener);
543f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Dialog result = builder.create();
544f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        result.setOnDismissListener(new OnDismissListener() {
545f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            public void onDismiss(DialogInterface dialog) {
546f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                // TODO: Check if we even need this...seems useless
547f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                //removeDialog(DIALOG_SELECT_ACCOUNT);
548f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
549f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        });
550f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return result;
551f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
552f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
553f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSplitContactAction() {
554f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) return false;
555f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
556f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        getActivity().showDialog(R.id.edit_dialog_split);
557f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
558f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
559f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
560f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Dialog createSplitDialog() {
561f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
562f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setTitle(R.string.splitConfirmation_title);
563f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setIcon(android.R.drawable.ic_dialog_alert);
564f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setMessage(R.string.splitConfirmation);
565f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
566f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            public void onClick(DialogInterface dialog, int which) {
567f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                // Split the contacts
568f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                mState.splitRawContacts();
569f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                doSaveAction(SAVE_MODE_SPLIT);
570f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
571f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        });
572f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setNegativeButton(android.R.string.cancel, null);
573f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setCancelable(false);
574f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return builder.create();
575f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
576f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
577f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doJoinContactAction() {
578f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return doSaveAction(SAVE_MODE_JOIN);
579f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
580f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
581f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
582f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Creates a dialog offering two options: take a photo or pick a photo from the gallery.
583f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
584f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private Dialog createPickPhotoDialog() {
585f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Wrap our context to inflate list items using correct theme
586f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Context dialogContext = new ContextThemeWrapper(mContext,
587f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                android.R.style.Theme_Light);
588f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
589f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        String[] choices = new String[2];
590f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        choices[0] = mContext.getString(R.string.take_photo);
591f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        choices[1] = mContext.getString(R.string.pick_photo);
592f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ListAdapter adapter = new ArrayAdapter<String>(dialogContext,
593f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                android.R.layout.simple_list_item_1, choices);
594f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
595f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final AlertDialog.Builder builder = new AlertDialog.Builder(dialogContext);
596f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setTitle(R.string.attachToContact);
597f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.setSingleChoiceItems(adapter, -1, new DialogInterface.OnClickListener() {
598f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            public void onClick(DialogInterface dialog, int which) {
599f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                dialog.dismiss();
600f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                switch(which) {
601f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    case 0:
602f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        doTakePhoto();
603f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        break;
604f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    case 1:
605f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        doPickPhotoFromGallery();
606f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        break;
607f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
608f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
609f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        });
610f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return builder.create();
611f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
612f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
613f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
614f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
615f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Launches Gallery to pick a photo.
616f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
617f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    protected void doPickPhotoFromGallery() {
618f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
619f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Launch picker to choose photo for selected contact
620f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = getPhotoPickIntent();
621f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().startActivityForResult(intent,
622f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    R.id.edit_request_code_photo_picked_with_data);
623f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (ActivityNotFoundException e) {
624f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
625cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
626cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
627cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
628f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
629f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap.
630f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
631f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getPhotoPickIntent() {
632f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
633f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setType("image/*");
634f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
635f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
636f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
637f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputX", ICON_SIZE);
638f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputY", ICON_SIZE);
639f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
640f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
641f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
642f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
643f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
644f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Check if our internal {@link #mState} is valid, usually checked before
645f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * performing user actions.
646f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
647f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean hasValidState() {
648f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return mState != null && mState.size() > 0;
649f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
650f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
651f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
652f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Create a file name for the icon photo using current time.
653f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
654f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private String getPhotoFileName() {
655f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Date date = new Date(System.currentTimeMillis());
656f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
657f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return dateFormat.format(date) + ".jpg";
658f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
659f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
660f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
661f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Launches Camera to take a picture and store it in a file.
662f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
663f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    protected void doTakePhoto() {
664f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
665f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Launch camera to take photo for selected contact
666f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            PHOTO_DIR.mkdirs();
667f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
668f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = getTakePickIntent(mCurrentPhotoFile);
669f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
670f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().startActivityForResult(intent, R.id.edit_request_code_camera_with_data);
671f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (ActivityNotFoundException e) {
672f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
673f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
674f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
675f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
676f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
677f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for capturing a photo and storing it in a temporary file.
678f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
679f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getTakePickIntent(File f) {
680f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
681f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
682f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
683f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
684f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
685f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
686f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Sends a newly acquired photo to Gallery for cropping
687f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
688f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    protected void doCropPhoto(File f) {
689f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
690f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Add the image to the media store
691f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            MediaScannerConnection.scanFile(
692f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mContext,
693f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { f.getAbsolutePath() },
694f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    new String[] { null },
695f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    null);
696f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
697f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Launch gallery to crop the photo
698f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = getCropImageIntent(Uri.fromFile(f));
699f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            getActivity().startActivityForResult(intent,
700f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    R.id.edit_request_code_photo_picked_with_data);
701f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (Exception e) {
702f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Log.e(TAG, "Cannot crop image", e);
703f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show();
704cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
705cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
706cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
707f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
708f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Constructs an intent for image cropping.
709f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
710f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static Intent getCropImageIntent(Uri photoUri) {
711f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Intent intent = new Intent("com.android.camera.action.CROP");
712f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.setDataAndType(photoUri, "image/*");
713f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("crop", "true");
714f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectX", 1);
715f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("aspectY", 1);
716f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputX", ICON_SIZE);
717f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("outputY", ICON_SIZE);
718f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra("return-data", true);
719f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return intent;
720f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
721f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
722f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
723f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Saves or creates the contact based on the mode, and if successful
724f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * finishes the activity.
725f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
726f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doSaveAction(int saveMode) {
727f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (!hasValidState()) {
728f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return false;
729f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
730f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
731f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // TODO: Status still needed?
732f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        //mStatus = STATUS_SAVING;
733f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final PersistTask task = new PersistTask(this, saveMode);
734f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        task.execute(mState);
735f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
736f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
737f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
738f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
739ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    /**
740ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann     * Asynchonously saves the changes made by the user. This can be called even if nothing
741ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann     * has changed
742ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann     */
743ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    public void save() {
744ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann        doSaveAction(SAVE_MODE_DEFAULT);
745ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann    }
746ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann
747f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private boolean doRevertAction() {
748f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mListener != null) mListener.closeAfterRevert();
749f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
750f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        return true;
751f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
752f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
753f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void onSaveCompleted(boolean success, int saveMode, Uri contactLookupUri) {
754f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (saveMode) {
755f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case SAVE_MODE_DEFAULT:
756f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final Intent resultIntent;
757f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final int resultCode;
758f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (success && contactLookupUri != null) {
759f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final String requestAuthority = mUri == null ? null : mUri.getAuthority();
760f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
761f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final String legacyAuthority = "contacts";
762f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
763f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = new Intent();
764f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (legacyAuthority.equals(requestAuthority)) {
765f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Build legacy Uri when requested by caller
766f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final long contactId = ContentUris.parseId(Contacts.lookupContact(
767f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                mContext.getContentResolver(), contactLookupUri));
768f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyContentUri = Uri.parse("content://contacts/people");
769f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri legacyUri = ContentUris.withAppendedId(
770f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                legacyContentUri, contactId);
771f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(legacyUri);
772f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    } else {
773f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // Otherwise pass back a lookup-style Uri
774f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        resultIntent.setData(contactLookupUri);
775f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
776f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
777f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultCode = Activity.RESULT_OK;
778f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
779f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultCode = Activity.RESULT_CANCELED;
780f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    resultIntent = null;
781f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
782f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (mListener != null) mListener.closeAfterSaving(resultCode, resultIntent);
783f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
784f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case SAVE_MODE_SPLIT:
785f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (mListener != null) mListener.closeAfterSplit();
786f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
787f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
788f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case SAVE_MODE_JOIN:
789f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                //mStatus = STATUS_EDITING;
790f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (success) {
791f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    showJoinAggregateActivity(contactLookupUri);
792f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
793f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
794f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
795f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
796f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
797f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
798f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Shows a list of aggregates that can be joined into the currently viewed aggregate.
799f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     *
800f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * @param contactLookupUri the fresh URI for the currently edited contact (after saving it)
801f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
802f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void showJoinAggregateActivity(Uri contactLookupUri) {
803f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (contactLookupUri == null) {
804f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return;
805f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
806f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
807f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        mContactIdForJoin = ContentUris.parseId(contactLookupUri);
808f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT);
809f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin);
810f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        getActivity().startActivityForResult(intent, R.id.edit_request_code_join);
811f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
812f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
813f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private interface JoinContactQuery {
814f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        String[] PROJECTION = {
815f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                RawContacts._ID,
816f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                RawContacts.CONTACT_ID,
817f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                RawContacts.NAME_VERIFIED,
818f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        };
819f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
820f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        String SELECTION = RawContacts.CONTACT_ID + "=? OR " + RawContacts.CONTACT_ID + "=?";
821f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
822f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int _ID = 0;
823f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int CONTACT_ID = 1;
824f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        int NAME_VERIFIED = 2;
825f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
826f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
827f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
828f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Performs aggregation with the contact selected by the user from suggestions or A-Z list.
829f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
830f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void joinAggregate(final long contactId) {
831f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        final ContentResolver resolver = mContext.getContentResolver();
832f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
833f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Load raw contact IDs for all raw contacts involved - currently edited and selected
834f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // in the join UIs
835f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Cursor c = resolver.query(RawContacts.CONTENT_URI,
836f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                JoinContactQuery.PROJECTION,
837f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                JoinContactQuery.SELECTION,
838f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                new String[]{String.valueOf(contactId), String.valueOf(mContactIdForJoin)}, null);
839f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
840f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        long rawContactIds[];
841f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        long verifiedNameRawContactId = -1;
842f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
843f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            rawContactIds = new long[c.getCount()];
844f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            for (int i = 0; i < rawContactIds.length; i++) {
845f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                c.moveToNext();
846f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                long rawContactId = c.getLong(JoinContactQuery._ID);
847f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                rawContactIds[i] = rawContactId;
848f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (c.getLong(JoinContactQuery.CONTACT_ID) == mContactIdForJoin) {
849f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (verifiedNameRawContactId == -1
850f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            || c.getInt(JoinContactQuery.NAME_VERIFIED) != 0) {
851f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        verifiedNameRawContactId = rawContactId;
852f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
853f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
854b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann            }
855f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } finally {
856f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            c.close();
857cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
858f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
859f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // For each pair of raw contacts, insert an aggregation exception
860f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
861f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        for (int i = 0; i < rawContactIds.length; i++) {
862f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            for (int j = 0; j < rawContactIds.length; j++) {
863f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (i != j) {
864f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    buildJoinContactDiff(operations, rawContactIds[i], rawContactIds[j]);
865f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
866f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
867cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
868f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
869f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Mark the original contact as "name verified" to make sure that the contact
870f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // display name does not change as a result of the join
871f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Builder builder = ContentProviderOperation.newUpdate(
872f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, verifiedNameRawContactId));
873f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.withValue(RawContacts.NAME_VERIFIED, 1);
874f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        operations.add(builder.build());
875f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
876f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Apply all aggregation exceptions as one batch
877f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        try {
878f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            resolver.applyBatch(ContactsContract.AUTHORITY, operations);
879f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
880f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // We can use any of the constituent raw contacts to refresh the UI - why not the first
881f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Intent intent = new Intent();
882f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            intent.setData(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactIds[0]));
883f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
884f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Reload the new state from database
885f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO: Reload necessary or do we have a listener?
886f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            //new QueryEntitiesTask(this).execute(intent);
887f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
888f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.contactsJoinedMessage, Toast.LENGTH_LONG).show();
889f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (RemoteException e) {
890f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Log.e(TAG, "Failed to apply aggregation exception batch", e);
891f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
892f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        } catch (OperationApplicationException e) {
893f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Log.e(TAG, "Failed to apply aggregation exception batch", e);
894f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
895cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        }
896f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
897f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
898f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
899f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Construct a {@link AggregationExceptions#TYPE_KEEP_TOGETHER} ContentProviderOperation.
900f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
901f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private void buildJoinContactDiff(ArrayList<ContentProviderOperation> operations,
902f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            long rawContactId1, long rawContactId2) {
903f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        Builder builder =
904f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
905f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
906f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
907f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
908f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        operations.add(builder.build());
909f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
910cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
911cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    public static interface Listener {
912cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
913cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         * Contact was not found, so somehow close this fragment.
914cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
915f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void closeBecauseContactNotFound();
916f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
917f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
918f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Contact was split, so we can close now
919f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
920f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void closeAfterSplit();
921f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
922f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
923f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User was presented with an account selection and couldn't decide.
924f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
925f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void closeBecauseAccountSelectorAborted();
926f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
927f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
928f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User has tapped Revert, close the fragment now.
929f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
930f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void closeAfterRevert();
931cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
932cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
933f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * User has removed the contact, close the fragment now.
934cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
935f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void closeAfterDelete();
936f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
937f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
938f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Set the Title (e.g. of the Activity)
939f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
940f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void setTitleTo(int resourceId);
941f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
942f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
943f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Contact was
944f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * @param resultCode
945f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * @param resultIntent
946f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
947f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        void closeAfterSaving(int resultCode, Intent resultIntent);
948f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
949f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
950f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private class EntityDeltaComparator implements Comparator<EntityDelta> {
951f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /**
952f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Compare EntityDeltas for sorting the stack of editors.
953f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         */
954f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public int compare(EntityDelta one, EntityDelta two) {
955f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check direct equality
956f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (one.equals(two)) {
957f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 0;
958f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
959f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
960f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Sources sources = Sources.getInstance(mContext);
961f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String accountType = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
962f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ContactsSource oneSource = sources.getInflatedSource(accountType,
963f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    ContactsSource.LEVEL_SUMMARY);
964f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            accountType = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
965f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ContactsSource twoSource = sources.getInflatedSource(accountType,
966f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    ContactsSource.LEVEL_SUMMARY);
967f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
968f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check read-only
969f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneSource.readOnly && !twoSource.readOnly) {
970f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
971f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoSource.readOnly && !oneSource.readOnly) {
972f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
973f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
974f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
975f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account type
976f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean skipAccountTypeCheck = false;
977f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean oneIsGoogle = oneSource instanceof GoogleSource;
978f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            boolean twoIsGoogle = twoSource instanceof GoogleSource;
979f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneIsGoogle && !twoIsGoogle) {
980f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
981f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoIsGoogle && !oneIsGoogle) {
982f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
983f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (oneIsGoogle && twoIsGoogle){
984f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                skipAccountTypeCheck = true;
985f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
986f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
987f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            int value;
988f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!skipAccountTypeCheck) {
9892776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                if (oneSource.accountType == null) {
9902776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                    return 1;
9912776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru                }
992f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                value = oneSource.accountType.compareTo(twoSource.accountType);
993f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (value != 0) {
994f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    return value;
995f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
996f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
997f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
998f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Check account name
999f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta oneValues = one.getValues();
1000f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME);
1001f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneAccount == null) oneAccount = "";
1002f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            ValuesDelta twoValues = two.getValues();
1003f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME);
1004f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (twoAccount == null) twoAccount = "";
1005f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            value = oneAccount.compareTo(twoAccount);
1006f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (value != 0) {
1007f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return value;
1008f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1009f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1010f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Both are in the same account, fall back to contact ID
1011f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long oneId = oneValues.getAsLong(RawContacts._ID);
1012f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Long twoId = twoValues.getAsLong(RawContacts._ID);
1013f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (oneId == null) {
1014f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return -1;
1015f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (twoId == null) {
1016f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return 1;
1017f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1018f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1019f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return (int)(oneId - twoId);
1020f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1021f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1022f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1023f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1024f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Class that listens to requests coming from photo editors
1025f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1026f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private class PhotoListener implements EditorListener, DialogInterface.OnClickListener {
1027f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private long mRawContactId;
1028f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private boolean mReadOnly;
1029f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private PhotoEditorView mEditor;
1030f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1031f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public PhotoListener(long rawContactId, boolean readOnly, PhotoEditorView editor) {
1032f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mRawContactId = rawContactId;
1033f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mReadOnly = readOnly;
1034f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mEditor = editor;
1035f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1036f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1037f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public void onDeleted(Editor editor) {
1038f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Do nothing
1039f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1040f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1041f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public void onRequest(int request) {
1042f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (!hasValidState()) return;
1043f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1044f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (request == EditorListener.REQUEST_PICK_PHOTO) {
1045f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (mEditor.hasSetPhoto()) {
1046f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // There is an existing photo, offer to remove, replace, or promoto to primary
1047f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    createPhotoDialog().show();
1048f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else if (!mReadOnly) {
1049f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // No photo set and not read-only, try to set the photo
1050f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    doPickPhotoAction(mRawContactId);
1051f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1052f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1053f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1054cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1055cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
1056f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Prepare dialog for picking a new {@link EditType} or entering a
1057f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * custom label. This dialog is limited to the valid types as determined
1058f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * by {@link EntityModifier}.
1059cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
1060f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public Dialog createPhotoDialog() {
1061f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Wrap our context to inflate list items using correct theme
1062f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Context dialogContext = new ContextThemeWrapper(mContext,
1063f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    android.R.style.Theme_Light);
1064f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1065f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            String[] choices;
1066f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (mReadOnly) {
1067f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                choices = new String[1];
1068f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                choices[0] = mContext.getString(R.string.use_photo_as_primary);
1069f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else {
1070f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                choices = new String[3];
1071f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                choices[0] = mContext.getString(R.string.use_photo_as_primary);
1072f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                choices[1] = mContext.getString(R.string.removePicture);
1073f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                choices[2] = mContext.getString(R.string.changePicture);
1074f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1075f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ListAdapter adapter = new ArrayAdapter<String>(dialogContext,
1076f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    android.R.layout.simple_list_item_1, choices);
1077f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1078f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final AlertDialog.Builder builder = new AlertDialog.Builder(dialogContext);
1079f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            builder.setTitle(R.string.attachToContact);
1080f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            builder.setSingleChoiceItems(adapter, -1, this);
1081f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return builder.create();
1082f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1083cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann
1084cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann        /**
1085f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann         * Called when something in the dialog is clicked
1086cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann         */
1087f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public void onClick(DialogInterface dialog, int which) {
1088f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            dialog.dismiss();
1089f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1090f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            switch (which) {
1091f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                case 0:
1092f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // Set the photo as super primary
1093f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mEditor.setSuperPrimary(true);
1094f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1095f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // And set all other photos as not super primary
1096f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    int count = mContent.getChildCount();
1097f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    for (int i = 0; i < count; i++) {
1098f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        View childView = mContent.getChildAt(i);
1099f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        if (childView instanceof BaseContactEditorView) {
1100f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            BaseContactEditorView editor = (BaseContactEditorView) childView;
1101f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            PhotoEditorView photoEditor = editor.getPhotoEditor();
1102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            if (!photoEditor.equals(mEditor)) {
1103f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                photoEditor.setSuperPrimary(false);
1104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            }
1105f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        }
1106f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
1107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    break;
1108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                case 1:
1110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // Remove the photo
1111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mEditor.setPhotoBitmap(null);
1112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    break;
1113f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1114f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                case 2:
1115f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // Pick a new photo for the contact
1116f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    doPickPhotoAction(mRawContactId);
1117f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    break;
1118f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1119f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1120f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1121f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1122f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1123f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    private class DeleteClickListener implements DialogInterface.OnClickListener {
1124f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public void onClick(DialogInterface dialog, int which) {
1125f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // TODO: Don't do this from the UI thread
1126f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Sources sources = Sources.getInstance(mContext);
1127f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Mark all raw contacts for deletion
1128f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            for (EntityDelta delta : mState) {
1129f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                delta.markDeleted();
1130f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1131f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Save the deletes
1132f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            doSaveAction(SAVE_MODE_DEFAULT);
1133f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mListener.closeAfterDelete();
1134f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1135f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1136f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1137f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    // TODO: There has to be a nicer way than this WeakAsyncTask...? Maybe call a service?
1138f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    /**
1139f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * Background task for persisting edited contact data, using the changes
1140f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * defined by a set of {@link EntityDelta}. This task starts
1141f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * {@link EmptyService} to make sure the background thread can finish
1142f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     * persisting in cases where the system wants to reclaim our process.
1143f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann     */
1144f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public static class PersistTask extends
1145ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            WeakAsyncTask<EntityDeltaList, Void, Integer, ContactEditorFragment> {
1146f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private static final int PERSIST_TRIES = 3;
1147f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1148f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private static final int RESULT_UNCHANGED = 0;
1149f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private static final int RESULT_SUCCESS = 1;
1150f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private static final int RESULT_FAILURE = 2;
1151f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1152f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private final Context mContext;
1153f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1154f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private int mSaveMode;
1155f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        private Uri mContactLookupUri = null;
1156f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1157f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        public PersistTask(ContactEditorFragment target, int saveMode) {
1158f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            super(target);
1159f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mSaveMode = saveMode;
1160f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContext = target.mContext;
1161f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1162f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1163f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /** {@inheritDoc} */
1164f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        @Override
1165f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        protected void onPreExecute(ContactEditorFragment target) {
1166f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Before starting this task, start an empty service to protect our
1167f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // process from being reclaimed by the system.
1168f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContext.startService(new Intent(mContext, EmptyService.class));
1169f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1170f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1171f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /** {@inheritDoc} */
1172f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        @Override
1173ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann        protected Integer doInBackground(ContactEditorFragment target, EntityDeltaList... params) {
1174f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final ContentResolver resolver = mContext.getContentResolver();
1175f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1176ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann            EntityDeltaList state = params[0];
1177f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1178f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Trim any empty fields, and RawContacts, before persisting
1179f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final Sources sources = Sources.getInstance(mContext);
1180f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            EntityModifier.trimEmpty(state, sources);
1181f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1182f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Attempt to persist changes
1183f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            int tries = 0;
1184f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            Integer result = RESULT_FAILURE;
1185f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            while (tries++ < PERSIST_TRIES) {
1186f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                try {
1187f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // Build operations and try applying
1188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final ArrayList<ContentProviderOperation> diff = state.buildDiff();
1189f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    ContentProviderResult[] results = null;
1190f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (!diff.isEmpty()) {
1191f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                         results = resolver.applyBatch(ContactsContract.AUTHORITY, diff);
1192f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
1193f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1194f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long rawContactId = getRawContactId(state, diff, results);
1195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (rawContactId != -1) {
1196f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        final Uri rawContactUri = ContentUris.withAppendedId(
1197f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                RawContacts.CONTENT_URI, rawContactId);
1198f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1199f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        // convert the raw contact URI to a contact URI
1200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        mContactLookupUri = RawContacts.getContactLookupUri(resolver,
1201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                rawContactUri);
1202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
1203f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    result = (diff.size() > 0) ? RESULT_SUCCESS : RESULT_UNCHANGED;
1204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    break;
1205f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1206f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } catch (RemoteException e) {
1207f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // Something went wrong, bail without success
1208f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    Log.e(TAG, "Problem persisting user edits", e);
1209f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    break;
1210f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1211f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } catch (OperationApplicationException e) {
1212f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // Version consistency failed, re-parent change and try again
1213f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    Log.w(TAG, "Version consistency failed, re-parenting: " + e.toString());
1214ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann                    final EntityDeltaList newState = EntityDeltaList.fromQuery(resolver,
1215f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            target.mQuerySelection, target.mQuerySelectionArgs, null);
1216ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann                    state = EntityDeltaList.mergeAfter(newState, state);
1217f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1218f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1219f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1220f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return result;
1221f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1222f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1223ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann        private long getRawContactId(EntityDeltaList state,
1224f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final ArrayList<ContentProviderOperation> diff,
1225f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                final ContentProviderResult[] results) {
1226f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            long rawContactId = state.findRawContactId();
1227f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (rawContactId != -1) {
1228f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                return rawContactId;
1229f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1230f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1231f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // we gotta do some searching for the id
1232f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            final int diffSize = diff.size();
1233f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            for (int i = 0; i < diffSize; i++) {
1234f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                ContentProviderOperation operation = diff.get(i);
1235f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (operation.getType() == ContentProviderOperation.TYPE_INSERT
1236f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        && operation.getUri().getEncodedPath().contains(
1237f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                                RawContacts.CONTENT_URI.getEncodedPath())) {
1238f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    return ContentUris.parseId(results[i].uri);
1239f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1240f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1241f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            return -1;
1242f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1243f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1244f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        /** {@inheritDoc} */
1245f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        @Override
1246f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        protected void onPostExecute(ContactEditorFragment target, Integer result) {
1247f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            if (result == RESULT_SUCCESS && mSaveMode != SAVE_MODE_JOIN) {
1248f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show();
1249f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            } else if (result == RESULT_FAILURE) {
1250f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show();
1251f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1252f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1253f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Stop the service that was protecting us
1254f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            mContext.stopService(new Intent(mContext, EmptyService.class));
1255f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1256f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            target.onSaveCompleted(result != RESULT_FAILURE, mSaveMode, mContactLookupUri);
1257f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1258f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1259f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1260f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    @Override
1261f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onSaveInstanceState(Bundle outState) {
1262d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putParcelable(KEY_URI, mUri);
1263d364314c460152db7089b304beec81b3675893baDmitri Plotnikov        outState.putString(KEY_ACTION, mAction);
1264d364314c460152db7089b304beec81b3675893baDmitri Plotnikov
1265f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (hasValidState()) {
1266f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            // Store entities with modifications
1267f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putParcelable(KEY_EDIT_STATE, mState);
1268f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1269f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1270f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
1271f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
1272f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (mCurrentPhotoFile != null) {
1273f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString());
1274f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1275f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putString(KEY_QUERY_SELECTION, mQuerySelection);
1276f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putStringArray(KEY_QUERY_SELECTION_ARGS, mQuerySelectionArgs);
1277f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
1278f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        super.onSaveInstanceState(outState);
1279f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    }
1280f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1281d364314c460152db7089b304beec81b3675893baDmitri Plotnikov    @Override
1282f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann    public void onActivityResult(int requestCode, int resultCode, Intent data) {
1283f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        // Ignore failed requests
1284f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        if (resultCode != Activity.RESULT_OK) return;
1285f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        switch (requestCode) {
1286f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_request_code_photo_picked_with_data: {
1287f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                BaseContactEditorView requestingEditor = null;
1288f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                for (int i = 0; i < mContent.getChildCount(); i++) {
1289f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    View childView = mContent.getChildAt(i);
1290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    if (childView instanceof BaseContactEditorView) {
1291f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        BaseContactEditorView editor = (BaseContactEditorView) childView;
1292f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        if (editor.getRawContactId() == mRawContactIdRequestingPhoto) {
1293f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            requestingEditor = editor;
1294f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                            break;
1295f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                        }
1296f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    }
1297f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1298f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1299f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (requestingEditor != null) {
1300f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final Bitmap photo = data.getParcelableExtra("data");
1301f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    requestingEditor.setPhotoBitmap(photo);
1302f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    mRawContactIdRequestingPhoto = -1;
1303f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                } else {
1304f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // The contact that requested the photo is no longer present.
1305f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    // TODO: Show error message
1306f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1307f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1308f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1309f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1310f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann
1311f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_request_code_camera_with_data: {
1312f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                doCropPhoto(mCurrentPhotoFile);
1313f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                break;
1314f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1315f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            case R.id.edit_request_code_join: {
1316f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                if (data != null) {
1317f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    final long contactId = ContentUris.parseId(data.getData());
1318f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                    joinAggregate(contactId);
1319f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann                }
1320f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann            }
1321f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann        }
1322cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann    }
13239cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov
13249cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    public Uri getUri() {
13259cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov        return mUri;
13269cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov    }
1327222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1328222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    /**
1329222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     * The listener for the data loader
1330222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann     */
1331222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener =
1332222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            new LoaderCallbacks<ContactLoader.Result>() {
1333222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1334222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
1335222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            mLoaderStartTime = SystemClock.elapsedRealtime();
1336222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            return new ContactLoader(mContext, mUri);
1337222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1338222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1339222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        @Override
1340222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
1341222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long loaderCurrentTime = SystemClock.elapsedRealtime();
1342222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
1343222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            if (data == ContactLoader.Result.NOT_FOUND) {
1344222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                // Item has been deleted
1345222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                Log.i(TAG, "No contact found. Closing activity");
1346222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                if (mListener != null) mListener.closeBecauseContactNotFound();
1347222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann                return;
1348222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            }
1349222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann
1350222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataStartTime = SystemClock.elapsedRealtime();
1351222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            setData(data);
1352222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            final long setDataEndTime = SystemClock.elapsedRealtime();
1353222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann            Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime));
1354222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann        }
1355222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann    };
13562ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey}
1357