1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.contacts.activities; 18 19 import com.android.contacts.ContactSaveService; 20 import com.android.contacts.ContactsActivity; 21 import com.android.contacts.R; 22 import com.android.contacts.common.model.AccountTypeManager; 23 import com.android.contacts.common.model.account.AccountType; 24 import com.android.contacts.common.model.account.AccountWithDataSet; 25 import com.android.contacts.common.util.ImplicitIntentsUtil; 26 import com.android.contacts.editor.ContactEditorBaseFragment; 27 import com.android.contacts.editor.ContactEditorFragment; 28 import com.android.contacts.editor.EditorIntents; 29 import com.android.contacts.interactions.ContactDeletionInteraction; 30 import com.android.contacts.util.DialogManager; 31 32 import android.app.ActionBar; 33 import android.app.Dialog; 34 import android.content.ContentValues; 35 import android.content.Intent; 36 import android.net.Uri; 37 import android.os.Bundle; 38 import android.provider.ContactsContract.Contacts; 39 import android.provider.ContactsContract.RawContacts; 40 import android.util.Log; 41 import android.view.View; 42 import android.view.inputmethod.InputMethodManager; 43 44 import java.util.ArrayList; 45 46 /** 47 * Base Activity for contact editors. 48 */ 49 abstract public class ContactEditorBaseActivity extends ContactsActivity 50 implements DialogManager.DialogShowingViewActivity { 51 protected static final String TAG = "ContactEditorActivity"; 52 53 /** 54 * Intent action to edit a contact with all available field inputs displayed. 55 * 56 * Only used to open the "fully expanded" editor -- {@link ContactEditorActivity}. 57 */ 58 public static final String ACTION_EDIT = "com.android.contacts.action.FULL_EDIT"; 59 60 /** 61 * Intent action to insert a new contact with all available field inputs displayed. 62 * 63 * Only used to open the "fully expanded" editor -- {@link ContactEditorActivity}. 64 */ 65 public static final String ACTION_INSERT = "com.android.contacts.action.FULL_INSERT"; 66 67 public static final String ACTION_JOIN_COMPLETED = "joinCompleted"; 68 public static final String ACTION_SAVE_COMPLETED = "saveCompleted"; 69 70 /** 71 * Contract for contact editors Fragments that are managed by this Activity. 72 */ 73 public interface ContactEditor { 74 75 /** 76 * Modes that specify what the AsyncTask has to perform after saving 77 */ 78 public interface SaveMode { 79 /** 80 * Close the editor after saving 81 */ 82 public static final int CLOSE = 0; 83 84 /** 85 * Reload the data so that the user can continue editing 86 */ 87 public static final int RELOAD = 1; 88 89 /** 90 * Split the contact after saving 91 */ 92 public static final int SPLIT = 2; 93 94 /** 95 * Join another contact after saving 96 */ 97 public static final int JOIN = 3; 98 99 /** 100 * Navigate to the compact editor view after saving. 101 */ 102 public static final int COMPACT = 4; 103 } 104 105 /** 106 * The status of the contact editor. 107 */ 108 public interface Status { 109 /** 110 * The loader is fetching data 111 */ 112 public static final int LOADING = 0; 113 114 /** 115 * Not currently busy. We are waiting for the user to enter data 116 */ 117 public static final int EDITING = 1; 118 119 /** 120 * The data is currently being saved. This is used to prevent more 121 * auto-saves (they shouldn't overlap) 122 */ 123 public static final int SAVING = 2; 124 125 /** 126 * Prevents any more saves. This is used if in the following cases: 127 * - After Save/Close 128 * - After Revert 129 * - After the user has accepted an edit suggestion 130 * - After the user chooses to expand the compact editor 131 */ 132 public static final int CLOSING = 3; 133 134 /** 135 * Prevents saving while running a child activity. 136 */ 137 public static final int SUB_ACTIVITY = 4; 138 } 139 140 /** 141 * Sets the hosting Activity that will receive callbacks from the contact editor. 142 */ setListener(ContactEditorBaseFragment.Listener listener)143 void setListener(ContactEditorBaseFragment.Listener listener); 144 145 /** 146 * Initialize the contact editor. 147 */ load(String action, Uri lookupUri, Bundle intentExtras)148 void load(String action, Uri lookupUri, Bundle intentExtras); 149 150 /** 151 * Applies extras from the hosting Activity to the first writable raw contact. 152 */ setIntentExtras(Bundle extras)153 void setIntentExtras(Bundle extras); 154 155 /** 156 * Saves or creates the contact based on the mode, and if successful 157 * finishes the activity. 158 * 159 * @param backPressed whether the save was initiated as a result of a back button press 160 * or because the framework stopped the editor Activity 161 */ save(int saveMode, boolean backPressed)162 boolean save(int saveMode, boolean backPressed); 163 164 /** 165 * If there are no unsaved changes, just close the editor, otherwise the user is prompted 166 * before discarding unsaved changes. 167 */ revert()168 boolean revert(); 169 170 /** 171 * Invoked after the contact is saved. 172 */ onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded, Uri contactLookupUri, Bundle updatedPhotos, boolean backPressed, long photoId, long nameId)173 void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded, 174 Uri contactLookupUri, Bundle updatedPhotos, boolean backPressed, long photoId, 175 long nameId); 176 177 /** 178 * Invoked after the contact is joined. 179 */ onJoinCompleted(Uri uri)180 void onJoinCompleted(Uri uri); 181 } 182 183 /** 184 * Boolean intent key that specifies that this activity should finish itself 185 * (instead of launching a new view intent) after the editor changes have been 186 * saved. 187 */ 188 public static final String INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED = 189 "finishActivityOnSaveCompleted"; 190 191 protected ContactEditor mFragment; 192 private boolean mFinishActivityOnSaveCompleted; 193 194 private DialogManager mDialogManager = new DialogManager(this); 195 196 @Override onCreate(Bundle savedState)197 public void onCreate(Bundle savedState) { 198 super.onCreate(savedState); 199 200 final Intent intent = getIntent(); 201 final String action = intent.getAction(); 202 203 // Determine whether or not this activity should be finished after the user is done 204 // editing the contact or if this activity should launch another activity to view the 205 // contact's details. 206 mFinishActivityOnSaveCompleted = intent.getBooleanExtra( 207 INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, false); 208 209 // The only situation where action could be ACTION_JOIN_COMPLETED is if the 210 // user joined the contact with another and closed the activity before 211 // the save operation was completed. The activity should remain closed then. 212 if (ACTION_JOIN_COMPLETED.equals(action)) { 213 finish(); 214 return; 215 } 216 217 if (ACTION_SAVE_COMPLETED.equals(action)) { 218 finish(); 219 return; 220 } 221 222 ActionBar actionBar = getActionBar(); 223 if (actionBar != null) { 224 if (Intent.ACTION_EDIT.equals(action) || ACTION_EDIT.equals(action)) { 225 actionBar.setTitle(getResources().getString( 226 R.string.contact_editor_title_existing_contact)); 227 } else { 228 actionBar.setTitle(getResources().getString( 229 R.string.contact_editor_title_new_contact)); 230 } 231 actionBar.setDisplayShowHomeEnabled(true); 232 actionBar.setDisplayHomeAsUpEnabled(true); 233 } 234 } 235 236 @Override onPause()237 protected void onPause() { 238 super.onPause(); 239 final InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 240 final View currentFocus = getCurrentFocus(); 241 if (imm != null && currentFocus != null) { 242 imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0); 243 } 244 } 245 246 @Override onNewIntent(Intent intent)247 protected void onNewIntent(Intent intent) { 248 super.onNewIntent(intent); 249 250 if (mFragment == null) { 251 return; 252 } 253 254 String action = intent.getAction(); 255 if (Intent.ACTION_EDIT.equals(action) || ACTION_EDIT.equals(action)) { 256 mFragment.setIntentExtras(intent.getExtras()); 257 } else if (ACTION_SAVE_COMPLETED.equals(action)) { 258 mFragment.onSaveCompleted(true, 259 intent.getIntExtra(ContactEditorFragment.SAVE_MODE_EXTRA_KEY, 260 ContactEditor.SaveMode.CLOSE), 261 intent.getBooleanExtra(ContactSaveService.EXTRA_SAVE_SUCCEEDED, false), 262 intent.getData(), 263 (Bundle) intent.getParcelableExtra(ContactSaveService.EXTRA_UPDATED_PHOTOS), 264 intent.getBooleanExtra(ContactEditorFragment.INTENT_EXTRA_SAVE_BACK_PRESSED, 265 false), 266 intent.getLongExtra(ContactEditorFragment.INTENT_EXTRA_PHOTO_ID, -1), 267 intent.getLongExtra(ContactEditorFragment.INTENT_EXTRA_NAME_ID, -1)); 268 } else if (ACTION_JOIN_COMPLETED.equals(action)) { 269 mFragment.onJoinCompleted(intent.getData()); 270 } 271 } 272 273 @Override onCreateDialog(int id, Bundle args)274 protected Dialog onCreateDialog(int id, Bundle args) { 275 if (DialogManager.isManagedId(id)) return mDialogManager.onCreateDialog(id, args); 276 277 // Nobody knows about the Dialog 278 Log.w(TAG, "Unknown dialog requested, id: " + id + ", args: " + args); 279 return null; 280 } 281 282 protected final ContactEditorBaseFragment.Listener mFragmentListener = 283 new ContactEditorBaseFragment.Listener() { 284 285 @Override 286 public void onDeleteRequested(Uri contactUri) { 287 ContactDeletionInteraction.start(ContactEditorBaseActivity.this, contactUri, true); 288 } 289 290 @Override 291 public void onReverted() { 292 finish(); 293 } 294 295 @Override 296 public void onSaveFinished(Intent resultIntent) { 297 final boolean backPressed = resultIntent == null ? false : resultIntent.getBooleanExtra( 298 ContactEditorBaseFragment.INTENT_EXTRA_SAVE_BACK_PRESSED, false); 299 if (mFinishActivityOnSaveCompleted) { 300 setResult(resultIntent == null ? RESULT_CANCELED : RESULT_OK, resultIntent); 301 } else if (resultIntent != null) { 302 if (backPressed) { 303 ImplicitIntentsUtil.startActivityInApp(ContactEditorBaseActivity.this, 304 resultIntent); 305 } 306 } 307 finish(); 308 } 309 310 @Override 311 public void onContactSplit(Uri newLookupUri) { 312 finish(); 313 } 314 315 @Override 316 public void onContactNotFound() { 317 finish(); 318 } 319 320 @Override 321 public void onEditOtherContactRequested( 322 Uri contactLookupUri, ArrayList<ContentValues> values) { 323 final Intent intent = EditorIntents.createEditOtherContactIntent( 324 contactLookupUri, values); 325 ImplicitIntentsUtil.startActivityInApp(ContactEditorBaseActivity.this, intent); 326 finish(); 327 } 328 329 @Override 330 public void onCustomCreateContactActivityRequested(AccountWithDataSet account, 331 Bundle intentExtras) { 332 final AccountTypeManager accountTypes = 333 AccountTypeManager.getInstance(ContactEditorBaseActivity.this); 334 final AccountType accountType = accountTypes.getAccountType( 335 account.type, account.dataSet); 336 337 Intent intent = new Intent(); 338 intent.setClassName(accountType.syncAdapterPackageName, 339 accountType.getCreateContactActivityClassName()); 340 intent.setAction(Intent.ACTION_INSERT); 341 intent.setType(Contacts.CONTENT_ITEM_TYPE); 342 if (intentExtras != null) { 343 intent.putExtras(intentExtras); 344 } 345 intent.putExtra(RawContacts.ACCOUNT_NAME, account.name); 346 intent.putExtra(RawContacts.ACCOUNT_TYPE, account.type); 347 intent.putExtra(RawContacts.DATA_SET, account.dataSet); 348 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 349 | Intent.FLAG_ACTIVITY_FORWARD_RESULT); 350 startActivity(intent); 351 finish(); 352 } 353 354 @Override 355 public void onCustomEditContactActivityRequested(AccountWithDataSet account, 356 Uri rawContactUri, Bundle intentExtras, boolean redirect) { 357 final AccountTypeManager accountTypes = 358 AccountTypeManager.getInstance(ContactEditorBaseActivity.this); 359 final AccountType accountType = accountTypes.getAccountType( 360 account.type, account.dataSet); 361 362 Intent intent = new Intent(); 363 intent.setClassName(accountType.syncAdapterPackageName, 364 accountType.getEditContactActivityClassName()); 365 intent.setAction(Intent.ACTION_EDIT); 366 intent.setData(rawContactUri); 367 if (intentExtras != null) { 368 intent.putExtras(intentExtras); 369 } 370 371 if (redirect) { 372 intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 373 | Intent.FLAG_ACTIVITY_FORWARD_RESULT); 374 startActivity(intent); 375 finish(); 376 } else { 377 startActivity(intent); 378 } 379 } 380 }; 381 382 @Override getDialogManager()383 public DialogManager getDialogManager() { 384 return mDialogManager; 385 } 386 } 387