ContactEditorFragment.java revision 916cf2661ada41a83556884d8f5b322d32ef452b
1cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann/* 2ef3f8f045ed4150caa64749742227acd0e6b85d8Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project 3cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * 4cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License"); 5cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * you may not use this file except in compliance with the License. 6cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * You may obtain a copy of the License at 7cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * 8cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * http://www.apache.org/licenses/LICENSE-2.0 9cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * 10cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Unless required by applicable law or agreed to in writing, software 11cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS, 12cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * See the License for the specific language governing permissions and 14cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * limitations under the License 15cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */ 16cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 17cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannpackage com.android.contacts.views.editor; 18cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 19f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.JoinContactActivity; 20cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.R; 2135769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmannimport com.android.contacts.model.BaseAccountType; 22f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityDelta; 23f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityDelta.ValuesDelta; 24ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmannimport com.android.contacts.model.EntityDeltaList; 25f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityModifier; 2635769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmannimport com.android.contacts.model.GoogleAccountType; 2735769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmannimport com.android.contacts.model.AccountTypes; 28f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.util.EmptyService; 29f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.util.WeakAsyncTask; 30bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmannimport com.android.contacts.views.ContactLoader; 31e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport com.android.contacts.views.GroupMetaDataLoader; 32f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.views.editor.AggregationSuggestionEngine.Suggestion; 33afeae64e9a9bb39c918202a5775c4904e2f0d92eDaniel Lehmannimport com.android.contacts.views.editor.Editor.EditorListener; 34f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 35f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account; 36cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity; 37222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.Fragment; 38222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager; 39222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks; 40825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmannimport android.app.ProgressDialog; 41cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ActivityNotFoundException; 42f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentProviderOperation; 43f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.content.ContentProviderOperation.Builder; 44f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentProviderResult; 45f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.ContentResolver; 46cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris; 47cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues; 48cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context; 49e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader; 50e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikovimport android.content.Entity; 51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent; 52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader; 53f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.content.OperationApplicationException; 54f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor; 55f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap; 56f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.graphics.Rect; 57f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.media.MediaScannerConnection; 58cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri; 59cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle; 60f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.Environment; 61f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.RemoteException; 629767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock; 63f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.provider.ContactsContract; 64f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.provider.ContactsContract.AggregationExceptions; 65cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email; 66cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone; 6741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.StructuredName; 68f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts; 696a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikovimport android.provider.ContactsContract.Intents.Insert; 70f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 71f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.MediaStore; 7241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikovimport android.text.TextUtils; 73cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log; 74cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater; 75cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu; 76cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater; 77cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem; 78cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View; 79cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup; 80f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.view.ViewGroup.LayoutParams; 81f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.view.ViewStub; 8280d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout; 83f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.widget.TextView; 84cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast; 85cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 86f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File; 87825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmannimport java.lang.ref.WeakReference; 88f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.text.SimpleDateFormat; 89cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList; 90f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections; 91f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator; 92f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Date; 93f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List; 94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 95a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmannpublic class ContactEditorFragment extends Fragment implements 96a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann SplitContactConfirmationDialogFragment.Listener, PickPhotoDialogFragment.Listener, 974a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann SelectAccountDialogFragment.Listener, ModifyPhotoDialogFragment.Listener, 984a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann AggregationSuggestionEngine.Listener { 99cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 100cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann private static final String TAG = "ContactEditorFragment"; 101cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int LOADER_DATA = 1; 103e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private static final int LOADER_GROUPS = 2; 104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 105d364314c460152db7089b304beec81b3675893baDmitri Plotnikov private static final String KEY_URI = "uri"; 106d364314c460152db7089b304beec81b3675893baDmitri Plotnikov private static final String KEY_ACTION = "action"; 107f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_EDIT_STATE = "state"; 108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester"; 109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator"; 110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile"; 111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_QUERY_SELECTION = "queryselection"; 112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin"; 1139302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions"; 114f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 11515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 11615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Modes that specify what the AsyncTask has to perform after saving 11715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 11815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann private interface SaveMode { 11915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 12015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Close the editor after saving 12115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 12215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int CLOSE = 0; 12315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 12415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 12515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Reload the data so that the user can continue editing 12615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 12715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int RELOAD = 1; 12815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 12915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 13015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Split the contact after saving 13115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 13215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int SPLIT = 2; 13315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 13415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 13515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Join another contact after saving 13615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 13715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int JOIN = 3; 13815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann } 139a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 140825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann private interface Status { 141825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 142825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * The loader is fetching data 143825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 144825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int LOADING = 0; 145825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 146825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 147825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * Not currently busy. We are waiting for the user to enter data 148825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 149825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int EDITING = 1; 150825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 151825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 152825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * The data is currently being saved. This is used to prevent more auto-saves (they shouldn't 153825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * overlap) 154825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 155825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int SAVING = 2; 156825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 157825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 158825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * Prevents any more savings (this is used if Save/Close or Revert was executed by the user) 159825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 160825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int CLOSING = 3; 161825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 162825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 163a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann private static final int REQUEST_CODE_JOIN = 0; 164a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1; 165a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 2; 166f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 167c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann private Bitmap mPhoto = null; 168f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private long mRawContactIdRequestingPhoto = -1; 169c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann private long mRawContactIdRequestingPhotoAfterLoad = -1; 170cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 171f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private final EntityDeltaComparator mComparator = new EntityDeltaComparator(); 172f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 173f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int ICON_SIZE = 96; 174f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 175f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final File PHOTO_DIR = new File( 176f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Environment.getExternalStorageDirectory() + "/DCIM/Camera"); 177f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 178e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private Cursor mGroupMetaData; 179e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 180f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 181f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * A delay in milliseconds used for bringing aggregation suggestions to 182f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * the visible part of the screen. The reason this has to be done after 183f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * a delay is a race condition with the soft keyboard. The keyboard 184f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * may expand to display its own autocomplete suggestions, which will 185f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * reduce the visible area of the screen. We will yield to the keyboard 186f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * hoping that the delay is sufficient. If not - part of the 187f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * suggestion will be hidden, which is not fatal. 188f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 189f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private static final int AGGREGATION_SUGGESTION_SCROLL_DELAY = 200; 190f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 191f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private File mCurrentPhotoFile; 192cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 193cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann private Context mContext; 194f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private String mAction; 195b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann private Uri mLookupUri; 196f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private String mMimeType; 197f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private Bundle mIntentExtras; 198cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann private Listener mListener; 199cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private String mQuerySelection; 201cc8bfc88f5c066b4e1b8d4a08eee52164decf24fDaniel Lehmann 202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private long mContactIdForJoin; 203cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private LinearLayout mContent; 205ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann private EntityDeltaList mState; 206cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 207f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private ViewIdGenerator mViewIdGenerator; 208cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 2099767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann private long mLoaderStartTime; 2109767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann 211825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann private int mStatus; 212825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 213f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private AggregationSuggestionEngine mAggregationSuggestionEngine; 2149302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov private long mAggregationSuggestionsRawContactId; 2159302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov private View mAggregationSuggestionView; 216f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 217cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public ContactEditorFragment() { 218cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 219cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 220cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann @Override 221cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public void onAttach(Activity activity) { 222cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann super.onAttach(activity); 223cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann mContext = activity; 224cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 225cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 226cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann @Override 227f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onStop() { 228f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov super.onStop(); 229f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (mAggregationSuggestionEngine != null) { 230f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.quit(); 231f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 232825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // If anything was left unsaved, save it now but keep the editor open. 233825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) { 234825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann save(false); 235825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 236f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 237f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 238f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 239cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { 240cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false); 241cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 242f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent = (LinearLayout) view.findViewById(R.id.editors); 243e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann 2443648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann setHasOptionsMenu(true); 245cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 246825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // If we are in an orientation change, we already have mState (it was loaded by onCreate) 247825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (mState != null) { 248825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann bindEditors(); 249825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 250825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 251cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann return view; 252cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 253cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 254222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann @Override 255222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann public void onActivityCreated(Bundle savedInstanceState) { 256222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann super.onActivityCreated(savedInstanceState); 257222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 258825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")"); 259222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 260825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Handle initial actions only when existing state missing 2614a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final boolean hasIncomingState = savedInstanceState != null; 262825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 263825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (!hasIncomingState) { 264825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (Intent.ACTION_EDIT.equals(mAction)) { 265825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit); 266825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener); 267825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } else if (Intent.ACTION_INSERT.equals(mAction)) { 268825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert); 269825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 270e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann doAddAction(true); 271825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } else throw new IllegalArgumentException("Unknown Action String " + mAction + 272825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT); 273825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 274222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 275222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 276e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov @Override 277e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov public void onStart() { 278e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener); 279e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov super.onStart(); 280e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 281e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 282b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann public void load(String action, Uri lookupUri, String mimeType, Bundle intentExtras) { 283f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mAction = action; 284b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann mLookupUri = lookupUri; 285f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mMimeType = mimeType; 286f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mIntentExtras = intentExtras; 287f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 288f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 289f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void setListener(Listener value) { 290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mListener = value; 291cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 292cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 293cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann @Override 294f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void onCreate(Bundle savedState) { 295d364314c460152db7089b304beec81b3675893baDmitri Plotnikov if (savedState != null) { 296d364314c460152db7089b304beec81b3675893baDmitri Plotnikov // Restore mUri before calling super.onCreate so that onInitializeLoaders 297d364314c460152db7089b304beec81b3675893baDmitri Plotnikov // would already have a uri and an action to work with 298b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann mLookupUri = savedState.getParcelable(KEY_URI); 299d364314c460152db7089b304beec81b3675893baDmitri Plotnikov mAction = savedState.getString(KEY_ACTION); 300d364314c460152db7089b304beec81b3675893baDmitri Plotnikov } 301d364314c460152db7089b304beec81b3675893baDmitri Plotnikov 302f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann super.onCreate(savedState); 303f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 304f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (savedState == null) { 305f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // If savedState is non-null, onRestoreInstanceState() will restore the generator. 306f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mViewIdGenerator = new ViewIdGenerator(); 307f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 308825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Read state from savedState. No loading involved here 309ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE); 310f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mRawContactIdRequestingPhoto = savedState.getLong( 311f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann KEY_RAW_CONTACT_ID_REQUESTING_PHOTO); 312f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR); 313f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE); 314f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (fileName != null) { 315f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mCurrentPhotoFile = new File(fileName); 316cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 317f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mQuerySelection = savedState.getString(KEY_QUERY_SELECTION); 318f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN); 3199302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS); 320825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.EDITING; 321cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 322cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 323cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 324bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann public void setData(ContactLoader.Result data) { 325d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann // If we have already loaded data, we do not want to change it here to not confuse the user 326d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann if (mState != null) { 327d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann Log.v(TAG, "Ignoring background change. This will have to be rebased later"); 328d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann return; 329d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann } 330d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann 331825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Build Filter mQuerySelection 332825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann final ArrayList<Entity> entities = data.getEntities(); 333825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann final StringBuilder sb = new StringBuilder(RawContacts._ID + " IN("); 334825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann final int count = entities.size(); 335e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov for (int i = 0; i < count; i++) { 336e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov if (i > 0) { 337e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov sb.append(','); 338e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov } 339e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov sb.append(entities.get(i).getEntityValues().get(RawContacts._ID)); 340e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov } 341e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov sb.append(")"); 342e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov mQuerySelection = sb.toString(); 343e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov mState = EntityDeltaList.fromIterator(entities.iterator()); 344e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov 345825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Merge in Extras from Intent 346916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov if (mIntentExtras != null && mIntentExtras.size() > 0) { 34735769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final AccountTypes sources = AccountTypes.getInstance(mContext); 348916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov for (EntityDelta state : mState) { 349916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE); 350916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov final BaseAccountType source = sources.getInflatedSource(accountType, 351916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov BaseAccountType.LEVEL_CONSTRAINTS); 352916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov if (!source.readOnly) { 353916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov // Apply extras to the first writable raw contact only 354916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov EntityModifier.parseExtras(mContext, source, state, mIntentExtras); 355916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov mIntentExtras = null; 356916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov break; 357916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov } 358916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov } 359bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann } 360916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov 361f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann bindEditors(); 362f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 363cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 364e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann private void selectAccountAndCreateContact(boolean isNewContact) { 36535769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final ArrayList<Account> accounts = AccountTypes.getInstance(mContext).getAccounts(true); 366f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // No Accounts available. Create a phone-local contact. 367f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (accounts.isEmpty()) { 368f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann createContact(null, isNewContact); 369f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return; // Don't show a dialog. 370f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 371cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 372f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // In the common case of a single account being writable, auto-select 373f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // it without showing a dialog. 374f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (accounts.size() == 1) { 375f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann createContact(accounts.get(0), isNewContact); 376f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return; // Don't show a dialog. 377f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 3794a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment(isNewContact); 3804a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialog.setTargetFragment(this, 0); 3814a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG); 382cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 383cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 384cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann /** 385f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * @param account may be null to signal a device-local contact should 386f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * be created. 387f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * @param prefillFromIntent If this is set, the intent extras will be used to prefill the fields 388cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */ 389f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void createContact(Account account, boolean prefillFromIntent) { 39035769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final AccountTypes sources = AccountTypes.getInstance(mContext); 391f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ContentValues values = new ContentValues(); 392f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (account != null) { 393f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann values.put(RawContacts.ACCOUNT_NAME, account.name); 394f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann values.put(RawContacts.ACCOUNT_TYPE, account.type); 395f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 396f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann values.putNull(RawContacts.ACCOUNT_NAME); 397f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann values.putNull(RawContacts.ACCOUNT_TYPE); 398cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 399cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 400f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Parse any values from incoming intent 401f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values)); 40235769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final BaseAccountType source = sources.getInflatedSource( 403f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann account != null ? account.type : null, 40435769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann BaseAccountType.LEVEL_CONSTRAINTS); 405f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann EntityModifier.parseExtras(mContext, source, insert, 406f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann prefillFromIntent ? mIntentExtras : null); 407f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 408f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Ensure we have some default fields 409f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann EntityModifier.ensureKindExists(insert, source, Phone.CONTENT_ITEM_TYPE); 410f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann EntityModifier.ensureKindExists(insert, source, Email.CONTENT_ITEM_TYPE); 411f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 412f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (mState == null) { 413f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Create state if none exists yet 414ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann mState = EntityDeltaList.fromSingle(insert); 415f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 416f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Add contact onto end of existing state 417f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mState.add(insert); 418cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 419f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 420f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann bindEditors(); 421cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 422cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 423f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void bindEditors() { 424f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Sort the editors 425f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Collections.sort(mState, mComparator); 426cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 427f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Remove any existing editors and rebuild any visible 428f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent.removeAllViews(); 429cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 430f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( 431f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Context.LAYOUT_INFLATER_SERVICE); 43235769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final AccountTypes sources = AccountTypes.getInstance(mContext); 433f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int size = mState.size(); 434f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann for (int i = 0; i < size; i++) { 435f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // TODO ensure proper ordering of entities in the list 436f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final EntityDelta entity = mState.get(i); 437f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ValuesDelta values = entity.getValues(); 438f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!values.isVisible()) continue; 439f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 440f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 44135769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final BaseAccountType source = sources.getInflatedSource(accountType, 44235769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann BaseAccountType.LEVEL_CONSTRAINTS); 443f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long rawContactId = values.getAsLong(RawContacts._ID); 444f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 44572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final BaseRawContactEditorView editor; 446f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!source.readOnly) { 44772af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann editor = (BaseRawContactEditorView) inflater.inflate(R.layout.item_contact_editor, 448f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent, false); 449f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 45072af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann editor = (BaseRawContactEditorView) inflater.inflate( 451f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann R.layout.item_read_only_contact_editor, mContent, false); 452cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 453f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final PhotoEditorView photoEditor = editor.getPhotoEditor(); 4544a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final boolean sourceReadOnly = source.readOnly; 4554a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann photoEditor.setEditorListener(new EditorListener() { 4564a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 4574a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onRequest(int request) { 4584a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann if (!hasValidState()) return; 4594a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann 4604a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann if (request == EditorListener.REQUEST_PICK_PHOTO) { 4614a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann if (editor.hasSetPhoto()) { 4624a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // There is an existing photo, offer to remove, replace, or promote to 4634a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // primary 4644a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final ModifyPhotoDialogFragment fragment = 4654a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann new ModifyPhotoDialogFragment(sourceReadOnly, rawContactId); 4664a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann fragment.setTargetFragment(ContactEditorFragment.this, 0); 4674a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann fragment.show(getFragmentManager(), ModifyPhotoDialogFragment.TAG); 4684a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } else if (!sourceReadOnly) { 4694a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // No photo set and not read-only, try to set the photo 4704a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann doPickPhotoAction(rawContactId); 4714a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 4724a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 4734a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 4744a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann 4754a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 4764a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onDeleted(Editor removedEditor) { 4774a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 4784a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann }); 479cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 480f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent.addView(editor); 481f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann editor.setState(entity, source, mViewIdGenerator); 482f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 48372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann if (editor instanceof RawContactEditorView) { 48472af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final RawContactEditorView rawContactEditor = (RawContactEditorView) editor; 48572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final FieldEditorView nameEditor = rawContactEditor.getNameEditor(); 486f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov nameEditor.setEditorListener(new EditorListener() { 487f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 488f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 489f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onRequest(int request) { 49041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov onContactNameChange(request, rawContactEditor, nameEditor); 491f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 492f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 493f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 4944a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onDeleted(Editor removedEditor) { 495f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 496f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov }); 497f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 4989302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (rawContactId == mAggregationSuggestionsRawContactId) { 499f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov acquireAggregationSuggestions(rawContactEditor); 500f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 501f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 502cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 503f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 504e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov bindGroupMetaData(); 505e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 506f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Show editor now that we've loaded state 507f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent.setVisibility(View.VISIBLE); 508a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 509a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann // Refresh Action Bar as the visibility of the join command 510825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Activity can be null if we have been detached from the Activity 511825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann final Activity activity = getActivity(); 512825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (activity != null) activity.invalidateOptionsMenu(); 513cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 514cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 515e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private void bindGroupMetaData() { 516e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov if (mGroupMetaData == null) { 517e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov return; 518e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 519e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 520e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov int editorCount = mContent.getChildCount(); 521e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov for (int i = 0; i < editorCount; i++) { 52272af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i); 523e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov editor.setGroupMetaData(mGroupMetaData); 524e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 525e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 526e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 527b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann @Override 528eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) { 529f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann inflater.inflate(R.menu.edit, menu); 530cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 531cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 532b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann @Override 533eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn public void onPrepareOptionsMenu(Menu menu) { 534f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1); 535cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 536cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 537b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann @Override 538cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public boolean onOptionsItemSelected(MenuItem item) { 539cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann switch (item.getItemId()) { 540f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_done: 54115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann return doSaveAction(SaveMode.CLOSE); 542f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_discard: 543f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doRevertAction(); 544328a7c9bba58e77b8a91f91d717307b32958640aDaniel Lehmann case R.id.menu_add_raw_contact: 545e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann return doAddAction(false); 546f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_delete: 547f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doDeleteAction(); 548f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_split: 549f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doSplitContactAction(); 550f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_join: 551f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doJoinContactAction(); 552f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 553f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return false; 554f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 555cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 556e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann private boolean doAddAction(boolean isNewContact) { 557f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Load Accounts async so that we can present them 558e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann selectAccountAndCreateContact(isNewContact); 559cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 560f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 561f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 562cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 563f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 564f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Delete the entire contact currently being edited, which usually asks for 565f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * user confirmation before continuing. 566f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 567f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doDeleteAction() { 568f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!hasValidState()) 569f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return false; 570cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 571b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann // TODO: Make sure Insert turns into Edit if/once it is autosaved 572b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann if (Intent.ACTION_INSERT.equals(mAction)) { 573b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann if (mListener != null) mListener.onReverted(); 574cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } else { 575b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann if (mListener != null) mListener.onDeleteRequested(mLookupUri); 576cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 577f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 578f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 579f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 580f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 581f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Pick a specific photo to be added under the currently selected tab. 582f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 583f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /* package */ boolean doPickPhotoAction(long rawContactId) { 584f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!hasValidState()) return false; 585f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 586f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mRawContactIdRequestingPhoto = rawContactId; 5874a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final PickPhotoDialogFragment dialogFragment = new PickPhotoDialogFragment(); 5884a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialogFragment.setTargetFragment(this, 0); 5894a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialogFragment.show(getFragmentManager(), PickPhotoDialogFragment.TAG); 590f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 591a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann return true; 592f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 593f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 594f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doSplitContactAction() { 595f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!hasValidState()) return false; 596f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 597a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann final SplitContactConfirmationDialogFragment dialog = 5984a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann new SplitContactConfirmationDialogFragment(); 5994a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialog.setTargetFragment(this, 0); 6004a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG); 601f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 602f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 603f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 604f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doJoinContactAction() { 60515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann return doSaveAction(SaveMode.JOIN); 606f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 607f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 608f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 609f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap. 610f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 611f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public static Intent getPhotoPickIntent() { 612f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); 613f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.setType("image/*"); 614f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("crop", "true"); 615f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectX", 1); 616f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectY", 1); 617f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("outputX", ICON_SIZE); 618f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("outputY", ICON_SIZE); 619f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("return-data", true); 620f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return intent; 621f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 622f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 623f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 624f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Check if our internal {@link #mState} is valid, usually checked before 625f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * performing user actions. 626f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 627f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean hasValidState() { 628f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return mState != null && mState.size() > 0; 629f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 630f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 631f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 632f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Create a file name for the icon photo using current time. 633f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 634f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private String getPhotoFileName() { 635f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Date date = new Date(System.currentTimeMillis()); 636f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss"); 637f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return dateFormat.format(date) + ".jpg"; 638f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 639f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 640f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 641f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Constructs an intent for capturing a photo and storing it in a temporary file. 642f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 643f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public static Intent getTakePickIntent(File f) { 644f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null); 645f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); 646f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return intent; 647f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 648f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 649f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 650f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Sends a newly acquired photo to Gallery for cropping 651f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 652f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann protected void doCropPhoto(File f) { 653f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann try { 654f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Add the image to the media store 655f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann MediaScannerConnection.scanFile( 656f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext, 657f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann new String[] { f.getAbsolutePath() }, 658f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann new String[] { null }, 659f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann null); 660f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 661f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Launch gallery to crop the photo 662f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Intent intent = getCropImageIntent(Uri.fromFile(f)); 663a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA); 664f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } catch (Exception e) { 665f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Log.e(TAG, "Cannot crop image", e); 666f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); 667cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 668cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 669cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 670f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 671f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Constructs an intent for image cropping. 672f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 673f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public static Intent getCropImageIntent(Uri photoUri) { 674f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Intent intent = new Intent("com.android.camera.action.CROP"); 675f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.setDataAndType(photoUri, "image/*"); 676f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("crop", "true"); 677f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectX", 1); 678f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectY", 1); 679f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("outputX", ICON_SIZE); 680f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("outputY", ICON_SIZE); 681f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("return-data", true); 682f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return intent; 683f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 684f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 685f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 686f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Saves or creates the contact based on the mode, and if successful 687f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * finishes the activity. 688f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 689f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doSaveAction(int saveMode) { 690f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!hasValidState()) { 691f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return false; 692f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 693f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 6948c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov // If we are about to close the editor - there is no need to refresh the data 6958c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov if (saveMode == SaveMode.CLOSE) { 6968c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov getLoaderManager().stopLoader(LOADER_DATA); 6978c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov } 6988c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov 699825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.SAVING; 7006cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov 7016cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov // Trim any empty fields, and RawContacts, before persisting 70235769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final AccountTypes sources = AccountTypes.getInstance(mContext); 7036cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov EntityModifier.trimEmpty(mState, sources); 7046cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov 7056cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov if (mState.buildDiff().isEmpty()) { 7066cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov onSaveCompleted(true, saveMode, mLookupUri); 7076cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov return true; 7086cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov } 7096cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov 710f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final PersistTask task = new PersistTask(this, saveMode); 711f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann task.execute(mState); 712f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 713f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 714f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 715f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 716ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann /** 717f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Asynchronously saves the changes made by the user. This can be called even if nothing 718ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann * has changed 719ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann */ 72015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public void save(boolean closeAfterSave) { 72115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann doSaveAction(closeAfterSave ? SaveMode.CLOSE : SaveMode.RELOAD); 722ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann } 723ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann 724f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doRevertAction() { 725825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // When this Fragment is closed we don't want it to auto-save 726825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.CLOSING; 72722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann if (mListener != null) mListener.onReverted(); 728f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 729f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 730f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 731f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 732f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void onSaveCompleted(boolean success, int saveMode, Uri contactLookupUri) { 73315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann Log.d(TAG, "onSaveCompleted(" + success + ", " + saveMode + ", " + contactLookupUri); 734f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann switch (saveMode) { 73515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.CLOSE: 736f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Intent resultIntent; 737f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final int resultCode; 738f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (success && contactLookupUri != null) { 739b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann final String requestAuthority = 740b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann mLookupUri == null ? null : mLookupUri.getAuthority(); 741f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 742f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final String legacyAuthority = "contacts"; 743f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 744f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent = new Intent(); 745f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (legacyAuthority.equals(requestAuthority)) { 746f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Build legacy Uri when requested by caller 747f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long contactId = ContentUris.parseId(Contacts.lookupContact( 748f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext.getContentResolver(), contactLookupUri)); 749f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Uri legacyContentUri = Uri.parse("content://contacts/people"); 750f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Uri legacyUri = ContentUris.withAppendedId( 751f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann legacyContentUri, contactId); 752f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent.setData(legacyUri); 753f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 754f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Otherwise pass back a lookup-style Uri 755f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent.setData(contactLookupUri); 756f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 757f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 758f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultCode = Activity.RESULT_OK; 759f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 760f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultCode = Activity.RESULT_CANCELED; 761f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent = null; 762f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 763825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // It is already saved, so prevent that it is saved again 764825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.CLOSING; 76522fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann if (mListener != null) mListener.onSaveFinished(resultCode, resultIntent); 766f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 76715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.RELOAD: 76815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann if (success && contactLookupUri != null) { 76915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann // If this was in INSERT, we are changing into an EDIT now. 77015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann // If it already was an EDIT, we are changing to the new Uri now 77115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann mState = null; 77215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann load(Intent.ACTION_EDIT, contactLookupUri, mMimeType, null); 773825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.LOADING; 77415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener); 77515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann } 77615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann break; 77715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.SPLIT: 778a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann if (mListener != null) { 7798c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov mListener.onContactSplit(contactLookupUri); 780a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } else { 781a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann Log.d(TAG, "No listener registered, can not call onSplitFinished"); 782a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 783825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.EDITING; 784f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 785f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 78615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.JOIN: 787f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (success) { 788f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann showJoinAggregateActivity(contactLookupUri); 789f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 790825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.EDITING; 791f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 792f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 793f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 794f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 795f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 796f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Shows a list of aggregates that can be joined into the currently viewed aggregate. 797f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * 798f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * @param contactLookupUri the fresh URI for the currently edited contact (after saving it) 799f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 800f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void showJoinAggregateActivity(Uri contactLookupUri) { 801f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (contactLookupUri == null) { 802f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return; 803f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 804f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 805f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContactIdForJoin = ContentUris.parseId(contactLookupUri); 806f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT); 807f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin); 808a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_JOIN); 809f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 810f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 811f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private interface JoinContactQuery { 812f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String[] PROJECTION = { 813f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann RawContacts._ID, 814f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann RawContacts.CONTACT_ID, 815f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann RawContacts.NAME_VERIFIED, 816f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann }; 817f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 818f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String SELECTION = RawContacts.CONTACT_ID + "=? OR " + RawContacts.CONTACT_ID + "=?"; 819f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 820f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int _ID = 0; 821f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int CONTACT_ID = 1; 822f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int NAME_VERIFIED = 2; 823f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 824f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 825f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 826f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Performs aggregation with the contact selected by the user from suggestions or A-Z list. 827f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 828f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void joinAggregate(final long contactId) { 829f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ContentResolver resolver = mContext.getContentResolver(); 830f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 831f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Load raw contact IDs for all raw contacts involved - currently edited and selected 832f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // in the join UIs 833f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Cursor c = resolver.query(RawContacts.CONTENT_URI, 834f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann JoinContactQuery.PROJECTION, 835f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann JoinContactQuery.SELECTION, 836f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann new String[]{String.valueOf(contactId), String.valueOf(mContactIdForJoin)}, null); 837f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 838f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann long rawContactIds[]; 839f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann long verifiedNameRawContactId = -1; 840f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann try { 841f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann rawContactIds = new long[c.getCount()]; 842f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann for (int i = 0; i < rawContactIds.length; i++) { 843f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann c.moveToNext(); 844f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann long rawContactId = c.getLong(JoinContactQuery._ID); 845f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann rawContactIds[i] = rawContactId; 846f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (c.getLong(JoinContactQuery.CONTACT_ID) == mContactIdForJoin) { 847f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (verifiedNameRawContactId == -1 848f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann || c.getInt(JoinContactQuery.NAME_VERIFIED) != 0) { 849f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann verifiedNameRawContactId = rawContactId; 850f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 851f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 852b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann } 853f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } finally { 854f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann c.close(); 855cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 856f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 857f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // For each pair of raw contacts, insert an aggregation exception 858f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>(); 859f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann for (int i = 0; i < rawContactIds.length; i++) { 860f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann for (int j = 0; j < rawContactIds.length; j++) { 861f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (i != j) { 862f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann buildJoinContactDiff(operations, rawContactIds[i], rawContactIds[j]); 863f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 864f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 865cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 866f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 867f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Mark the original contact as "name verified" to make sure that the contact 868f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // display name does not change as a result of the join 869f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Builder builder = ContentProviderOperation.newUpdate( 870f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ContentUris.withAppendedId(RawContacts.CONTENT_URI, verifiedNameRawContactId)); 871f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann builder.withValue(RawContacts.NAME_VERIFIED, 1); 872f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann operations.add(builder.build()); 873f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 8748c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov boolean success = false; 875f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Apply all aggregation exceptions as one batch 876f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann try { 877f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resolver.applyBatch(ContactsContract.AUTHORITY, operations); 8788c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov Toast.makeText(mContext, R.string.contactsJoinedMessage, Toast.LENGTH_LONG).show(); 8798c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov success = true; 880f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } catch (RemoteException e) { 881f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Log.e(TAG, "Failed to apply aggregation exception batch", e); 882f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show(); 883f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } catch (OperationApplicationException e) { 884f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Log.e(TAG, "Failed to apply aggregation exception batch", e); 885f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show(); 886cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 887a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 8888c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov if (success) { 8898c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov onSaveCompleted(true, SaveMode.RELOAD, mLookupUri); 890a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 891f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 892f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 893f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 894f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Construct a {@link AggregationExceptions#TYPE_KEEP_TOGETHER} ContentProviderOperation. 895f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 896f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void buildJoinContactDiff(ArrayList<ContentProviderOperation> operations, 897f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann long rawContactId1, long rawContactId2) { 898f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Builder builder = 899f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI); 900f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER); 901f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1); 902f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2); 903f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann operations.add(builder.build()); 904f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 905cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 906cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public static interface Listener { 907cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann /** 90822fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann * Contact was not found, so somehow close this fragment. This is raised after a contact 90922fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann * is removed via Menu/Delete (unless it was a new contact) 910cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */ 91122fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann void onContactNotFound(); 912f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 913f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 9148c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov * Contact was split, so we can close now. 915a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * @param newLookupUri The lookup uri of the new contact that should be shown to the user. 916a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * The editor tries best to chose the most natural contact here. 917f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 9188c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov void onContactSplit(Uri newLookupUri); 919f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 920f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 921f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * User was presented with an account selection and couldn't decide. 922f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 92322fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann void onAccountSelectorAborted(); 924f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 925f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 926f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * User has tapped Revert, close the fragment now. 927f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 92822fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann void onReverted(); 929f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 930f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 931f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Set the Title (e.g. of the Activity) 932f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 933f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann void setTitleTo(int resourceId); 934f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 935f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 93622fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann * Contact was saved and the Fragment can now be closed safely. 937f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 93822fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann void onSaveFinished(int resultCode, Intent resultIntent); 939b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann 940b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann /** 941b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann * User decided to delete the contact. 942b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann */ 943a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann void onDeleteRequested(Uri lookupUri); 944f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 945f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 946f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private class EntityDeltaComparator implements Comparator<EntityDelta> { 947f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 948f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Compare EntityDeltas for sorting the stack of editors. 949f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 9504a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 951f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public int compare(EntityDelta one, EntityDelta two) { 952f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check direct equality 953f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (one.equals(two)) { 954f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 0; 955f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 956f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 95735769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final AccountTypes sources = AccountTypes.getInstance(mContext); 958f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String accountType = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE); 95935769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final BaseAccountType oneSource = sources.getInflatedSource(accountType, 96035769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann BaseAccountType.LEVEL_SUMMARY); 961f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann accountType = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE); 96235769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann final BaseAccountType twoSource = sources.getInflatedSource(accountType, 96335769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann BaseAccountType.LEVEL_SUMMARY); 964f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 965f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check read-only 966f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (oneSource.readOnly && !twoSource.readOnly) { 967f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 1; 968f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else if (twoSource.readOnly && !oneSource.readOnly) { 969f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 970f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 971f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 972f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check account type 973f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann boolean skipAccountTypeCheck = false; 97435769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann boolean oneIsGoogle = oneSource instanceof GoogleAccountType; 97535769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmann boolean twoIsGoogle = twoSource instanceof GoogleAccountType; 976f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (oneIsGoogle && !twoIsGoogle) { 977f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 978f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else if (twoIsGoogle && !oneIsGoogle) { 979f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 1; 980f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else if (oneIsGoogle && twoIsGoogle){ 981f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann skipAccountTypeCheck = true; 982f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 983f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 984f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int value; 985f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!skipAccountTypeCheck) { 9862776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru if (oneSource.accountType == null) { 9872776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru return 1; 9882776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru } 989f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann value = oneSource.accountType.compareTo(twoSource.accountType); 990f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (value != 0) { 991f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return value; 992f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 993f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 994f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 995f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check account name 996f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ValuesDelta oneValues = one.getValues(); 997f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME); 998f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (oneAccount == null) oneAccount = ""; 999f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ValuesDelta twoValues = two.getValues(); 1000f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME); 1001f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (twoAccount == null) twoAccount = ""; 1002f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann value = oneAccount.compareTo(twoAccount); 1003f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (value != 0) { 1004f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return value; 1005f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1006f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1007f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Both are in the same account, fall back to contact ID 1008f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Long oneId = oneValues.getAsLong(RawContacts._ID); 1009f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Long twoId = twoValues.getAsLong(RawContacts._ID); 1010f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (oneId == null) { 1011f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 1012f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else if (twoId == null) { 1013f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 1; 1014f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1015f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1016f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return (int)(oneId - twoId); 1017f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1018f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1019f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1020f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1021f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Returns the contact ID for the currently edited contact or 0 if the contact is new. 1022f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 1023f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov protected long getContactId() { 1024f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov for (EntityDelta rawContact : mState) { 1025f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID); 1026f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (contactId != null) { 1027f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return contactId; 1028f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1029f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1030f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return 0; 1031f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1032f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 103341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 103472af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann private void onContactNameChange(int request, final RawContactEditorView rawContactEditor, 103572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann FieldEditorView nameEditor) { 103641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 103741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov switch (request) { 103841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov case EditorListener.EDITOR_FORM_CHANGED: 10390b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov if (nameEditor.hasShortAndLongForms()) { 10400b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov if (nameEditor.areOptionalFieldsVisible()) { 10410b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov switchFromFullNameToStructuredName(nameEditor); 10420b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov } else { 10430b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov switchFromStructuredNameToFullName(nameEditor); 10440b85aed7ae694341ea226c88bf10c0e11ea990ceDmitri Plotnikov } 104541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 104641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov break; 104741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 104841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov case EditorListener.FIELD_CHANGED: 1049dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov if (nameEditor.hasShortAndLongForms()) { 1050dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov if (nameEditor.areOptionalFieldsVisible()) { 1051dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov eraseFullName(nameEditor.getValues()); 1052dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov } else { 1053dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov eraseStructuredName(nameEditor.getValues()); 1054dbf3e60e3b3cfbd7114d319d6c9ea0cdab5997afDmitri Plotnikov } 105541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 105641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov acquireAggregationSuggestions(rawContactEditor); 105741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov break; 105841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 105941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 106041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 106172af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann private void switchFromFullNameToStructuredName(FieldEditorView nameEditor) { 106241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov ValuesDelta values = nameEditor.getValues(); 106341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 106441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov String displayName = values.getAsString(StructuredName.DISPLAY_NAME); 106541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov if (displayName == null) { 106641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov displayName = ""; 106741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 106841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 106941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov Uri uri = ContactsContract.AUTHORITY_URI.buildUpon().appendPath("complete_name") 107041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov .appendQueryParameter(StructuredName.DISPLAY_NAME, displayName).build(); 107141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{ 107241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov StructuredName.PREFIX, 107341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov StructuredName.GIVEN_NAME, 107441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov StructuredName.MIDDLE_NAME, 107541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov StructuredName.FAMILY_NAME, 107641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov StructuredName.SUFFIX, 107741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov }, null, null, null); 107841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 107941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov try { 108041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov if (cursor.moveToFirst()) { 108141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov eraseFullName(values); 108241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.put(StructuredName.PREFIX, cursor.getString(0)); 108341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.put(StructuredName.GIVEN_NAME, cursor.getString(1)); 108441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.put(StructuredName.MIDDLE_NAME, cursor.getString(2)); 108541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.put(StructuredName.FAMILY_NAME, cursor.getString(3)); 108641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.put(StructuredName.SUFFIX, cursor.getString(4)); 108741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 108841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } finally { 108941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov cursor.close(); 109041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 109141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 109241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 109372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann private void switchFromStructuredNameToFullName(FieldEditorView nameEditor) { 109441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov ValuesDelta values = nameEditor.getValues(); 109541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 109641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov Uri.Builder builder = ContactsContract.AUTHORITY_URI.buildUpon().appendPath( 109741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov "complete_name"); 109841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov appendQueryParameter(builder, values, StructuredName.PREFIX); 109941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov appendQueryParameter(builder, values, StructuredName.GIVEN_NAME); 110041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov appendQueryParameter(builder, values, StructuredName.MIDDLE_NAME); 110141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov appendQueryParameter(builder, values, StructuredName.FAMILY_NAME); 110241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov appendQueryParameter(builder, values, StructuredName.SUFFIX); 110341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov Uri uri = builder.build(); 110441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov Cursor cursor = getActivity().getContentResolver().query(uri, new String[]{ 110541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov StructuredName.DISPLAY_NAME, 110641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov }, null, null, null); 110741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 110841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov try { 110941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov if (cursor.moveToFirst()) { 111041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov eraseStructuredName(values); 111141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.put(StructuredName.DISPLAY_NAME, cursor.getString(0)); 111241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 111341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } finally { 111441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov cursor.close(); 111541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 111641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 111741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 111841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov private void eraseFullName(ValuesDelta values) { 111941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.putNull(StructuredName.DISPLAY_NAME); 112041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 112141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 112241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov private void eraseStructuredName(ValuesDelta values) { 112341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.putNull(StructuredName.PREFIX); 112441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.putNull(StructuredName.GIVEN_NAME); 112541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.putNull(StructuredName.MIDDLE_NAME); 112641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.putNull(StructuredName.FAMILY_NAME); 112741f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov values.putNull(StructuredName.SUFFIX); 112841f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 112941f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 113041f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov private void appendQueryParameter(Uri.Builder builder, ValuesDelta values, String field) { 113141f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov String value = values.getAsString(field); 113241f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov if (!TextUtils.isEmpty(value)) { 113341f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov builder.appendQueryParameter(field, value); 113441f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 113541f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov } 113641f026d52e0277e21236787b10f76129a8bc6fa4Dmitri Plotnikov 1137f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 1138f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Triggers an asynchronous search for aggregation suggestions. 1139f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 114072af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann public void acquireAggregationSuggestions(RawContactEditorView rawContactEditor) { 11419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov long rawContactId = rawContactEditor.getRawContactId(); 11429302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (mAggregationSuggestionsRawContactId != rawContactId 11439302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov && mAggregationSuggestionView != null) { 11449302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView.setVisibility(View.GONE); 11459302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView = null; 11469302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionEngine.reset(); 11479302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 11489302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 11499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionsRawContactId = rawContactId; 11509302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 1151f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (mAggregationSuggestionEngine == null) { 1152f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine = new AggregationSuggestionEngine(getActivity()); 1153f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.setListener(this); 1154f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.start(); 1155f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1156f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1157916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov mAggregationSuggestionEngine.setContactId(getContactId()); 1158916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov 115972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann FieldEditorView nameEditor = rawContactEditor.getNameEditor(); 1160f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.onNameChange(nameEditor.getValues()); 1161f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1162f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1163f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 1164f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onAggregationSuggestionChange() { 11659302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov View rawContactView = getContactEditorView(mAggregationSuggestionsRawContactId); 11669302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (rawContactView == null) { 11679302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov return; 11689302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 1169f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 11709302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov ViewStub stub = (ViewStub)rawContactView.findViewById(R.id.aggregation_suggestion_stub); 1171f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (stub != null) { 1172f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov stub.inflate(); 1173f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1174f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 11759302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov // Only request the view on screen when it is first displayed 11769302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov boolean requestOnScreen = mAggregationSuggestionView == null; 11779302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView = rawContactView.findViewById(R.id.aggregation_suggestion); 1178f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1179f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov int count = mAggregationSuggestionEngine.getSuggestedContactCount(); 1180f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (count == 0) { 11819302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView.setVisibility(View.GONE); 1182f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return; 1183f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1184f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 11859302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov List<Suggestion> suggestions = mAggregationSuggestionEngine.getSuggestions(); 11869302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 11879302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov TextView title = (TextView) mAggregationSuggestionView.findViewById( 11889302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov R.id.aggregation_suggestion_title); 11899302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov title.setText(getActivity().getResources().getQuantityString( 11909302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov R.plurals.aggregation_suggestion_title, count)); 1191f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 11929302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById( 11939302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov R.id.aggregation_suggestions); 1194f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov itemList.removeAllViews(); 1195f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1196f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov LayoutInflater inflater = getActivity().getLayoutInflater(); 1197f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1198f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov for (Suggestion suggestion : suggestions) { 1199f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov AggregationSuggestionView suggestionView = 1200f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov (AggregationSuggestionView) inflater.inflate( 1201f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov R.layout.aggregation_suggestions_item, null); 1202f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov suggestionView.setLayoutParams( 1203f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov new LinearLayout.LayoutParams( 1204f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 1205c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov suggestionView.setNewContact(mState.size() == 1 && mState.get(0).isContactInsert()); 1206f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov suggestionView.setListener(new AggregationSuggestionView.Listener() { 1207f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1208f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 1209f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onJoinAction(long contactId, List<Long> rawContactIds) { 1210f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mState.setJoinWithRawContacts(rawContactIds); 1211f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov // If we are in the edit mode (indicated by a non-zero contact ID), 1212f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov // join the suggested contact, save all changes, and stay in the editor. 12139302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov doSaveAction(SaveMode.RELOAD); 1214f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1215c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov 1216c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov @Override 1217c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov public void onEditAction(Uri contactLookupUri) { 12186a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov // Save all the data that has been entered so far 12196a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov ArrayList<ContentValues> values = mState.get(0).getContentValues(); 12206a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov 12216a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov // Abandon the currently inserted contact 1222c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov mState = null; 12236a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov 12246a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov // Load the suggested one 12256a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov Bundle extras = null; 12266a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov if (values.size() != 0) { 12276a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov extras = new Bundle(); 1228916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov extras.putParcelableArrayList(Insert.DATA, values); 12296a91292251913b3c0c8add733326cc70eae4cf51Dmitri Plotnikov } 1230916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov load(Intent.ACTION_EDIT, contactLookupUri, Contacts.CONTENT_TYPE, extras); 1231916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov mStatus = Status.LOADING; 1232916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener); 1233c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov } 1234f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov }); 12359302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov suggestionView.bindSuggestion(suggestion); 1236f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov itemList.addView(suggestionView); 1237f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 12389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 12399302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView.setVisibility(View.VISIBLE); 12409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 12419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (requestOnScreen) { 12429302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mContent.postDelayed(new Runnable() { 12439302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 12449302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov @Override 12459302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov public void run() { 12469302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov requestAggregationSuggestionOnScreen(mAggregationSuggestionView); 12479302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 12489302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov }, AGGREGATION_SUGGESTION_SCROLL_DELAY); 12499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 1250f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1251f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1252f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 1253f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Scrolls the editor if necessary to reveal the aggregation suggestion that is 1254f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * shown below the name editor. Makes sure that the currently focused field 1255f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * remains visible. 1256f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 1257f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private void requestAggregationSuggestionOnScreen(final View view) { 1258f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov Rect rect = getRelativeBounds(mContent, view); 1259f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov View focused = mContent.findFocus(); 1260f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (focused != null) { 1261f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov rect.union(getRelativeBounds(mContent, focused)); 1262f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1263f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mContent.requestRectangleOnScreen(rect); 1264f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1265f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1266f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 1267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Computes bounds of the supplied view relative to its ascendant. 1268f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 1269f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private Rect getRelativeBounds(View ascendant, View view) { 1270f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov Rect rect = new Rect(); 1271f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); 1272f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov View parent = (View) view.getParent(); 1274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov while (parent != ascendant) { 1275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov rect.offset(parent.getLeft(), parent.getTop()); 1276f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov parent = (View) parent.getParent(); 1277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1278f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return rect; 1279f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1280f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1281f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // TODO: There has to be a nicer way than this WeakAsyncTask...? Maybe call a service? 1282f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1283f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Background task for persisting edited contact data, using the changes 1284f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * defined by a set of {@link EntityDelta}. This task starts 1285f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * {@link EmptyService} to make sure the background thread can finish 1286f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * persisting in cases where the system wants to reclaim our process. 1287f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 1288f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public static class PersistTask extends 1289ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann WeakAsyncTask<EntityDeltaList, Void, Integer, ContactEditorFragment> { 1290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int PERSIST_TRIES = 3; 1291f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1292f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int RESULT_UNCHANGED = 0; 1293f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int RESULT_SUCCESS = 1; 1294f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int RESULT_FAILURE = 2; 1295f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1296f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private final Context mContext; 1297f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1298825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann private WeakReference<ProgressDialog> mProgress; 1299825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 1300f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private int mSaveMode; 1301f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private Uri mContactLookupUri = null; 1302f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1303f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public PersistTask(ContactEditorFragment target, int saveMode) { 1304f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann super(target); 1305f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mSaveMode = saveMode; 1306f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext = target.mContext; 1307f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1308f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1309f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** {@inheritDoc} */ 1310f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann @Override 1311f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann protected void onPreExecute(ContactEditorFragment target) { 1312825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(target.getActivity(), 1313825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann null, target.getActivity().getText(R.string.savingContact))); 1314825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 1315f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Before starting this task, start an empty service to protect our 1316f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // process from being reclaimed by the system. 1317f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext.startService(new Intent(mContext, EmptyService.class)); 1318f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1319f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1320f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** {@inheritDoc} */ 1321f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann @Override 1322ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann protected Integer doInBackground(ContactEditorFragment target, EntityDeltaList... params) { 1323f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ContentResolver resolver = mContext.getContentResolver(); 1324f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1325ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann EntityDeltaList state = params[0]; 1326f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1327f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Attempt to persist changes 1328f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int tries = 0; 1329f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Integer result = RESULT_FAILURE; 1330f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann while (tries++ < PERSIST_TRIES) { 1331f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann try { 1332f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Build operations and try applying 1333f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ArrayList<ContentProviderOperation> diff = state.buildDiff(); 1334f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ContentProviderResult[] results = null; 1335f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!diff.isEmpty()) { 133615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann results = resolver.applyBatch(ContactsContract.AUTHORITY, diff); 1337f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1338f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1339f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long rawContactId = getRawContactId(state, diff, results); 1340f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (rawContactId != -1) { 1341f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Uri rawContactUri = ContentUris.withAppendedId( 1342f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann RawContacts.CONTENT_URI, rawContactId); 1343f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1344f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // convert the raw contact URI to a contact URI 1345f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContactLookupUri = RawContacts.getContactLookupUri(resolver, 1346f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann rawContactUri); 134715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann Log.d(TAG, "Looked up RawContact Uri " + rawContactUri + 134815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann " into ContactLookupUri " + mContactLookupUri); 134915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann } else { 135015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann Log.w(TAG, "Could not determine RawContact ID after save"); 1351f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1352f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann result = (diff.size() > 0) ? RESULT_SUCCESS : RESULT_UNCHANGED; 1353f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1354f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1355f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } catch (RemoteException e) { 1356f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Something went wrong, bail without success 1357f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Log.e(TAG, "Problem persisting user edits", e); 1358f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1359f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1360f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } catch (OperationApplicationException e) { 1361f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Version consistency failed, re-parent change and try again 1362f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Log.w(TAG, "Version consistency failed, re-parenting: " + e.toString()); 1363ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann final EntityDeltaList newState = EntityDeltaList.fromQuery(resolver, 1364e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov target.mQuerySelection, null, null); 1365ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann state = EntityDeltaList.mergeAfter(newState, state); 1366f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1367f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1368f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1369f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return result; 1370f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1371f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1372ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann private long getRawContactId(EntityDeltaList state, 1373f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ArrayList<ContentProviderOperation> diff, 1374f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ContentProviderResult[] results) { 1375f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann long rawContactId = state.findRawContactId(); 1376f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (rawContactId != -1) { 1377f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return rawContactId; 1378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1379f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 138015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 1381f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // we gotta do some searching for the id 1382f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final int diffSize = diff.size(); 1383f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann for (int i = 0; i < diffSize; i++) { 1384f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ContentProviderOperation operation = diff.get(i); 1385f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (operation.getType() == ContentProviderOperation.TYPE_INSERT 1386f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann && operation.getUri().getEncodedPath().contains( 1387f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann RawContacts.CONTENT_URI.getEncodedPath())) { 1388f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return ContentUris.parseId(results[i].uri); 1389f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1390f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1391f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 1392f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1393f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1394f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** {@inheritDoc} */ 1395f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann @Override 1396f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann protected void onPostExecute(ContactEditorFragment target, Integer result) { 1397a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann Log.d(TAG, "onPostExecute(something," + result + "). mSaveMode=" + mSaveMode); 139815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann if (result == RESULT_SUCCESS && mSaveMode != SaveMode.JOIN) { 1399f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show(); 1400f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else if (result == RESULT_FAILURE) { 1401f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show(); 1402f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1403f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1404825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann final ProgressDialog progress = mProgress.get(); 1405825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (progress != null && progress.isShowing()) { 1406825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann try { 1407825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann progress.dismiss(); 1408825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } catch (Exception e) { 1409825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // this can happen if our view has already been closed. this can safely be 1410825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // ignored 1411825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 1412825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 1413825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 1414f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Stop the service that was protecting us 1415f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext.stopService(new Intent(mContext, EmptyService.class)); 1416f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1417f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann target.onSaveCompleted(result != RESULT_FAILURE, mSaveMode, mContactLookupUri); 1418f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1419f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1420f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1421f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann @Override 1422f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void onSaveInstanceState(Bundle outState) { 1423b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann outState.putParcelable(KEY_URI, mLookupUri); 1424d364314c460152db7089b304beec81b3675893baDmitri Plotnikov outState.putString(KEY_ACTION, mAction); 1425d364314c460152db7089b304beec81b3675893baDmitri Plotnikov 1426f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (hasValidState()) { 1427f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Store entities with modifications 1428f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putParcelable(KEY_EDIT_STATE, mState); 1429f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1430f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1431f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto); 1432f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator); 1433f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (mCurrentPhotoFile != null) { 1434f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString()); 1435f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1436f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putString(KEY_QUERY_SELECTION, mQuerySelection); 1437f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin); 14389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId); 1439f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann super.onSaveInstanceState(outState); 1440f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1441f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1442d364314c460152db7089b304beec81b3675893baDmitri Plotnikov @Override 1443f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void onActivityResult(int requestCode, int resultCode, Intent data) { 1444f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Ignore failed requests 1445f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (resultCode != Activity.RESULT_OK) return; 1446f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann switch (requestCode) { 1447a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: { 1448c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann // As we are coming back to this view, the editor will be reloaded automatically, 1449c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann // which will cause the photo that is set here to disappear. To prevent this, 14504a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // we remember to set a flag which is interpreted after loading. 14514a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // This photo is set here already to reduce flickering. 1452c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mPhoto = data.getParcelableExtra("data"); 1453c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann setPhoto(mRawContactIdRequestingPhoto, mPhoto); 1454c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mRawContactIdRequestingPhotoAfterLoad = mRawContactIdRequestingPhoto; 1455c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mRawContactIdRequestingPhoto = -1; 1456f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1457f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1458f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1459a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann case REQUEST_CODE_CAMERA_WITH_DATA: { 1460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann doCropPhoto(mCurrentPhotoFile); 1461f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1462f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1463a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann case REQUEST_CODE_JOIN: { 1464f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (data != null) { 1465f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long contactId = ContentUris.parseId(data.getData()); 1466f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann joinAggregate(contactId); 1467f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 14684a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann break; 1469f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1470f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1471cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 14729cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov 1473c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann /** 1474c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann * Sets the photo stored in mPhoto and writes it to the RawContact with the given id 1475c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann */ 1476c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann private void setPhoto(long rawContact, Bitmap photo) { 147772af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann BaseRawContactEditorView requestingEditor = getContactEditorView(rawContact); 14789302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (requestingEditor != null) { 14799302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov requestingEditor.setPhotoBitmap(photo); 14809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } else { 14819302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov Log.w(TAG, "The contact that requested the photo is no longer present."); 14829302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 14839302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 14849302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 14859302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov /** 14869302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov * Finds raw contact editor view for the given rawContactId. 14879302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov */ 148872af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann public BaseRawContactEditorView getContactEditorView(long rawContactId) { 1489c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann for (int i = 0; i < mContent.getChildCount(); i++) { 1490c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann final View childView = mContent.getChildAt(i); 149172af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann if (childView instanceof BaseRawContactEditorView) { 149272af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; 14939302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (editor.getRawContactId() == rawContactId) { 14949302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov return editor; 1495c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1496c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1497c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 14989302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov return null; 1499c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1500c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann 1501b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann public Uri getLookupUri() { 1502b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann return mLookupUri; 15039cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov } 1504222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 1505222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann /** 1506222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann * The listener for the data loader 1507222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann */ 1508222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener = 1509222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann new LoaderCallbacks<ContactLoader.Result>() { 1510222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann @Override 1511222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) { 1512222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann mLoaderStartTime = SystemClock.elapsedRealtime(); 1513b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann return new ContactLoader(mContext, mLookupUri); 1514222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 1515222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 1516222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann @Override 1517222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) { 1518222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann final long loaderCurrentTime = SystemClock.elapsedRealtime(); 1519222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime)); 15205da9363bc4f2e04dc388579e1df979a5843e25e6Dmitri Plotnikov if (data == ContactLoader.Result.NOT_FOUND || data == ContactLoader.Result.ERROR) { 1521222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann // Item has been deleted 1522222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann Log.i(TAG, "No contact found. Closing activity"); 152322fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann if (mListener != null) mListener.onContactNotFound(); 1524222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann return; 1525222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 1526222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 1527825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.EDITING; 1528222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann final long setDataStartTime = SystemClock.elapsedRealtime(); 1529222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann setData(data); 1530222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann final long setDataEndTime = SystemClock.elapsedRealtime(); 1531c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann 1532c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann // If we are coming back from the photo trimmer, this will be set. 1533c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann if (mRawContactIdRequestingPhotoAfterLoad != -1) { 1534c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann setPhoto(mRawContactIdRequestingPhotoAfterLoad, mPhoto); 1535c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mRawContactIdRequestingPhotoAfterLoad = -1; 1536c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mPhoto = null; 1537c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1538222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime)); 1539222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 1540222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann }; 1541a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1542e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov /** 1543e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov * The listener for the group meta data loader 1544e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov */ 1545e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener = 1546e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov new LoaderCallbacks<Cursor>() { 1547e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 1548e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov @Override 1549e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov public CursorLoader onCreateLoader(int id, Bundle args) { 1550e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov return new GroupMetaDataLoader(mContext); 1551e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 1552e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 1553e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov @Override 1554e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 1555e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov mGroupMetaData = data; 1556e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov bindGroupMetaData(); 1557e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 1558e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov }; 1559e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 1560a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann @Override 1561a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann public void onSplitContactConfirmed() { 1562a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann mState.markRawContactsForSplitting(); 156315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann doSaveAction(SaveMode.SPLIT); 1564a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1565a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1566a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann /** 1567a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * Launches Camera to take a picture and store it in a file. 1568a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann */ 1569a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann @Override 1570a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann public void onTakePhotoChosen() { 1571a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann try { 1572a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann // Launch camera to take photo for selected contact 1573a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann PHOTO_DIR.mkdirs(); 1574a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName()); 1575a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann final Intent intent = getTakePickIntent(mCurrentPhotoFile); 1576a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1577a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_CAMERA_WITH_DATA); 1578a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } catch (ActivityNotFoundException e) { 1579a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); 1580a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1581a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1582a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1583a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann /** 1584a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * Launches Gallery to pick a photo. 1585a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann */ 1586a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann @Override 1587a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann public void onPickFromGalleryChosen() { 1588a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann try { 1589a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann // Launch picker to choose photo for selected contact 1590a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann final Intent intent = getPhotoPickIntent(); 1591a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA); 1592a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } catch (ActivityNotFoundException e) { 1593a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); 1594a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1595a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1596a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1597a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann /** 1598a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * Account was chosen in the selector. Create a RawContact for this account now 1599a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann */ 1600a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann @Override 1601e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann public void onAccountChosen(Account account, boolean isNewContact) { 1602e17b1e52e6895f8177b4192f34126000fcb3f983Daniel Lehmann createContact(account, isNewContact); 1603a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1604a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1605a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann /** 1606a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * The account selector has been aborted. If we are in "New" mode, we have to close now 1607a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann */ 1608a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann @Override 1609a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann public void onAccountSelectorCancelled() { 16104a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann if (!hasValidState() && mListener != null) { 16114a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann mListener.onAccountSelectorAborted(); 16124a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16134a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16144a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann 16154a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann /** 16164a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann * User has chosen to set the selected photo as the (super) primary photo 16174a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann */ 16184a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 16194a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onUseAsPrimaryChosen(long rawContactId) { 16204a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // Set the IsSuperPrimary for each editor 16214a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann int count = mContent.getChildCount(); 16224a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann for (int i = 0; i < count; i++) { 16234a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final View childView = mContent.getChildAt(i); 162472af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann if (childView instanceof BaseRawContactEditorView) { 162572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; 16264a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final PhotoEditorView photoEditor = editor.getPhotoEditor(); 16274a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann photoEditor.setSuperPrimary(editor.getRawContactId() == rawContactId); 16284a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 1629a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1630a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 16314a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann 16324a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann /** 16334a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann * User has chosen to remove a picture 16344a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann */ 16354a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 16364a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onRemovePictureChose(long rawContactId) { 16374a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // find the correct editor and remove it's photo 16384a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final int editorCount = mContent.getChildCount(); 16394a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann for (int i = 0; i < editorCount; i++) { 16404a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final View child = mContent.getChildAt(i); 164172af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann if (child instanceof BaseRawContactEditorView) { 164272af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final BaseRawContactEditorView editor = 164372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann (BaseRawContactEditorView) child; 16444a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann if (editor.getRawContactId() == rawContactId) { 16454a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann editor.setPhotoBitmap(null); 16464a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann break; 16474a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16484a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16494a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16504a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16514a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann 16524a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann /** 16534a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann * User has chosen to change a picture 16544a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann */ 16554a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 16564a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onChangePictureChosen(long rawContactId) { 16574a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // Pick a new photo for the contact 16584a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann doPickPhotoAction(rawContactId); 16594a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 16602ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey} 1661