ContactEditorFragment.java revision a94859f61c216d4e137a631995026d3ddefbbf70
1cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann/* 2ef3f8f045ed4150caa64749742227acd0e6b85d8Daniel Lehmann * Copyright (C) 2010 The Android Open Source Project 3cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * 4cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Licensed under the Apache License, Version 2.0 (the "License"); 5cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * you may not use this file except in compliance with the License. 6cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * You may obtain a copy of the License at 7cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * 8cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * http://www.apache.org/licenses/LICENSE-2.0 9cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * 10cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * Unless required by applicable law or agreed to in writing, software 11cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * distributed under the License is distributed on an "AS IS" BASIS, 12cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * See the License for the specific language governing permissions and 14cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann * limitations under the License 15cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */ 16cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 1718ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovpackage com.android.contacts.editor; 18cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 1918ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.ContactLoader; 2018ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.ContactSaveService; 2118ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.GroupMetaDataLoader; 22cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport com.android.contacts.R; 232b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikovimport com.android.contacts.activities.ContactEditorActivity; 24d21ddb2c96e71f43eaf7addc25e163181d1ca87dDmitri Plotnikovimport com.android.contacts.activities.JoinContactActivity; 2518ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.AggregationSuggestionEngine.Suggestion; 2618ffaa2561cc7dd2e3ef81737e6537931c0a9a11Dmitri Plotnikovimport com.android.contacts.editor.Editor.EditorListener; 274597c92d655d45447780b32c7572acef110b6ed1Dmitri Plotnikovimport com.android.contacts.model.AccountType; 28a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikovimport com.android.contacts.model.AccountTypeManager; 29f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport com.android.contacts.model.EntityDelta; 30f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityDelta.ValuesDelta; 31ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmannimport com.android.contacts.model.EntityDeltaList; 32f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport com.android.contacts.model.EntityModifier; 3335769b804fbfd5a1fc0b2c36cd0a786d662c4334Daniel Lehmannimport com.android.contacts.model.GoogleAccountType; 34d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport com.android.contacts.util.AccountsListAdapter; 35f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 36f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.accounts.Account; 37cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.app.Activity; 38bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.AlertDialog; 39bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.Dialog; 40bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.app.DialogFragment; 41222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.Fragment; 42222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager; 43222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmannimport android.app.LoaderManager.LoaderCallbacks; 44cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ActivityNotFoundException; 45cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentUris; 46cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.ContentValues; 47cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Context; 48e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikovimport android.content.CursorLoader; 49bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.content.DialogInterface; 50e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikovimport android.content.Entity; 51cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Intent; 52cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.content.Loader; 53f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.database.Cursor; 54f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.graphics.Bitmap; 55f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.graphics.Rect; 56f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.media.MediaScannerConnection; 57cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.net.Uri; 58cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.os.Bundle; 59f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport android.os.Environment; 609767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmannimport android.os.SystemClock; 61cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Email; 62362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Event; 63362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Note; 64362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Organization; 65cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Phone; 66362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 67362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmannimport android.provider.ContactsContract.CommonDataKinds.Website; 68f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.Contacts; 690a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 70be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuanimport android.provider.ContactsContract.Groups; 712013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmannimport android.provider.ContactsContract.Intents; 72f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts; 73f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.provider.MediaStore; 74cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.util.Log; 75cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.LayoutInflater; 76cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.Menu; 77cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuInflater; 78cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.MenuItem; 79cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.View; 80cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.view.ViewGroup; 81f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.view.ViewGroup.LayoutParams; 82bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikovimport android.view.ViewGroup.MarginLayoutParams; 83f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport android.view.ViewStub; 84d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.AdapterView; 8580d527c94389cab477e2c75ded03eec877ea6835Daniel Lehmannimport android.widget.LinearLayout; 86d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawaimport android.widget.ListPopupWindow; 87cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport android.widget.Toast; 88cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 89f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.io.File; 90f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.text.SimpleDateFormat; 91cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmannimport java.util.ArrayList; 92f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Collections; 93f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Comparator; 94f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmannimport java.util.Date; 95f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikovimport java.util.List; 96f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 97a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmannpublic class ContactEditorFragment extends Fragment implements 98d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa SplitContactConfirmationDialogFragment.Listener, 99fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov AggregationSuggestionEngine.Listener, AggregationSuggestionView.Listener, 100fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov ExternalRawContactEditorView.Listener { 101cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 102cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann private static final String TAG = "ContactEditorFragment"; 103cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final int LOADER_DATA = 1; 105e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private static final int LOADER_GROUPS = 2; 106f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 107d364314c460152db7089b304beec81b3675893baDmitri Plotnikov private static final String KEY_URI = "uri"; 108d364314c460152db7089b304beec81b3675893baDmitri Plotnikov private static final String KEY_ACTION = "action"; 109f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_EDIT_STATE = "state"; 110f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester"; 111f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator"; 112f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile"; 113f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin"; 114623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann private static final String KEY_CONTACT_WRITABLE_FOR_JOIN = "contactwritableforjoin"; 1159302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov private static final String KEY_SHOW_JOIN_SUGGESTIONS = "showJoinSuggestions"; 11602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov private static final String KEY_ENABLED = "enabled"; 117ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov private static final String KEY_STATUS = "status"; 118f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 119a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public static final String SAVE_MODE_EXTRA_KEY = "saveMode"; 120a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 12115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 1227d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov * An intent extra that forces the editor to add the edited contact 1237d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov * to the default group (e.g. "My Contacts"). 1247d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov */ 1257d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov public static final String INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY = "addToDefaultDirectory"; 1267d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov 1277d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov /** 12815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Modes that specify what the AsyncTask has to perform after saving 12915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 130c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // TODO: Move this into a common utils class or the save service because the contact and 131c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan // group editors need to use this interface definition 1329df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov public interface SaveMode { 13315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 13415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Close the editor after saving 13515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 13615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int CLOSE = 0; 13715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 13815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 13915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Reload the data so that the user can continue editing 14015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 14115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int RELOAD = 1; 14215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 14315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 14415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Split the contact after saving 14515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 14615972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int SPLIT = 2; 14715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann 14815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann /** 14915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann * Join another contact after saving 15015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann */ 15115972398b530b91612418dc11d41c356d4f43739Daniel Lehmann public static final int JOIN = 3; 1529df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov 1539df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov /** 1549df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov * Navigate to Contacts Home activity after saving. 1559df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov */ 1569df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov public static final int HOME = 4; 15715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann } 158a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 159825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann private interface Status { 160825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 161825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * The loader is fetching data 162825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 163825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int LOADING = 0; 164825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 165825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 166825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann * Not currently busy. We are waiting for the user to enter data 167825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 168825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int EDITING = 1; 169825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 170825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 171f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov * The data is currently being saved. This is used to prevent more 172f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov * auto-saves (they shouldn't overlap) 173825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 174825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int SAVING = 2; 175825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 176825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann /** 177a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann * Prevents any more saves. This is used if in the following cases: 178a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann * - After Save/Close 179a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann * - After Revert 180a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann * - After the user has accepted an edit suggestion 181825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann */ 182825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann public static final int CLOSING = 3; 183f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov 184f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov /** 185f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov * Prevents saving while running a child activity. 186f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov */ 187f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov public static final int SUB_ACTIVITY = 4; 188825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 189825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 190a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann private static final int REQUEST_CODE_JOIN = 0; 191a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1; 192a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 2; 193f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 194c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann private Bitmap mPhoto = null; 195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private long mRawContactIdRequestingPhoto = -1; 196c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann private long mRawContactIdRequestingPhotoAfterLoad = -1; 197cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 198f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private final EntityDeltaComparator mComparator = new EntityDeltaComparator(); 199f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private static final File PHOTO_DIR = new File( 201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Environment.getExternalStorageDirectory() + "/DCIM/Camera"); 202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 203e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private Cursor mGroupMetaData; 204e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 205f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 206f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * A delay in milliseconds used for bringing aggregation suggestions to 207f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * the visible part of the screen. The reason this has to be done after 208f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * a delay is a race condition with the soft keyboard. The keyboard 209f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * may expand to display its own autocomplete suggestions, which will 210f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * reduce the visible area of the screen. We will yield to the keyboard 211f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * hoping that the delay is sufficient. If not - part of the 212f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * suggestion will be hidden, which is not fatal. 213f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 214f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private static final int AGGREGATION_SUGGESTION_SCROLL_DELAY = 200; 215f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 216f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private File mCurrentPhotoFile; 217cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 2180a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro // Height/width (in pixels) to request for the photo - queried from the provider. 2190a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro private int mPhotoPickSize; 2200a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro 221cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann private Context mContext; 222f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private String mAction; 223b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann private Uri mLookupUri; 224f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private Bundle mIntentExtras; 225cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann private Listener mListener; 226cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 227f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private long mContactIdForJoin; 228623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann private boolean mContactWritableForJoin; 229cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 230f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private LinearLayout mContent; 231ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann private EntityDeltaList mState; 232cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 233f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private ViewIdGenerator mViewIdGenerator; 234cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 2359767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann private long mLoaderStartTime; 2369767e09ae37332d74b5558a3ec16ded20a9328dcDaniel Lehmann 237825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann private int mStatus; 238825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 239f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private AggregationSuggestionEngine mAggregationSuggestionEngine; 2409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov private long mAggregationSuggestionsRawContactId; 2419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov private View mAggregationSuggestionView; 242f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 2437d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov private boolean mAutoAddToDefaultGroup; 2447d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov 24502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov private boolean mEnabled = true; 246eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov private boolean mRequestFocus; 24702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov 248cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public ContactEditorFragment() { 249cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 250cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 25102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov public void setEnabled(boolean enabled) { 25202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov if (mEnabled != enabled) { 25302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov mEnabled = enabled; 25402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov if (mContent != null) { 25502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov int count = mContent.getChildCount(); 25602bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov for (int i = 0; i < count; i++) { 25702bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov mContent.getChildAt(i).setEnabled(enabled); 25802bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 25902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 260a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov setAggregationSuggestionViewEnabled(enabled); 26102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov final Activity activity = getActivity(); 26202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov if (activity != null) activity.invalidateOptionsMenu(); 26302bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 26402bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 26502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov 266cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann @Override 267cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public void onAttach(Activity activity) { 268cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann super.onAttach(activity); 269cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann mContext = activity; 2700a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro loadPhotoPickSize(); 271cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 272cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 273cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann @Override 274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onStop() { 275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov super.onStop(); 276f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (mAggregationSuggestionEngine != null) { 277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.quit(); 278f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 279248fba273e867616b1f8973dac6ce3e5ee1ba544Dmitri Plotnikov 280825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // If anything was left unsaved, save it now but keep the editor open. 281f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) { 282623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann save(SaveMode.RELOAD); 283825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 284f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 285f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 286f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 287cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { 288cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false); 289cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 290f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent = (LinearLayout) view.findViewById(R.id.editors); 291e8767a1136d2a2f9cb3e3ca5f44b2142baab9709Daniel Lehmann 2923648d2ea76a6649230d1fdd3dba92797ae7cfb26Daniel Lehmann setHasOptionsMenu(true); 293cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 294825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // If we are in an orientation change, we already have mState (it was loaded by onCreate) 295825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (mState != null) { 296825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann bindEditors(); 297825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 298825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 299cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann return view; 300cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 301cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 302222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann @Override 303222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann public void onActivityCreated(Bundle savedInstanceState) { 304222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann super.onActivityCreated(savedInstanceState); 305222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 306825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann Log.d(TAG, "onActivityCreated(" + savedInstanceState + ")"); 307222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 308825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Handle initial actions only when existing state missing 3094a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann final boolean hasIncomingState = savedInstanceState != null; 310825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 311825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (!hasIncomingState) { 312825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (Intent.ACTION_EDIT.equals(mAction)) { 313825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (mListener != null) mListener.setTitleTo(R.string.editContact_title_edit); 314825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann getLoaderManager().initLoader(LOADER_DATA, null, mDataLoaderListener); 315825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } else if (Intent.ACTION_INSERT.equals(mAction)) { 316825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (mListener != null) mListener.setTitleTo(R.string.editContact_title_insert); 317825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann 3182013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann final Account account = mIntentExtras == null ? null : 3192013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann (Account) mIntentExtras.getParcelable(Intents.Insert.ACCOUNT); 3202013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann 3212013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann if (account != null) { 3222013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann // Account specified in Intent 32340bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov createContact(account); 3242013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann } else { 3252013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann // No Account specified. Let the user choose 32640bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov // Load Accounts async so that we can present them 327d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa createContact(); 3282013058703aa110a1d7aac87ef408c96a3919472Daniel Lehmann } 329a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } else if (ContactEditorActivity.ACTION_SAVE_COMPLETED.equals(mAction)) { 330a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov // do nothing 331825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } else throw new IllegalArgumentException("Unknown Action String " + mAction + 332825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann ". Only support " + Intent.ACTION_EDIT + " or " + Intent.ACTION_INSERT); 333825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann } 334222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 335222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 336e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov @Override 337e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov public void onStart() { 338e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupLoaderListener); 339e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov super.onStart(); 340e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 341e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 3421015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov public void load(String action, Uri lookupUri, Bundle intentExtras) { 343f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mAction = action; 344b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann mLookupUri = lookupUri; 345f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mIntentExtras = intentExtras; 3467d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov mAutoAddToDefaultGroup = mIntentExtras != null 3477d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov && mIntentExtras.containsKey(INTENT_EXTRA_ADD_TO_DEFAULT_DIRECTORY); 348f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 349f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 350f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void setListener(Listener value) { 351f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mListener = value; 352cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 353cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 354cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann @Override 355f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void onCreate(Bundle savedState) { 356d364314c460152db7089b304beec81b3675893baDmitri Plotnikov if (savedState != null) { 357d364314c460152db7089b304beec81b3675893baDmitri Plotnikov // Restore mUri before calling super.onCreate so that onInitializeLoaders 358d364314c460152db7089b304beec81b3675893baDmitri Plotnikov // would already have a uri and an action to work with 359b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann mLookupUri = savedState.getParcelable(KEY_URI); 360d364314c460152db7089b304beec81b3675893baDmitri Plotnikov mAction = savedState.getString(KEY_ACTION); 361d364314c460152db7089b304beec81b3675893baDmitri Plotnikov } 362d364314c460152db7089b304beec81b3675893baDmitri Plotnikov 363f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann super.onCreate(savedState); 364f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 365f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (savedState == null) { 366f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // If savedState is non-null, onRestoreInstanceState() will restore the generator. 367f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mViewIdGenerator = new ViewIdGenerator(); 368f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 369825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Read state from savedState. No loading involved here 370ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE); 371f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mRawContactIdRequestingPhoto = savedState.getLong( 372f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann KEY_RAW_CONTACT_ID_REQUESTING_PHOTO); 373f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR); 374f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE); 375f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (fileName != null) { 376f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mCurrentPhotoFile = new File(fileName); 377cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 378f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN); 379623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN); 3809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS); 38102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov mEnabled = savedState.getBoolean(KEY_ENABLED); 382ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov mStatus = savedState.getInt(KEY_STATUS); 383cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 384cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 385cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 386bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann public void setData(ContactLoader.Result data) { 387d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann // If we have already loaded data, we do not want to change it here to not confuse the user 388d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann if (mState != null) { 389d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann Log.v(TAG, "Ignoring background change. This will have to be rebased later"); 390d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann return; 391d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann } 392d3f1e3128b709d7d9a0229f1d1843f015f4977baDaniel Lehmann 393fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov // See if this edit operation needs to be redirected to a custom editor 394fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov ArrayList<Entity> entities = data.getEntities(); 395fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov if (entities.size() == 1) { 396fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov Entity entity = entities.get(0); 397fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov ContentValues entityValues = entity.getEntityValues(); 398fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE); 399a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov AccountType accountType = AccountTypeManager.getInstance(mContext).getAccountType(type); 400fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov if (accountType.getEditContactActivityClassName() != null) { 401fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov if (mListener != null) { 402fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov String name = entityValues.getAsString(RawContacts.ACCOUNT_NAME); 403fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID); 404fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov mListener.onCustomEditContactActivityRequested(new Account(name, type), 405fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 406fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov mIntentExtras, true); 407fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 408fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov return; 409fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 410fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 411fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 412fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov bindEditorsForExistingContact(data); 413fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 414fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 415fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov @Override 416fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov public void onExternalEditorRequest(Account account, Uri uri) { 417fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov mListener.onCustomEditContactActivityRequested(account, uri, null, false); 418fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 419fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 420fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov private void bindEditorsForExistingContact(ContactLoader.Result data) { 42102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov setEnabled(true); 42202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov 423a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov mState = EntityDeltaList.fromIterator(data.getEntities().iterator()); 4241ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov setIntentExtras(mIntentExtras); 4251ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov mIntentExtras = null; 426e579a175bdc18153014da00d989cf0a5343d25a9Dmitri Plotnikov 427eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov mRequestFocus = true; 428eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov 4291ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov bindEditors(); 4301ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } 4311ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov 4321ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov /** 4331ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov * Merges extras from the intent. 4341ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov */ 4351ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov public void setIntentExtras(Bundle extras) { 4361ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov if (extras == null || extras.size() == 0) { 4371ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov return; 438bb11be3f5867453e7561cdc7bebe6a380eff6881Daniel Lehmann } 439916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov 440a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 4411ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov for (EntityDelta state : mState) { 4421ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE); 443b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov final AccountType type = accountTypes.getAccountType(accountType); 44469f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov if (!type.readOnly) { 4451ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov // Apply extras to the first writable raw contact only 44669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov EntityModifier.parseExtras(mContext, type, state, extras); 4471ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov break; 4481ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } 4491ac58b6f2a925c5a4f759346e5244dfd174acd08Dmitri Plotnikov } 450f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 451cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 452d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa /** 453d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * Shows the account creation screen. An account associated with the contact is automatically 454d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * selected. If there's no available account, device-local contact should be created. 455d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa */ 456d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa private void createContact() { 457a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final ArrayList<Account> accounts = 458a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov AccountTypeManager.getInstance(mContext).getAccounts(true); 459f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // No Accounts available. Create a phone-local contact. 460f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (accounts.isEmpty()) { 46140bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov createContact(null); 462f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return; // Don't show a dialog. 463f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 464cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 465d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa // We have an account switcher in "create-account" screen, so don't need to ask a user to 466d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa // select an account here. 467d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa createContact(accounts.get(0)); 468cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 469cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 470d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa 471cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann /** 472d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * Shows account creation screen associated with a given account. 473d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * 474d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * @param account may be null to signal a device-local contact should be created. 475cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */ 47640bb481d29bf490fddc65b88c957dd4b5dbc4d82Dmitri Plotnikov private void createContact(Account account) { 477a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 478b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov final AccountType accountType = 479b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov accountTypes.getAccountType(account != null ? account.type : null); 480fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 481b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov if (accountType.getCreateContactActivityClassName() != null) { 482fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov if (mListener != null) { 483fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov mListener.onCustomCreateContactActivityRequested(account, mIntentExtras); 484fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 485fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } else { 486b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov bindEditorsForNewContact(account, accountType); 487fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 488fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } 489fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 490d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa /** 491d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * Removes a current editor ({@link #mState}) and rebinds new editor for a new account. 492d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * Some of old data are reused with new restriction enforced by the new account. 493d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * 494d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * @param oldState Old data being editted. 495d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * @param oldAccount Old account associated with oldState. 496d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa * @param newAccount New account to be used. 497d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa */ 498d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa private void rebindEditorsForNewContact( 499d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityDelta oldState, Account oldAccount, Account newAccount) { 500d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 501d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa AccountType oldAccountType = accountTypes.getAccountType(oldAccount.type); 502d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa AccountType newAccountType = accountTypes.getAccountType(newAccount.type); 503d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa 504d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa if (newAccountType.getCreateContactActivityClassName() != null) { 505d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa Log.w(TAG, "external activity called in rebind situation"); 506d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa if (mListener != null) { 507d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras); 508d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 509d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } else { 510d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa mState = null; 511d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa bindEditorsForNewContact(newAccount, newAccountType, oldState, oldAccountType); 512d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 513d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 514d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa 51569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov private void bindEditorsForNewContact(Account account, final AccountType accountType) { 516d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa bindEditorsForNewContact(account, accountType, null, null); 517d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 518d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa 519d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa private void bindEditorsForNewContact(Account newAccount, final AccountType newAccountType, 520d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityDelta oldState, AccountType oldAccountType) { 521a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov mStatus = Status.EDITING; 522a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov 523f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ContentValues values = new ContentValues(); 524d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa if (newAccount != null) { 525d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa values.put(RawContacts.ACCOUNT_NAME, newAccount.name); 526d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa values.put(RawContacts.ACCOUNT_TYPE, newAccount.type); 527f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 528f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann values.putNull(RawContacts.ACCOUNT_NAME); 529f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann values.putNull(RawContacts.ACCOUNT_TYPE); 530cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 531cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 532f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values)); 533d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa if (oldState == null) { 534d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa // Parse any values from incoming intent 535d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras); 536d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } else { 537d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.migrateStateForNewContact(mContext, oldState, insert, 538d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa oldAccountType, newAccountType); 539d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 540f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 54169f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov // Ensure we have some default fields (if the account type does not support a field, 542362acdb3da27524d42c4bb44423d6276c5738616Daniel Lehmann // ensureKind will not add it, so it is safe to add e.g. Event) 543d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE); 544d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE); 545d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, Note.CONTENT_ITEM_TYPE); 546d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE); 547d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE); 548d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, Website.CONTENT_ITEM_TYPE); 549d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa EntityModifier.ensureKindExists(insert, newAccountType, StructuredPostal.CONTENT_ITEM_TYPE); 550f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 551f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (mState == null) { 552f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Create state if none exists yet 553ca98444277723c60be83062cf5a25ec7ca1fdb34Daniel Lehmann mState = EntityDeltaList.fromSingle(insert); 554f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 555f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Add contact onto end of existing state 556f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mState.add(insert); 557cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 558f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 559eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov mRequestFocus = true; 560eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov 561f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann bindEditors(); 562cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 563cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 564f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void bindEditors() { 565f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Sort the editors 566f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Collections.sort(mState, mComparator); 567cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 568f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Remove any existing editors and rebuild any visible 569f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent.removeAllViews(); 570cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 571f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( 572f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Context.LAYOUT_INFLATER_SERVICE); 573a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 574a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan int numRawContacts = mState.size(); 575a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan for (int i = 0; i < numRawContacts; i++) { 576f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // TODO ensure proper ordering of entities in the list 577f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final EntityDelta entity = mState.get(i); 578f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final ValuesDelta values = entity.getValues(); 579f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!values.isVisible()) continue; 580f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 581f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 582b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov final AccountType type = accountTypes.getAccountType(accountType); 583f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long rawContactId = values.getAsLong(RawContacts._ID); 584f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 58572af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final BaseRawContactEditorView editor; 58669f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov if (type.isExternal()) { 587fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov editor = (BaseRawContactEditorView) inflater.inflate( 588fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov R.layout.external_raw_contact_editor_view, mContent, false); 589fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov ((ExternalRawContactEditorView) editor).setListener(this); 590fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov } else { 591a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan final RawContactEditorView rawContactEditor = (RawContactEditorView) 592f7ce5978a6a6314028fe9bbb1da99338b111750fDaniel Lehmann inflater.inflate(R.layout.raw_contact_editor_view, mContent, false); 593a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan // For existing contacts, only show the account header if there is more than 1 raw 594a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan // contact in the aggregate contact. 595a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan if (Intent.ACTION_EDIT.equals(mAction)) { 596a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan rawContactEditor.setAccountHeaderVisible(numRawContacts > 1); 597a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan } 598a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan editor = rawContactEditor; 599cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 600a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan if (Intent.ACTION_INSERT.equals(mAction) && numRawContacts == 1) { 601d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa final ArrayList<Account> accounts = 602d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa AccountTypeManager.getInstance(mContext).getAccounts(true); 603d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa if (accounts.size() > 1) { 604d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa addAccountSwitcher(mState.get(0), editor); 605a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan } else { 606a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan disableAccountSwitcher(editor); 607d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 608d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 609a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan 61002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov editor.setEnabled(mEnabled); 611cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 612f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent.addView(editor); 6137d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov 61469f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov editor.setState(entity, type, mViewIdGenerator); 615f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 6169442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann editor.getPhotoEditor().setEditorListener( 61769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov new PhotoEditorListener(editor, type.readOnly)); 61872af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann if (editor instanceof RawContactEditorView) { 61972af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final RawContactEditorView rawContactEditor = (RawContactEditorView) editor; 6205ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov EditorListener listener = new EditorListener() { 621f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 622f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 623f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onRequest(int request) { 62411bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov if (request == EditorListener.FIELD_CHANGED) { 62511bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov acquireAggregationSuggestions(rawContactEditor); 62611bb73bcdf4290ced99e3e06b1f76d4c37357aeaDmitri Plotnikov } 627f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 628f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 629f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 6304a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann public void onDeleted(Editor removedEditor) { 631f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 6325ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov }; 6335ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov 6345ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov final TextFieldsEditorView nameEditor = rawContactEditor.getNameEditor(); 6355ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov if (mRequestFocus) { 6365ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov nameEditor.requestFocus(); 6375ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov mRequestFocus = false; 6385ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov } 6395ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov nameEditor.setEditorListener(listener); 640f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 6415ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov final TextFieldsEditorView phoneticNameEditor = 6425ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov rawContactEditor.getPhoneticNameEditor(); 6435ec40b04041818bc042c0671cb1a43b54f650e25Dmitri Plotnikov phoneticNameEditor.setEditorListener(listener); 6447d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup); 6457d901bb3d4118762e21f4db19e35fc937dcf96feDmitri Plotnikov 6469302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (rawContactId == mAggregationSuggestionsRawContactId) { 647f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov acquireAggregationSuggestions(rawContactEditor); 648f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 649f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 650cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 651f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 652eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov mRequestFocus = false; 653eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov 654e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov bindGroupMetaData(); 655e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 656f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Show editor now that we've loaded state 657f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContent.setVisibility(View.VISIBLE); 658a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 659a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann // Refresh Action Bar as the visibility of the join command 660825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // Activity can be null if we have been detached from the Activity 661825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann final Activity activity = getActivity(); 662825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann if (activity != null) activity.invalidateOptionsMenu(); 663eeb68a341734ded343004d4eecb585420e70605bDmitri Plotnikov 664cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 665cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 666e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private void bindGroupMetaData() { 667e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov if (mGroupMetaData == null) { 668e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov return; 669e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 670e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 671e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov int editorCount = mContent.getChildCount(); 672e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov for (int i = 0; i < editorCount; i++) { 67372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i); 674e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov editor.setGroupMetaData(mGroupMetaData); 675e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 676e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 677e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 678d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa private void addAccountSwitcher( 679d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa final EntityDelta currentState, BaseRawContactEditorView editor) { 680d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa ValuesDelta values = currentState.getValues(); 681d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa final Account currentAccount = new Account( 682d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa values.getAsString(RawContacts.ACCOUNT_NAME), 683d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa values.getAsString(RawContacts.ACCOUNT_TYPE)); 684d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa final View accountView = editor.findViewById(R.id.account); 685d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa final View anchorView = editor.findViewById(R.id.anchor_for_account_switcher); 686d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa accountView.setOnClickListener(new View.OnClickListener() { 687d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa @Override 688d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa public void onClick(View v) { 689d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa final ListPopupWindow popup = new ListPopupWindow(mContext, null); 690a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa final AccountsListAdapter adapter = 691a6c8f2daa80f1816dd25237457d7f6287c6b1b7cDaisuke Miyakawa new AccountsListAdapter(mContext, true, currentAccount); 692d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.setWidth(anchorView.getWidth()); 693d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.setAnchorView(anchorView); 694d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.setAdapter(adapter); 695d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.setModal(true); 696d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); 697d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.setOnItemClickListener(new AdapterView.OnItemClickListener() { 698d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa @Override 699d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa public void onItemClick(AdapterView<?> parent, View view, int position, 700d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa long id) { 701d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.dismiss(); 702d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa Account newAccount = adapter.getItem(position); 703d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa if (!newAccount.equals(currentAccount)) { 704d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa rebindEditorsForNewContact(currentState, currentAccount, newAccount); 705d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 706d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 707d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa }); 708d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa popup.show(); 709d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 710d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa }); 711d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa } 712d37a891cb44cd17083c06d7be693c469403d16dfDaisuke Miyakawa 713a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan private void disableAccountSwitcher(BaseRawContactEditorView editor) { 714a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan // Remove the pressed state from the account header because the user cannot switch accounts 715a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan // on an existing contact 716a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan final View accountView = editor.findViewById(R.id.account); 717a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan accountView.setBackgroundDrawable(null); 718a94859f61c216d4e137a631995026d3ddefbbf70Katherine Kuan accountView.setEnabled(false); 719a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan } 720a7c3d4d726b91f645431af14d8cceadd2245f4ceKatherine Kuan 721b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann @Override 722eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) { 723c6b8afe730255537978f2c938cca6986cae63c34Katherine Kuan inflater.inflate(R.menu.edit_contact, menu); 724cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 725cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 726b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann @Override 727eb4d1bf9868dfddd958d8f028e36a4d2da7a8731Dianne Hackborn public void onPrepareOptionsMenu(Menu menu) { 728f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann menu.findItem(R.id.menu_split).setVisible(mState != null && mState.size() > 1); 72902bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov int size = menu.size(); 73002bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov for (int i = 0; i < size; i++) { 73102bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov menu.getItem(i).setEnabled(mEnabled); 73202bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov } 733cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 734cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 735b85b83ee4adc8b72fe68499f669ca530d58e6815Daniel Lehmann @Override 736cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public boolean onOptionsItemSelected(MenuItem item) { 737cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann switch (item.getItemId()) { 738f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_done: 7399df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov return save(SaveMode.CLOSE); 740f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_discard: 741d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov return revert(); 742f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_delete: 743f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doDeleteAction(); 744f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_split: 745f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doSplitContactAction(); 746f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann case R.id.menu_join: 747f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return doJoinContactAction(); 748f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 749f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return false; 750f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 751cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 752f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 753f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Delete the entire contact currently being edited, which usually asks for 754f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * user confirmation before continuing. 755f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 756f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doDeleteAction() { 757f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!hasValidState()) 758f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return false; 759cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 760b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann // TODO: Make sure Insert turns into Edit if/once it is autosaved 761b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann if (Intent.ACTION_INSERT.equals(mAction)) { 762b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann if (mListener != null) mListener.onReverted(); 763cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } else { 764b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann if (mListener != null) mListener.onDeleteRequested(mLookupUri); 765cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 766f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 767f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 768f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 769f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doSplitContactAction() { 770f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!hasValidState()) return false; 771f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 772a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann final SplitContactConfirmationDialogFragment dialog = 7734a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann new SplitContactConfirmationDialogFragment(); 7744a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialog.setTargetFragment(this, 0); 7754a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann dialog.show(getFragmentManager(), SplitContactConfirmationDialogFragment.TAG); 776f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 777f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 778f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 779f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean doJoinContactAction() { 7804c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov if (!hasValidState()) { 7814c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov return false; 7824c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov } 7834c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov 7844c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov // If we just started creating a new contact and haven't added any data, it's too 7854c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov // early to do a join 786a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 787a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (mState.size() == 1 && mState.get(0).isContactInsert() 788a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov && !EntityModifier.hasChanges(mState, accountTypes)) { 789a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact, 790a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Toast.LENGTH_LONG).show(); 791a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov return true; 7924c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov } 7934c699fc698763b3e271efb7654fb5e38ffb6f556Dmitri Plotnikov 7949df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov return save(SaveMode.JOIN); 795f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 796f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 7970a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro private void loadPhotoPickSize() { 7980a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro Cursor c = mContext.getContentResolver().query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, 7990a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null); 8000a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro try { 8010a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro c.moveToFirst(); 8020a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro mPhotoPickSize = c.getInt(0); 8030a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro } finally { 8040a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro c.close(); 8050a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro } 8060a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro } 8070a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro 808f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 809f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap. 810f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 8110a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro public Intent getPhotoPickIntent() { 812f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); 813f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.setType("image/*"); 814f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("crop", "true"); 815f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectX", 1); 816f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectY", 1); 8170a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro intent.putExtra("outputX", mPhotoPickSize); 8180a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro intent.putExtra("outputY", mPhotoPickSize); 819f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("return-data", true); 820f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return intent; 821f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 822f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 823f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 824f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Check if our internal {@link #mState} is valid, usually checked before 825f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * performing user actions. 826f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 827f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private boolean hasValidState() { 828f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return mState != null && mState.size() > 0; 829f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 830f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 831f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 832f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Create a file name for the icon photo using current time. 833f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 834f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private String getPhotoFileName() { 835f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Date date = new Date(System.currentTimeMillis()); 836f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss"); 837f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return dateFormat.format(date) + ".jpg"; 838f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 839f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 840f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 841f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Constructs an intent for capturing a photo and storing it in a temporary file. 842f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 843f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public static Intent getTakePickIntent(File f) { 844f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null); 845f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); 846f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return intent; 847f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 848f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 849f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 850f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Sends a newly acquired photo to Gallery for cropping 851f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 852f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann protected void doCropPhoto(File f) { 853f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann try { 854f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Add the image to the media store 855f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann MediaScannerConnection.scanFile( 856f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext, 857f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann new String[] { f.getAbsolutePath() }, 858f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann new String[] { null }, 859f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann null); 860f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 861f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Launch gallery to crop the photo 862f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Intent intent = getCropImageIntent(Uri.fromFile(f)); 863f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov mStatus = Status.SUB_ACTIVITY; 864a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA); 865f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } catch (Exception e) { 866f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Log.e(TAG, "Cannot crop image", e); 867f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); 868cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 869cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 870cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann 871f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 872f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Constructs an intent for image cropping. 873f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 8740a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro public Intent getCropImageIntent(Uri photoUri) { 875f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Intent intent = new Intent("com.android.camera.action.CROP"); 876f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.setDataAndType(photoUri, "image/*"); 877f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("crop", "true"); 878f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectX", 1); 879f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("aspectY", 1); 8800a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro intent.putExtra("outputX", mPhotoPickSize); 8810a2a5db3b3633883388953dc98e30c2edd7cae62Dave Santoro intent.putExtra("outputY", mPhotoPickSize); 882f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra("return-data", true); 883f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return intent; 884f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 885f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 886f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 887f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Saves or creates the contact based on the mode, and if successful 888f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * finishes the activity. 889f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 8909df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov public boolean save(int saveMode) { 891a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov if (!hasValidState() || mStatus != Status.EDITING) { 892f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return false; 893f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 894f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 8958c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov // If we are about to close the editor - there is no need to refresh the data 896a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (saveMode == SaveMode.CLOSE || saveMode == SaveMode.SPLIT) { 8979d2bcfb40d0ee107886eb99eba13a840e944ba43Dianne Hackborn getLoaderManager().destroyLoader(LOADER_DATA); 8988c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov } 8998c6955ff3c05e1f3899110701c3cb5559a492f1eDmitri Plotnikov 900825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.SAVING; 9016cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov 902a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 903a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (!EntityModifier.hasChanges(mState, accountTypes)) { 904a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov onSaveCompleted(false, saveMode, mLookupUri); 9056cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov return true; 9066cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov } 9076cb8fe23106bc05139798318f19b29c569140628Dmitri Plotnikov 908a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov setEnabled(false); 909f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 910a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState, 911a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov SAVE_MODE_EXTRA_KEY, saveMode, getActivity().getClass(), 912a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov ContactEditorActivity.ACTION_SAVE_COMPLETED); 913a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov getActivity().startService(intent); 914f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return true; 915f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 916f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 917d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov public static class CancelEditDialogFragment extends DialogFragment { 918d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov 919d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov public static void show(ContactEditorFragment fragment) { 920d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov CancelEditDialogFragment dialog = new CancelEditDialogFragment(); 921d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov dialog.setTargetFragment(fragment, 0); 922d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov dialog.show(fragment.getFragmentManager(), "cancelEditor"); 923d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 924d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov 925d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov @Override 926d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov public Dialog onCreateDialog(Bundle savedInstanceState) { 927d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov AlertDialog dialog = new AlertDialog.Builder(getActivity()) 9284292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov .setIconAttribute(android.R.attr.alertDialogIcon) 929d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov .setTitle(R.string.cancel_confirmation_dialog_title) 930d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov .setMessage(R.string.cancel_confirmation_dialog_message) 931d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov .setPositiveButton(R.string.discard, 932d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov new DialogInterface.OnClickListener() { 933d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov @Override 934d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov public void onClick(DialogInterface dialog, int whichButton) { 935d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov ((ContactEditorFragment)getTargetFragment()).doRevertAction(); 936d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 937d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 938d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov ) 939d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov .setNegativeButton(android.R.string.cancel, null) 940d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov .create(); 941d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov return dialog; 942d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 943d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 944d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov 945d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov private boolean revert() { 946c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 947c863b0171f2a54a0ee71b34b33034aeea2464ccaDmitri Plotnikov if (mState == null || !EntityModifier.hasChanges(mState, accountTypes)) { 948d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov doRevertAction(); 949d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } else { 950d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov CancelEditDialogFragment.show(this); 951d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 952d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov return true; 953d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov } 954d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov 955d3eedfc5f518a081d76d6b9e31a39c5adf988bc0Dmitri Plotnikov private void doRevertAction() { 956825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // When this Fragment is closed we don't want it to auto-save 957825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.CLOSING; 95822fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann if (mListener != null) mListener.onReverted(); 959f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 960f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 9612b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov public void onJoinCompleted(Uri uri) { 962a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov onSaveCompleted(false, SaveMode.RELOAD, uri); 9632b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov } 9642b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov 965a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov public void onSaveCompleted(boolean hadChanges, int saveMode, Uri contactLookupUri) { 966a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov boolean success = contactLookupUri != null; 967a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Log.d(TAG, "onSaveCompleted(" + saveMode + ", " + contactLookupUri); 968a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (hadChanges) { 969a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (success) { 970a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov if (saveMode != SaveMode.JOIN) { 971a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Toast.makeText(mContext, R.string.contactSavedToast, Toast.LENGTH_SHORT).show(); 972a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 973a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } else { 974a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov Toast.makeText(mContext, R.string.contactSavedErrorToast, Toast.LENGTH_LONG).show(); 975a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 976a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov } 977f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann switch (saveMode) { 97815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.CLOSE: 9799df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov case SaveMode.HOME: 980f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Intent resultIntent; 981f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (success && contactLookupUri != null) { 982b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann final String requestAuthority = 983b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann mLookupUri == null ? null : mLookupUri.getAuthority(); 984f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 985f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final String legacyAuthority = "contacts"; 986f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 987f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent = new Intent(); 9885649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan resultIntent.setAction(Intent.ACTION_VIEW); 989f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (legacyAuthority.equals(requestAuthority)) { 990f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Build legacy Uri when requested by caller 991f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long contactId = ContentUris.parseId(Contacts.lookupContact( 992f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContext.getContentResolver(), contactLookupUri)); 993f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Uri legacyContentUri = Uri.parse("content://contacts/people"); 994f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Uri legacyUri = ContentUris.withAppendedId( 995f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann legacyContentUri, contactId); 996f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent.setData(legacyUri); 997f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 998f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Otherwise pass back a lookup-style Uri 999f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent.setData(contactLookupUri); 1000f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1001f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1002f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else { 1003f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann resultIntent = null; 1004f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1005825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann // It is already saved, so prevent that it is saved again 1006825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.CLOSING; 10075649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan if (mListener != null) mListener.onSaveFinished(resultIntent); 1008f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1009a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 101015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.RELOAD: 1011dd0dee6c55ea83d541b28e90cd4ad87ffd026f68Dmitri Plotnikov case SaveMode.JOIN: 101215972398b530b91612418dc11d41c356d4f43739Daniel Lehmann if (success && contactLookupUri != null) { 1013623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann // If it was a JOIN, we are now ready to bring up the join activity. 1014623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann if (saveMode == SaveMode.JOIN) { 1015623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann showJoinAggregateActivity(contactLookupUri); 1016623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann } 1017623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann 101815972398b530b91612418dc11d41c356d4f43739Daniel Lehmann // If this was in INSERT, we are changing into an EDIT now. 101915972398b530b91612418dc11d41c356d4f43739Daniel Lehmann // If it already was an EDIT, we are changing to the new Uri now 102015972398b530b91612418dc11d41c356d4f43739Daniel Lehmann mState = null; 10211015d629f848de9d331a47c819f55854549d661dDmitri Plotnikov load(Intent.ACTION_EDIT, contactLookupUri, null); 1022825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.LOADING; 102315972398b530b91612418dc11d41c356d4f43739Daniel Lehmann getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener); 102415972398b530b91612418dc11d41c356d4f43739Daniel Lehmann } 102515972398b530b91612418dc11d41c356d4f43739Daniel Lehmann break; 1026a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov 102715972398b530b91612418dc11d41c356d4f43739Daniel Lehmann case SaveMode.SPLIT: 1028a011414b12955a91c8f3efe528f374654d930098Dmitri Plotnikov mStatus = Status.CLOSING; 1029a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann if (mListener != null) { 10308c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov mListener.onContactSplit(contactLookupUri); 1031a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } else { 1032a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann Log.d(TAG, "No listener registered, can not call onSplitFinished"); 1033a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1034f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1035f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1036f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1037f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1038f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1039f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Shows a list of aggregates that can be joined into the currently viewed aggregate. 1040f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * 1041f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * @param contactLookupUri the fresh URI for the currently edited contact (after saving it) 1042f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 1043f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void showJoinAggregateActivity(Uri contactLookupUri) { 104473a45b4ad96b21f468dbacde0da213d190979835Dmitri Plotnikov if (contactLookupUri == null || !isAdded()) { 1045f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return; 1046f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1047f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1048f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann mContactIdForJoin = ContentUris.parseId(contactLookupUri); 1049623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann mContactWritableForJoin = isContactWritable(); 1050f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final Intent intent = new Intent(JoinContactActivity.JOIN_CONTACT); 1051f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann intent.putExtra(JoinContactActivity.EXTRA_TARGET_CONTACT_ID, mContactIdForJoin); 1052a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_JOIN); 1053f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1054f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1055f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1056f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Performs aggregation with the contact selected by the user from suggestions or A-Z list. 1057f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 1058f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private void joinAggregate(final long contactId) { 10592b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov Intent intent = ContactSaveService.createJoinContactsIntent(mContext, mContactIdForJoin, 1060623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann contactId, mContactWritableForJoin, 10612b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov ContactEditorActivity.class, ContactEditorActivity.ACTION_JOIN_COMPLETED); 10622b46f0301c51973d6e3b02b78b398af097244af9Dmitri Plotnikov mContext.startService(intent); 1063f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1064f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1065f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1066ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov * Returns true if there is at least one writable raw contact in the current contact. 1067ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov */ 1068ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov private boolean isContactWritable() { 1069a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 1070ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov int size = mState.size(); 1071ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov for (int i = 0; i < size; i++) { 1072ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov ValuesDelta values = mState.get(i).getValues(); 1073ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE); 1074b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov final AccountType type = accountTypes.getAccountType(accountType); 107569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov if (!type.readOnly) { 1076ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov return true; 1077ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov } 1078ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov } 1079ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov return false; 1080ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov } 1081ec502e886a94d23f03282ed2ee0cd8400678e8d7Dmitri Plotnikov 1082cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann public static interface Listener { 1083cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann /** 108422fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann * Contact was not found, so somehow close this fragment. This is raised after a contact 108522fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann * is removed via Menu/Delete (unless it was a new contact) 1086cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann */ 108722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann void onContactNotFound(); 1088f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1089f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 10908c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov * Contact was split, so we can close now. 1091a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * @param newLookupUri The lookup uri of the new contact that should be shown to the user. 1092a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann * The editor tries best to chose the most natural contact here. 1093f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 10948c91dfb9ef1c7ac1a4b2feed0b9a8585d4873542Dmitri Plotnikov void onContactSplit(Uri newLookupUri); 1095f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1096f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1097f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * User has tapped Revert, close the fragment now. 1098f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 109922fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann void onReverted(); 1100f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1101f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1102f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Set the Title (e.g. of the Activity) 1103f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 1104f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann void setTitleTo(int resourceId); 1105f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1106f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 110722fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann * Contact was saved and the Fragment can now be closed safely. 1108f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 11095649a12fe551855f00c8dbeacfc96511c2a5fb71Katherine Kuan void onSaveFinished(Intent resultIntent); 1110b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann 1111b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann /** 1112b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann * User decided to delete the contact. 1113b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann */ 1114a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann void onDeleteRequested(Uri lookupUri); 1115e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov 1116e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov /** 1117e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov * User switched to editing a different contact (a suggestion from the 1118e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov * aggregation engine). 1119e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov */ 1120e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov void onEditOtherContactRequested( 1121e47dd262a9880121fc2b75fe82b002bc101fc682Dmitri Plotnikov Uri contactLookupUri, ArrayList<ContentValues> contentValues); 1122fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 1123fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov /** 1124fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * Contact is being created for an external account that provides its own 1125fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * new contact activity. 1126fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov */ 1127fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov void onCustomCreateContactActivityRequested(Account account, Bundle intentExtras); 1128fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov 1129fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov /** 1130fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * The edited raw contact belongs to an external account that provides 1131fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * its own edit activity. 1132fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * 1133fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * @param redirect indicates that the current editor should be closed 1134fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov * before the custom editor is shown. 1135fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov */ 1136fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov void onCustomEditContactActivityRequested(Account account, Uri rawContactUri, 1137fff6f07a02d3e3bbeff2ecf94a703782b71aea66Dmitri Plotnikov Bundle intentExtras, boolean redirect); 1138f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1139f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1140f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann private class EntityDeltaComparator implements Comparator<EntityDelta> { 1141f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1142f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann * Compare EntityDeltas for sorting the stack of editors. 1143f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann */ 11444a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann @Override 1145f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public int compare(EntityDelta one, EntityDelta two) { 1146f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check direct equality 1147f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (one.equals(two)) { 1148f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 0; 1149f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1150f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1151a07fa5f37031e4c5cd2933de02d2db41ec153e2bDmitri Plotnikov final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 1152b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov String accountType2 = one.getValues().getAsString(RawContacts.ACCOUNT_TYPE); 1153b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov final AccountType type1 = accountTypes.getAccountType(accountType2); 1154b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov accountType2 = two.getValues().getAsString(RawContacts.ACCOUNT_TYPE); 1155b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov final AccountType type2 = accountTypes.getAccountType(accountType2); 1156f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1157f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check read-only 1158b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov if (type1.readOnly && !type2.readOnly) { 1159f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 1; 1160b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov } else if (!type1.readOnly && type2.readOnly) { 1161f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 1162f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1163f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1164f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check account type 1165f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann boolean skipAccountTypeCheck = false; 1166b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov boolean isGoogleAccount1 = type1 instanceof GoogleAccountType; 1167b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov boolean isGoogleAccount2 = type2 instanceof GoogleAccountType; 116869f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov if (isGoogleAccount1 && !isGoogleAccount2) { 1169f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 117069f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov } else if (!isGoogleAccount1 && isGoogleAccount2) { 1171f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 1; 117269f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov } else if (isGoogleAccount1 && isGoogleAccount2){ 1173f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann skipAccountTypeCheck = true; 1174f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1175f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1176f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann int value; 1177f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (!skipAccountTypeCheck) { 1178b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov if (type1.accountType == null) { 11792776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru return 1; 11802776c7fe8117773fdf773396f61ed047238470f9Jean-Baptiste Queru } 1181b77be6d2ad06edfd8751f55043e4aa9fd9f36015Dmitri Plotnikov value = type1.accountType.compareTo(type2.accountType); 1182f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (value != 0) { 1183f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return value; 1184f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1185f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1186f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1187f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Check account name 1188f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ValuesDelta oneValues = one.getValues(); 1189f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME); 1190f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (oneAccount == null) oneAccount = ""; 1191f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann ValuesDelta twoValues = two.getValues(); 1192f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME); 1193f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (twoAccount == null) twoAccount = ""; 1194f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann value = oneAccount.compareTo(twoAccount); 1195f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (value != 0) { 1196f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return value; 1197f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1198f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1199f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Both are in the same account, fall back to contact ID 1200f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Long oneId = oneValues.getAsLong(RawContacts._ID); 1201f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann Long twoId = twoValues.getAsLong(RawContacts._ID); 1202f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (oneId == null) { 1203f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return -1; 1204f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } else if (twoId == null) { 1205f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return 1; 1206f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1207f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1208f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann return (int)(oneId - twoId); 1209f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1210f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1211f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1212f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann /** 1213f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Returns the contact ID for the currently edited contact or 0 if the contact is new. 1214f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 1215f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov protected long getContactId() { 1216c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov if (mState != null) { 1217c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov for (EntityDelta rawContact : mState) { 1218c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID); 1219c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov if (contactId != null) { 1220c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov return contactId; 1221c76c2e872b4d8deb0e8ac26e9558fa360d525fdeDmitri Plotnikov } 1222f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1223f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1224f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return 0; 1225f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1226f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1227f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 1228f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Triggers an asynchronous search for aggregation suggestions. 1229f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 123072af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann public void acquireAggregationSuggestions(RawContactEditorView rawContactEditor) { 12319302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov long rawContactId = rawContactEditor.getRawContactId(); 12329302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (mAggregationSuggestionsRawContactId != rawContactId 12339302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov && mAggregationSuggestionView != null) { 12349302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView.setVisibility(View.GONE); 12359302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView = null; 12369302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionEngine.reset(); 12379302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 12389302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 12399302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionsRawContactId = rawContactId; 12409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 1241f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (mAggregationSuggestionEngine == null) { 1242f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine = new AggregationSuggestionEngine(getActivity()); 1243f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.setListener(this); 1244f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.start(); 1245f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1246f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1247916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov mAggregationSuggestionEngine.setContactId(getContactId()); 1248916cf2661ada41a83556884d8f5b322d32ef452bDmitri Plotnikov 1249392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann LabeledEditorView nameEditor = rawContactEditor.getNameEditor(); 1250f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mAggregationSuggestionEngine.onNameChange(nameEditor.getValues()); 1251f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1252f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1253f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov @Override 1254f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov public void onAggregationSuggestionChange() { 1255a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov if (!isAdded() || mState == null || mStatus != Status.EDITING) { 125602cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov return; 125702cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov } 125802cbf8b0e73a7e169445e341f387356242f0334dDmitri Plotnikov 1259bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov RawContactEditorView rawContactView = 1260bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov (RawContactEditorView)getRawContactEditorView(mAggregationSuggestionsRawContactId); 12619302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (rawContactView == null) { 12629302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov return; 12639302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 1264f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 12659302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov ViewStub stub = (ViewStub)rawContactView.findViewById(R.id.aggregation_suggestion_stub); 1266f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (stub != null) { 1267f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov stub.inflate(); 1268f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1269f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 12709302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov // Only request the view on screen when it is first displayed 12719302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov boolean requestOnScreen = mAggregationSuggestionView == null; 12729302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView = rawContactView.findViewById(R.id.aggregation_suggestion); 1273f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1274f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov int count = mAggregationSuggestionEngine.getSuggestedContactCount(); 1275f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (count == 0) { 12769302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView.setVisibility(View.GONE); 1277f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return; 1278f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1279f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 12809302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov List<Suggestion> suggestions = mAggregationSuggestionEngine.getSuggestions(); 12819302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 12829302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById( 12839302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov R.id.aggregation_suggestions); 1284f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov itemList.removeAllViews(); 1285f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1286f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov LayoutInflater inflater = getActivity().getLayoutInflater(); 1287f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1288f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov for (Suggestion suggestion : suggestions) { 1289f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov AggregationSuggestionView suggestionView = 1290f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov (AggregationSuggestionView) inflater.inflate( 1291f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov R.layout.aggregation_suggestions_item, null); 1292f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov suggestionView.setLayoutParams( 1293f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov new LinearLayout.LayoutParams( 1294f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 1295c0130cc28edccb21f6698066d90ce2120096eff2Dmitri Plotnikov suggestionView.setNewContact(mState.size() == 1 && mState.get(0).isContactInsert()); 1296bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov suggestionView.setListener(this); 12979302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov suggestionView.bindSuggestion(suggestion); 1298f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov itemList.addView(suggestionView); 1299f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 13009302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 1301bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov adjustAggregationSuggestionViewLayout(rawContactView); 1302a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov setAggregationSuggestionViewEnabled(mEnabled); 13039302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mAggregationSuggestionView.setVisibility(View.VISIBLE); 13049302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 13059302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (requestOnScreen) { 13069302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov mContent.postDelayed(new Runnable() { 13079302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 13089302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov @Override 13099302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov public void run() { 13109302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov requestAggregationSuggestionOnScreen(mAggregationSuggestionView); 13119302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 13129302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov }, AGGREGATION_SUGGESTION_SCROLL_DELAY); 13139302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 1314f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1315f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1316f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 1317bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov * Adjusts the layout of the aggregation suggestion view so that it is placed directly 1318bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov * underneath and have the same width as the last text editor of the contact name editor. 1319bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov */ 1320bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov private void adjustAggregationSuggestionViewLayout(RawContactEditorView rawContactView) { 1321392ccec3b56e8074a5a028af28106134b39f64bcDaniel Lehmann TextFieldsEditorView nameEditor = rawContactView.getNameEditor(); 1322bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov Rect rect = new Rect(); 1323bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov nameEditor.acquireEditorBounds(rect); 1324bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov MarginLayoutParams layoutParams = 1325bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov (MarginLayoutParams) mAggregationSuggestionView.getLayoutParams(); 1326bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov layoutParams.leftMargin = rect.left; 1327bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov layoutParams.width = rect.width(); 1328bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov mAggregationSuggestionView.setLayoutParams(layoutParams); 1329bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1330bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1331bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov @Override 1332bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public void onJoinAction(long contactId, List<Long> rawContactIdList) { 1333bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov long rawContactIds[] = new long[rawContactIdList.size()]; 1334bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov for (int i = 0; i < rawContactIds.length; i++) { 1335bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov rawContactIds[i] = rawContactIdList.get(i); 1336bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1337bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov JoinSuggestedContactDialogFragment dialog = 1338bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov new JoinSuggestedContactDialogFragment(); 1339bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov Bundle args = new Bundle(); 1340bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov args.putLongArray("rawContactIds", rawContactIds); 1341bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov dialog.setArguments(args); 1342bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov dialog.setTargetFragment(this, 0); 134374f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov try { 134474f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov dialog.show(getFragmentManager(), "join"); 134574f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov } catch (Exception ex) { 134674f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov // No problem - the activity is no longer available to display the dialog 134774f519f81f257cd2f962fdf12e6ee9ec6fe6a5f0Dmitri Plotnikov } 1348bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1349bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1350bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public static class JoinSuggestedContactDialogFragment extends DialogFragment { 1351bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1352bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov @Override 1353bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public Dialog onCreateDialog(Bundle savedInstanceState) { 1354bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov return new AlertDialog.Builder(getActivity()) 13554292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov .setIconAttribute(android.R.attr.alertDialogIcon) 1356bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setTitle(R.string.aggregation_suggestion_join_dialog_title) 1357bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setMessage(R.string.aggregation_suggestion_join_dialog_message) 1358bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setPositiveButton(android.R.string.yes, 1359bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov new DialogInterface.OnClickListener() { 1360bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public void onClick(DialogInterface dialog, int whichButton) { 1361bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov ContactEditorFragment targetFragment = 1362bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov (ContactEditorFragment) getTargetFragment(); 1363bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov long rawContactIds[] = 1364bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov getArguments().getLongArray("rawContactIds"); 1365bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov targetFragment.doJoinSuggestedContact(rawContactIds); 1366bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1367bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1368bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov ) 1369bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setNegativeButton(android.R.string.no, null) 1370bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .create(); 1371bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1372bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1373bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1374bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov /** 1375bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov * Joins the suggested contact (specified by the id's of constituent raw 1376bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov * contacts), save all changes, and stay in the editor. 1377bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov */ 1378bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov protected void doJoinSuggestedContact(long[] rawContactIds) { 1379cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov if (!hasValidState() || mStatus != Status.EDITING) { 1380cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov return; 1381cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov } 1382cd1b9a29458d30ec74cf94dc9945cbdb6186a68eDmitri Plotnikov 1383bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov mState.setJoinWithRawContacts(rawContactIds); 13849df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov save(SaveMode.RELOAD); 1385bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1386bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1387bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov @Override 1388bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public void onEditAction(Uri contactLookupUri) { 1389bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov SuggestionEditConfirmationDialogFragment dialog = 1390bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov new SuggestionEditConfirmationDialogFragment(); 1391bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov Bundle args = new Bundle(); 1392bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov args.putParcelable("contactUri", contactLookupUri); 1393bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov dialog.setArguments(args); 1394bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov dialog.setTargetFragment(this, 0); 1395bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov dialog.show(getFragmentManager(), "edit"); 1396bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1397bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1398bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public static class SuggestionEditConfirmationDialogFragment extends DialogFragment { 1399bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1400bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov @Override 1401bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public Dialog onCreateDialog(Bundle savedInstanceState) { 1402bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov return new AlertDialog.Builder(getActivity()) 14034292dfa46123a6c0e1de9862b4d8694bfb87875aDmitri Plotnikov .setIconAttribute(android.R.attr.alertDialogIcon) 1404bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setTitle(R.string.aggregation_suggestion_edit_dialog_title) 1405bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setMessage(R.string.aggregation_suggestion_edit_dialog_message) 1406bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setPositiveButton(android.R.string.yes, 1407bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov new DialogInterface.OnClickListener() { 1408bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public void onClick(DialogInterface dialog, int whichButton) { 1409bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov ContactEditorFragment targetFragment = 1410bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov (ContactEditorFragment) getTargetFragment(); 1411bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov Uri contactUri = 1412bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov getArguments().getParcelable("contactUri"); 1413bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov targetFragment.doEditSuggestedContact(contactUri); 1414bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1415bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1416bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov ) 1417bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .setNegativeButton(android.R.string.no, null) 1418bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov .create(); 1419bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1420bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1421bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1422bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov /** 1423bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov * Abandons the currently edited contact and switches to editing the suggested 1424bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov * one, transferring all the data there 1425bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov */ 1426bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov protected void doEditSuggestedContact(Uri contactUri) { 1427bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov if (mListener != null) { 1428a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann // make sure we don't save this contact when closing down 1429a10775d625339d168337e03de05d02f5e0a4f55dDaniel Lehmann mStatus = Status.CLOSING; 1430bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov mListener.onEditOtherContactRequested( 1431bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov contactUri, mState.get(0).getContentValues()); 1432bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1433bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov } 1434bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov 1435bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov /** 1436f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Scrolls the editor if necessary to reveal the aggregation suggestion that is 1437f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * shown below the name editor. Makes sure that the currently focused field 1438f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * remains visible. 1439f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 1440f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private void requestAggregationSuggestionOnScreen(final View view) { 1441f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov Rect rect = getRelativeBounds(mContent, view); 1442f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov View focused = mContent.findFocus(); 1443f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov if (focused != null) { 1444f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov rect.union(getRelativeBounds(mContent, focused)); 1445f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1446f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov mContent.requestRectangleOnScreen(rect); 1447f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1448f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1449a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov public void setAggregationSuggestionViewEnabled(boolean enabled) { 1450a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov if (mAggregationSuggestionView == null) { 1451a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov return; 1452a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov } 1453a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov 1454a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov LinearLayout itemList = (LinearLayout) mAggregationSuggestionView.findViewById( 1455a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov R.id.aggregation_suggestions); 1456a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov int count = itemList.getChildCount(); 1457a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov for (int i = 0; i < count; i++) { 1458a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov itemList.getChildAt(i).setEnabled(enabled); 1459a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov } 1460a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov } 1461a9333790f027d59a2edfd4a98c0392b144577416Dmitri Plotnikov 1462f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov /** 1463f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov * Computes bounds of the supplied view relative to its ascendant. 1464f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov */ 1465f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov private Rect getRelativeBounds(View ascendant, View view) { 1466f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov Rect rect = new Rect(); 1467f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov rect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); 1468f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1469f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov View parent = (View) view.getParent(); 1470f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov while (parent != ascendant) { 1471f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov rect.offset(parent.getLeft(), parent.getTop()); 1472f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov parent = (View) parent.getParent(); 1473f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1474f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov return rect; 1475f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov } 1476f491ae914769f1062a4d9c31fcbec5ff0e01e4e6Dmitri Plotnikov 1477f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann @Override 1478f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void onSaveInstanceState(Bundle outState) { 1479b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann outState.putParcelable(KEY_URI, mLookupUri); 1480d364314c460152db7089b304beec81b3675893baDmitri Plotnikov outState.putString(KEY_ACTION, mAction); 1481d364314c460152db7089b304beec81b3675893baDmitri Plotnikov 1482f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (hasValidState()) { 1483f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Store entities with modifications 1484f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putParcelable(KEY_EDIT_STATE, mState); 1485f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1486f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1487f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto); 1488f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator); 1489f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (mCurrentPhotoFile != null) { 1490f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString()); 1491f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1492f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin); 1493623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin); 14949302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId); 149502bb1252aa990813fa9e86ad75c458acc15e6801Dmitri Plotnikov outState.putBoolean(KEY_ENABLED, mEnabled); 1496ce37f3017c666bcea483a75322e80d5cc1ba6f64Dmitri Plotnikov outState.putInt(KEY_STATUS, mStatus); 1497f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann super.onSaveInstanceState(outState); 1498f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1499f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1500d364314c460152db7089b304beec81b3675893baDmitri Plotnikov @Override 1501f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann public void onActivityResult(int requestCode, int resultCode, Intent data) { 1502f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov if (mStatus == Status.SUB_ACTIVITY) { 1503f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov mStatus = Status.EDITING; 1504f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov } 1505f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov 1506f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann // Ignore failed requests 1507f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (resultCode != Activity.RESULT_OK) return; 1508f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann switch (requestCode) { 1509a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: { 1510c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann // As we are coming back to this view, the editor will be reloaded automatically, 1511c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann // which will cause the photo that is set here to disappear. To prevent this, 15124a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // we remember to set a flag which is interpreted after loading. 15134a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann // This photo is set here already to reduce flickering. 1514c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mPhoto = data.getParcelableExtra("data"); 1515c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann setPhoto(mRawContactIdRequestingPhoto, mPhoto); 1516c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mRawContactIdRequestingPhotoAfterLoad = mRawContactIdRequestingPhoto; 1517c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mRawContactIdRequestingPhoto = -1; 1518f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann 1519f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1520f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1521a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann case REQUEST_CODE_CAMERA_WITH_DATA: { 1522f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann doCropPhoto(mCurrentPhotoFile); 1523f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann break; 1524f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1525a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann case REQUEST_CODE_JOIN: { 1526f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann if (data != null) { 1527f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann final long contactId = ContentUris.parseId(data.getData()); 1528f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann joinAggregate(contactId); 1529f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 15304a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann break; 1531f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1532f319cf8549738feca5965a598af9a310869e1f3dDaniel Lehmann } 1533cdef2b60aa87b1178033fdc964a3402386c03d7cDaniel Lehmann } 15349cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov 1535c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann /** 1536c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann * Sets the photo stored in mPhoto and writes it to the RawContact with the given id 1537c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann */ 1538c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann private void setPhoto(long rawContact, Bitmap photo) { 1539bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact); 15409302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (requestingEditor != null) { 15419302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov requestingEditor.setPhotoBitmap(photo); 15429302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } else { 15439302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov Log.w(TAG, "The contact that requested the photo is no longer present."); 15449302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 15459302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov } 15469302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov 15479302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov /** 15489302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov * Finds raw contact editor view for the given rawContactId. 15499302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov */ 1550bd0c12c63bb0adbc78715d9d13ba588c8ae61839Dmitri Plotnikov public BaseRawContactEditorView getRawContactEditorView(long rawContactId) { 1551c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann for (int i = 0; i < mContent.getChildCount(); i++) { 1552c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann final View childView = mContent.getChildAt(i); 155372af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann if (childView instanceof BaseRawContactEditorView) { 155472af89f9e497bb8ef54fe3deeec7e8477d192242Daniel Lehmann final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; 15559302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov if (editor.getRawContactId() == rawContactId) { 15569302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov return editor; 1557c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1558c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1559c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 15609302ba7bc47d995c88eba7604aeea00a7e41779fDmitri Plotnikov return null; 1561c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1562c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann 1563fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann /** 1564fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann * Returns true if there is currently more than one photo on screen. 1565fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann */ 1566fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann private boolean hasMoreThanOnePhoto() { 1567fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann int count = mContent.getChildCount(); 1568fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann int countWithPicture = 0; 1569fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann for (int i = 0; i < count; i++) { 1570fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann final View childView = mContent.getChildAt(i); 1571fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann if (childView instanceof BaseRawContactEditorView) { 1572fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; 1573fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann if (editor.hasSetPhoto()) { 1574fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann countWithPicture++; 1575fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann if (countWithPicture > 1) return true; 1576fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann } 1577fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann } 1578fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann } 1579fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann 1580fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann return false; 15819cd1708f333eda622dc6a4fed2a0df9058193a9dDmitri Plotnikov } 1582222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 1583222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann /** 1584222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann * The listener for the data loader 1585222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann */ 1586222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener = 1587222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann new LoaderCallbacks<ContactLoader.Result>() { 1588222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann @Override 1589222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) { 1590222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann mLoaderStartTime = SystemClock.elapsedRealtime(); 1591b846fc117b2c4c0c3ed5eb3e9ce32591986a0253Daniel Lehmann return new ContactLoader(mContext, mLookupUri); 1592222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 1593222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 1594222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann @Override 1595222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) { 1596222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann final long loaderCurrentTime = SystemClock.elapsedRealtime(); 1597222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime)); 15985da9363bc4f2e04dc388579e1df979a5843e25e6Dmitri Plotnikov if (data == ContactLoader.Result.NOT_FOUND || data == ContactLoader.Result.ERROR) { 1599222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann // Item has been deleted 1600222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann Log.i(TAG, "No contact found. Closing activity"); 160122fb2053fe2bfe98376bf1a0e564f23ae9cecdedDaniel Lehmann if (mListener != null) mListener.onContactNotFound(); 1602222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann return; 1603222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 1604222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann 1605825cb62b7df3cfe208651d488278e1b57c863884Daniel Lehmann mStatus = Status.EDITING; 16066caccaeeed943db323be89853a108f422e670760Dmitri Plotnikov mLookupUri = data.getLookupUri(); 1607222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann final long setDataStartTime = SystemClock.elapsedRealtime(); 1608222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann setData(data); 1609222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann final long setDataEndTime = SystemClock.elapsedRealtime(); 1610c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann 1611c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann // If we are coming back from the photo trimmer, this will be set. 1612c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann if (mRawContactIdRequestingPhotoAfterLoad != -1) { 1613c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann setPhoto(mRawContactIdRequestingPhotoAfterLoad, mPhoto); 1614c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mRawContactIdRequestingPhotoAfterLoad = -1; 1615c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann mPhoto = null; 1616c1406450bb2a1a214ff35e99a173ee1a28b926faDaniel Lehmann } 1617222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann Log.v(TAG, "Time needed for setting UI: " + (setDataEndTime-setDataStartTime)); 1618222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann } 16194ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn 1620623932de8c18e9b83b6fd941afe415ab2e6c730bDaniel Lehmann @Override 16214ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn public void onLoaderReset(Loader<ContactLoader.Result> loader) { 16224ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn } 1623222744ea3cd7233677f0ef88804eb3e2db710e43Daniel Lehmann }; 1624a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 1625e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov /** 1626be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan * The listener for the group meta data loader for all groups. 1627e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov */ 1628e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov private final LoaderManager.LoaderCallbacks<Cursor> mGroupLoaderListener = 1629e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov new LoaderCallbacks<Cursor>() { 1630e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 1631e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov @Override 1632e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov public CursorLoader onCreateLoader(int id, Bundle args) { 1633be18de05d6f6a107c552e369bce58f51c946fde7Katherine Kuan return new GroupMetaDataLoader(mContext, Groups.CONTENT_URI); 1634e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 1635e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 1636e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov @Override 1637e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 1638e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov mGroupMetaData = data; 1639e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov bindGroupMetaData(); 1640e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov } 16414ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn 16424ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn public void onLoaderReset(Loader<Cursor> loader) { 16434ef95cc3329b4ad9fa450e4090efaad9935d493fDianne Hackborn } 1644e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov }; 1645e843f916942fff482ec162eee2a23914e32182cfDmitri Plotnikov 1646a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann @Override 1647a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann public void onSplitContactConfirmed() { 1648a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann mState.markRawContactsForSplitting(); 16499df61ed9eeecb81043e7e6662ff3da83428d6865Dmitri Plotnikov save(SaveMode.SPLIT); 1650a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1651a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 16529442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann private final class PhotoEditorListener 16539442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann implements EditorListener, PhotoActionPopup.Listener { 16549442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann private final BaseRawContactEditorView mEditor; 165569f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov private final boolean mAccountReadOnly; 16569442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann 165769f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov private PhotoEditorListener(BaseRawContactEditorView editor, boolean accountReadOnly) { 16589442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mEditor = editor; 165969f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov mAccountReadOnly = accountReadOnly; 16609442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 16619442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann 16629442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann @Override 16639442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann public void onRequest(int request) { 16649442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann if (!hasValidState()) return; 16659442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann 16669442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann if (request == EditorListener.REQUEST_PICK_PHOTO) { 16679442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann // Determine mode 16689442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann final int mode; 166969f9e6f0cd9b5401da55f251e9bd98e69643d7dfDmitri Plotnikov if (mAccountReadOnly) { 16709442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann if (mEditor.hasSetPhoto() && hasMoreThanOnePhoto()) { 16719442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mode = PhotoActionPopup.MODE_READ_ONLY_ALLOW_PRIMARY; 16729442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } else { 16739442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann // Read-only and either no photo or the only photo ==> no options 16749442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann return; 16759442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 16769442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } else { 16779442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann if (mEditor.hasSetPhoto()) { 16789442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann if (hasMoreThanOnePhoto()) { 16799442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mode = PhotoActionPopup.MODE_PHOTO_ALLOW_PRIMARY; 16809442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } else { 16819442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mode = PhotoActionPopup.MODE_PHOTO_DISALLOW_PRIMARY; 16829442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 16839442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } else { 16849442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mode = PhotoActionPopup.MODE_NO_PHOTO; 16859442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 1686fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann } 16879442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann PhotoActionPopup.createPopupMenu(mContext, mEditor.getPhotoEditor(), this, mode) 16889442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann .show(); 1689fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann } 1690fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann } 1691fe22aff8c87374cfa80a7a02ec29b442f2453d8cDaniel Lehmann 16929442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann @Override 16939442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann public void onDeleted(Editor removedEditor) { 16949442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 1695a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 16969442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann /** 16979442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann * User has chosen to set the selected photo as the (super) primary photo 16989442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann */ 16999442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann @Override 17009442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann public void onUseAsPrimaryChosen() { 17019442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann // Set the IsSuperPrimary for each editor 17029442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann int count = mContent.getChildCount(); 17039442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann for (int i = 0; i < count; i++) { 17049442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann final View childView = mContent.getChildAt(i); 17059442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann if (childView instanceof BaseRawContactEditorView) { 17069442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; 17079442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann final PhotoEditorView photoEditor = editor.getPhotoEditor(); 17089442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann photoEditor.setSuperPrimary(editor == mEditor); 17099442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 17109442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 1711a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1712a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 17139442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann /** 17149442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann * User has chosen to remove a picture 17159442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann */ 17169442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann @Override 17179442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann public void onRemovePictureChose() { 17189442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mEditor.setPhotoBitmap(null); 1719a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann } 1720a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 17219442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann /** 17229442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann * Launches Camera to take a picture and store it in a file. 17239442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann */ 17249442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann @Override 17259442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann public void onTakePhotoChosen() { 17269442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mRawContactIdRequestingPhoto = mEditor.getRawContactId(); 17279442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann try { 17289442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann // Launch camera to take photo for selected contact 17299442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann PHOTO_DIR.mkdirs(); 17309442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName()); 17319442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann final Intent intent = getTakePickIntent(mCurrentPhotoFile); 17329442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann 1733f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov mStatus = Status.SUB_ACTIVITY; 17349442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_CAMERA_WITH_DATA); 17359442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } catch (ActivityNotFoundException e) { 17369442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann Toast.makeText(mContext, R.string.photoPickerNotFoundText, 17379442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann Toast.LENGTH_LONG).show(); 17389442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 17399442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 1740a35a7e2aabc4edfafb9b4171e279bdb4c0c03d44Daniel Lehmann 17419442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann /** 17429442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann * Launches Gallery to pick a photo. 17439442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann */ 17449442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann @Override 17459442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann public void onPickFromGalleryChosen() { 17469442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann mRawContactIdRequestingPhoto = mEditor.getRawContactId(); 17479442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann try { 17489442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann // Launch picker to choose photo for selected contact 17499442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann final Intent intent = getPhotoPickIntent(); 1750f9ca423c867ab2cd4f0d9025a95436489c41d405Dmitri Plotnikov mStatus = Status.SUB_ACTIVITY; 17519442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann startActivityForResult(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA); 17529442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } catch (ActivityNotFoundException e) { 17539442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann Toast.makeText(mContext, R.string.photoPickerNotFoundText, 17549442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann Toast.LENGTH_LONG).show(); 17559442ef4d2667eab16f65535b63757a7ffe4ccf69Daniel Lehmann } 17564a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 17574a62be4f5a365e5afde71becfd446381f2baa494Daniel Lehmann } 17582ae666ec99ae9318936a9326e5243987e4e1c586Jeff Sharkey} 1759