ContactEditorFragment.java revision 92f8ccc1f15df787b7434224857c056721281046
1/* 2 * Copyright (C) 2010 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 17package com.android.contacts.editor; 18 19import android.app.Activity; 20import android.content.Context; 21import android.content.Intent; 22import android.graphics.Bitmap; 23import android.net.Uri; 24import android.os.Bundle; 25import android.provider.ContactsContract.CommonDataKinds.Photo; 26import android.text.TextUtils; 27import android.util.Log; 28import android.view.LayoutInflater; 29import android.view.View; 30import android.view.ViewGroup; 31import android.widget.AdapterView; 32import android.widget.LinearLayout; 33import android.widget.ListPopupWindow; 34 35import com.android.contacts.ContactSaveService; 36import com.android.contacts.R; 37import com.android.contacts.activities.ContactEditorActivity; 38import com.android.contacts.activities.ContactEditorBaseActivity.ContactEditor; 39import com.android.contacts.common.model.AccountTypeManager; 40import com.android.contacts.common.model.RawContactDelta; 41import com.android.contacts.common.model.RawContactDeltaList; 42import com.android.contacts.common.model.RawContactModifier; 43import com.android.contacts.common.model.ValuesDelta; 44import com.android.contacts.common.model.account.AccountType; 45import com.android.contacts.common.model.account.AccountWithDataSet; 46import com.android.contacts.common.util.AccountsListAdapter; 47import com.android.contacts.common.util.AccountsListAdapter.AccountListFilter; 48import com.android.contacts.detail.PhotoSelectionHandler; 49import com.android.contacts.editor.Editor.EditorListener; 50import com.android.contacts.util.ContactPhotoUtils; 51import com.android.contacts.util.UiClosables; 52 53import com.google.common.collect.ImmutableList; 54import com.google.common.collect.Lists; 55 56import java.io.FileNotFoundException; 57import java.util.Collections; 58import java.util.HashMap; 59import java.util.List; 60 61/** 62 * Contact editor with all fields displayed. 63 */ 64public class ContactEditorFragment extends ContactEditorBaseFragment implements 65 ContactEditor, SplitContactConfirmationDialogFragment.Listener, 66 RawContactReadOnlyEditorView.Listener { 67 68 private static final String KEY_EXPANDED_EDITORS = "expandedEditors"; 69 70 private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester"; 71 private static final String KEY_CURRENT_PHOTO_URI = "currentphotouri"; 72 private static final String KEY_UPDATED_PHOTOS = "updatedPhotos"; 73 74 // Used to store which raw contact editors have been expanded. Keyed on raw contact ids. 75 private HashMap<Long, Boolean> mExpandedEditors = new HashMap<Long, Boolean>(); 76 77 /** 78 * The raw contact for which we started "take photo" or "choose photo from gallery" most 79 * recently. Used to restore {@link #mCurrentPhotoHandler} after orientation change. 80 */ 81 private long mRawContactIdRequestingPhoto; 82 83 /** 84 * The {@link PhotoHandler} for the photo editor for the {@link #mRawContactIdRequestingPhoto} 85 * raw contact. 86 * 87 * A {@link PhotoHandler} is created for each photo editor in {@link #bindPhotoHandler}, but 88 * the only "active" one should get the activity result. This member represents the active 89 * one. 90 */ 91 private PhotoHandler mCurrentPhotoHandler; 92 private Uri mCurrentPhotoUri; 93 private Bundle mUpdatedPhotos = new Bundle(); 94 95 public ContactEditorFragment() { 96 } 97 98 @Override 99 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) { 100 final View view = inflater.inflate(R.layout.contact_editor_fragment, container, false); 101 102 mContent = (LinearLayout) view.findViewById(R.id.editors); 103 104 setHasOptionsMenu(true); 105 106 return view; 107 } 108 109 @Override 110 public void onCreate(Bundle savedState) { 111 super.onCreate(savedState); 112 113 if (savedState != null) { 114 mExpandedEditors = (HashMap<Long, Boolean>) 115 savedState.getSerializable(KEY_EXPANDED_EDITORS); 116 mRawContactIdRequestingPhoto = savedState.getLong( 117 KEY_RAW_CONTACT_ID_REQUESTING_PHOTO); 118 mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI); 119 mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS); 120 } 121 } 122 123 @Override 124 public void onExternalEditorRequest(AccountWithDataSet account, Uri uri) { 125 mListener.onCustomEditContactActivityRequested(account, uri, null, false); 126 } 127 128 @Override 129 public void onEditorExpansionChanged() { 130 updatedExpandedEditorsMap(); 131 } 132 133 /** 134 * Removes a current editor ({@link #mState}) and rebinds new editor for a new account. 135 * Some of old data are reused with new restriction enforced by the new account. 136 * 137 * @param oldState Old data being edited. 138 * @param oldAccount Old account associated with oldState. 139 * @param newAccount New account to be used. 140 */ 141 private void rebindEditorsForNewContact( 142 RawContactDelta oldState, AccountWithDataSet oldAccount, 143 AccountWithDataSet newAccount) { 144 AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 145 AccountType oldAccountType = accountTypes.getAccountTypeForAccount(oldAccount); 146 AccountType newAccountType = accountTypes.getAccountTypeForAccount(newAccount); 147 148 if (newAccountType.getCreateContactActivityClassName() != null) { 149 Log.w(TAG, "external activity called in rebind situation"); 150 if (mListener != null) { 151 mListener.onCustomCreateContactActivityRequested(newAccount, mIntentExtras); 152 } 153 } else { 154 mExistingContactDataReady = false; 155 mNewContactDataReady = false; 156 mState = new RawContactDeltaList(); 157 setStateForNewContact(newAccount, newAccountType, oldState, oldAccountType); 158 if (mIsEdit) { 159 setStateForExistingContact(mDefaultDisplayName, mIsUserProfile, mRawContacts); 160 } 161 } 162 } 163 164 @Override 165 protected void setGroupMetaData() { 166 if (mGroupMetaData == null) { 167 return; 168 } 169 int editorCount = mContent.getChildCount(); 170 for (int i = 0; i < editorCount; i++) { 171 BaseRawContactEditorView editor = (BaseRawContactEditorView) mContent.getChildAt(i); 172 editor.setGroupMetaData(mGroupMetaData); 173 } 174 } 175 176 @Override 177 protected void bindEditors() { 178 // bindEditors() can only bind views if there is data in mState, so immediately return 179 // if mState is null 180 if (mState.isEmpty()) { 181 return; 182 } 183 184 // Check if delta list is ready. Delta list is populated from existing data and when 185 // editing an read-only contact, it's also populated with newly created data for the 186 // blank form. When the data is not ready, skip. This method will be called multiple times. 187 if ((mIsEdit && !mExistingContactDataReady) || (mHasNewContact && !mNewContactDataReady)) { 188 return; 189 } 190 191 // Sort the editors 192 Collections.sort(mState, mComparator); 193 194 // Remove any existing editors and rebuild any visible 195 mContent.removeAllViews(); 196 197 final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( 198 Context.LAYOUT_INFLATER_SERVICE); 199 final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext); 200 int numRawContacts = mState.size(); 201 202 for (int i = 0; i < numRawContacts; i++) { 203 // TODO ensure proper ordering of entities in the list 204 final RawContactDelta rawContactDelta = mState.get(i); 205 if (!rawContactDelta.isVisible()) continue; 206 207 final AccountType type = rawContactDelta.getAccountType(accountTypes); 208 final long rawContactId = rawContactDelta.getRawContactId(); 209 210 final BaseRawContactEditorView editor; 211 if (!type.areContactsWritable()) { 212 editor = (BaseRawContactEditorView) inflater.inflate( 213 R.layout.raw_contact_readonly_editor_view, mContent, false); 214 } else { 215 editor = (RawContactEditorView) inflater.inflate(R.layout.raw_contact_editor_view, 216 mContent, false); 217 } 218 editor.setListener(this); 219 final List<AccountWithDataSet> accounts = AccountTypeManager.getInstance(mContext) 220 .getAccounts(true); 221 if (mHasNewContact && !mNewLocalProfile && accounts.size() > 1) { 222 addAccountSwitcher(mState.get(0), editor); 223 } 224 225 editor.setEnabled(isEnabled()); 226 227 if (mExpandedEditors.containsKey(rawContactId)) { 228 editor.setCollapsed(mExpandedEditors.get(rawContactId)); 229 } else { 230 // By default, only the first editor will be expanded. 231 editor.setCollapsed(i != 0); 232 } 233 234 mContent.addView(editor); 235 236 editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile()); 237 editor.setCollapsible(numRawContacts > 1); 238 239 // Set up the photo handler. 240 bindPhotoHandler(editor, type, mState); 241 242 // If a new photo was chosen but not yet saved, we need to update the UI to 243 // reflect this. 244 final Uri photoUri = updatedPhotoUriForRawContact(rawContactId); 245 if (photoUri != null) editor.setFullSizedPhoto(photoUri); 246 247 if (editor instanceof RawContactEditorView) { 248 final Activity activity = getActivity(); 249 final RawContactEditorView rawContactEditor = (RawContactEditorView) editor; 250 EditorListener listener = new EditorListener() { 251 252 @Override 253 public void onRequest(int request) { 254 if (activity.isFinishing()) { // Make sure activity is still running. 255 return; 256 } 257 if (request == EditorListener.FIELD_CHANGED && !isEditingUserProfile()) { 258 acquireAggregationSuggestions(activity, rawContactEditor); 259 } else if (request == EditorListener.EDITOR_FOCUS_CHANGED) { 260 adjustNameFieldsHintDarkness(rawContactEditor); 261 } 262 } 263 264 @Override 265 public void onDeleteRequested(Editor removedEditor) { 266 } 267 }; 268 269 final StructuredNameEditorView nameEditor = rawContactEditor.getNameEditor(); 270 if (mRequestFocus) { 271 nameEditor.requestFocus(); 272 mRequestFocus = false; 273 } 274 nameEditor.setEditorListener(listener); 275 if (!TextUtils.isEmpty(mDefaultDisplayName)) { 276 nameEditor.setDisplayName(mDefaultDisplayName); 277 } 278 279 final TextFieldsEditorView phoneticNameEditor = 280 rawContactEditor.getPhoneticNameEditor(); 281 phoneticNameEditor.setEditorListener(listener); 282 rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup); 283 284 final TextFieldsEditorView nickNameEditor = 285 rawContactEditor.getNickNameEditor(); 286 nickNameEditor.setEditorListener(listener); 287 288 if (isAggregationSuggestionRawContactId(rawContactId)) { 289 acquireAggregationSuggestions(activity, rawContactEditor); 290 } 291 292 adjustNameFieldsHintDarkness(rawContactEditor); 293 } 294 } 295 296 mRequestFocus = false; 297 298 setGroupMetaData(); 299 300 // Show editor now that we've loaded state 301 mContent.setVisibility(View.VISIBLE); 302 303 // Refresh Action Bar as the visibility of the join command 304 // Activity can be null if we have been detached from the Activity 305 invalidateOptionsMenu(); 306 307 updatedExpandedEditorsMap(); 308 } 309 310 /** 311 * Adjust how dark the hint text should be on all the names' text fields. 312 * 313 * @param rawContactEditor editor to update 314 */ 315 private void adjustNameFieldsHintDarkness(RawContactEditorView rawContactEditor) { 316 // Check whether fields contain focus by calling findFocus() instead of hasFocus(). 317 // The hasFocus() value is not necessarily up to date. 318 final boolean nameFieldsAreNotFocused 319 = rawContactEditor.getNameEditor().findFocus() == null 320 && rawContactEditor.getPhoneticNameEditor().findFocus() == null 321 && rawContactEditor.getNickNameEditor().findFocus() == null; 322 rawContactEditor.getNameEditor().setHintColorDark(!nameFieldsAreNotFocused); 323 rawContactEditor.getPhoneticNameEditor().setHintColorDark(!nameFieldsAreNotFocused); 324 rawContactEditor.getNickNameEditor().setHintColorDark(!nameFieldsAreNotFocused); 325 } 326 327 /** 328 * Update the values in {@link #mExpandedEditors}. 329 */ 330 private void updatedExpandedEditorsMap() { 331 for (int i = 0; i < mContent.getChildCount(); i++) { 332 final View childView = mContent.getChildAt(i); 333 if (childView instanceof BaseRawContactEditorView) { 334 BaseRawContactEditorView childEditor = (BaseRawContactEditorView) childView; 335 mExpandedEditors.put(childEditor.getRawContactId(), childEditor.isCollapsed()); 336 } 337 } 338 } 339 340 /** 341 * If we've stashed a temporary file containing a contact's new photo, return its URI. 342 * @param rawContactId identifies the raw-contact whose Bitmap we'll try to return. 343 * @return Uru of photo for specified raw-contact, or null 344 */ 345 private Uri updatedPhotoUriForRawContact(long rawContactId) { 346 return (Uri) mUpdatedPhotos.get(String.valueOf(rawContactId)); 347 } 348 349 private void bindPhotoHandler(BaseRawContactEditorView editor, AccountType type, 350 RawContactDeltaList state) { 351 final int mode; 352 final boolean showIsPrimaryOption; 353 if (type.areContactsWritable()) { 354 if (editor.hasSetPhoto()) { 355 mode = PhotoActionPopup.Modes.WRITE_ABLE_PHOTO; 356 showIsPrimaryOption = hasMoreThanOnePhoto(); 357 } else { 358 mode = PhotoActionPopup.Modes.NO_PHOTO; 359 showIsPrimaryOption = false; 360 } 361 } else if (editor.hasSetPhoto() && hasMoreThanOnePhoto()) { 362 mode = PhotoActionPopup.Modes.READ_ONLY_PHOTO; 363 showIsPrimaryOption = true; 364 } else { 365 // Read-only and either no photo or the only photo ==> no options 366 editor.getPhotoEditor().setEditorListener(null); 367 editor.getPhotoEditor().setShowPrimary(false); 368 return; 369 } 370 final PhotoHandler photoHandler = new PhotoHandler(mContext, editor, mode, state); 371 editor.getPhotoEditor().setEditorListener( 372 (PhotoHandler.PhotoEditorListener) photoHandler.getListener()); 373 editor.getPhotoEditor().setShowPrimary(showIsPrimaryOption); 374 375 // Note a newly created raw contact gets some random negative ID, so any value is valid 376 // here. (i.e. don't check against -1 or anything.) 377 if (mRawContactIdRequestingPhoto == editor.getRawContactId()) { 378 mCurrentPhotoHandler = photoHandler; 379 } 380 } 381 382 private void saveDefaultAccountIfNecessary() { 383 // Verify that this is a newly created contact, that the contact is composed of only 384 // 1 raw contact, and that the contact is not a user profile. 385 if (!Intent.ACTION_INSERT.equals(mAction) && mState.size() == 1 && 386 !isEditingUserProfile()) { 387 return; 388 } 389 390 // Find the associated account for this contact (retrieve it here because there are 391 // multiple paths to creating a contact and this ensures we always have the correct 392 // account). 393 final RawContactDelta rawContactDelta = mState.get(0); 394 String name = rawContactDelta.getAccountName(); 395 String type = rawContactDelta.getAccountType(); 396 String dataSet = rawContactDelta.getDataSet(); 397 398 AccountWithDataSet account = (name == null || type == null) ? null : 399 new AccountWithDataSet(name, type, dataSet); 400 mEditorUtils.saveDefaultAndAllAccounts(account); 401 } 402 403 private void addAccountSwitcher( 404 final RawContactDelta currentState, BaseRawContactEditorView editor) { 405 final AccountWithDataSet currentAccount = new AccountWithDataSet( 406 currentState.getAccountName(), 407 currentState.getAccountType(), 408 currentState.getDataSet()); 409 final View accountView = editor.findViewById(R.id.account); 410 final View anchorView = editor.findViewById(R.id.account_selector_container); 411 if (accountView == null) { 412 return; 413 } 414 anchorView.setVisibility(View.VISIBLE); 415 accountView.setOnClickListener(new View.OnClickListener() { 416 @Override 417 public void onClick(View v) { 418 final ListPopupWindow popup = new ListPopupWindow(mContext, null); 419 final AccountsListAdapter adapter = 420 new AccountsListAdapter(mContext, 421 AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, currentAccount); 422 popup.setWidth(anchorView.getWidth()); 423 popup.setAnchorView(anchorView); 424 popup.setAdapter(adapter); 425 popup.setModal(true); 426 popup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED); 427 popup.setOnItemClickListener(new AdapterView.OnItemClickListener() { 428 @Override 429 public void onItemClick(AdapterView<?> parent, View view, int position, 430 long id) { 431 UiClosables.closeQuietly(popup); 432 AccountWithDataSet newAccount = adapter.getItem(position); 433 if (!newAccount.equals(currentAccount)) { 434 rebindEditorsForNewContact(currentState, currentAccount, newAccount); 435 } 436 } 437 }); 438 popup.show(); 439 } 440 }); 441 } 442 443 @Override 444 protected boolean doSaveAction(int saveMode) { 445 // Store account as default account, only if this is a new contact 446 saveDefaultAccountIfNecessary(); 447 448 // Save contact 449 Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState, 450 SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(), 451 ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED, 452 mUpdatedPhotos); 453 mContext.startService(intent); 454 455 // Don't try to save the same photos twice. 456 mUpdatedPhotos = new Bundle(); 457 458 return true; 459 } 460 461 @Override 462 public void onSaveInstanceState(Bundle outState) { 463 outState.putSerializable(KEY_EXPANDED_EDITORS, mExpandedEditors); 464 outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto); 465 outState.putParcelable(KEY_CURRENT_PHOTO_URI, mCurrentPhotoUri); 466 outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos); 467 super.onSaveInstanceState(outState); 468 } 469 470 @Override 471 public void onActivityResult(int requestCode, int resultCode, Intent data) { 472 if (mStatus == Status.SUB_ACTIVITY) { 473 mStatus = Status.EDITING; 474 } 475 476 // See if the photo selection handler handles this result. 477 if (mCurrentPhotoHandler != null && mCurrentPhotoHandler.handlePhotoActivityResult( 478 requestCode, resultCode, data)) { 479 return; 480 } 481 482 super.onActivityResult(requestCode, resultCode, data); 483 } 484 485 /** 486 * Sets the photo stored in mPhoto and writes it to the RawContact with the given id 487 */ 488 private void setPhoto(long rawContact, Bitmap photo, Uri photoUri) { 489 BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact); 490 491 if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) { 492 // This is unexpected. 493 Log.w(TAG, "Invalid bitmap passed to setPhoto()"); 494 } 495 496 if (requestingEditor != null) { 497 requestingEditor.setPhotoEntry(photo); 498 // Immediately set all other photos as non-primary. Otherwise the UI can display 499 // multiple photos as "Primary photo". 500 for (int i = 0; i < mContent.getChildCount(); i++) { 501 final View childView = mContent.getChildAt(i); 502 if (childView instanceof BaseRawContactEditorView 503 && childView != requestingEditor) { 504 final BaseRawContactEditorView rawContactEditor 505 = (BaseRawContactEditorView) childView; 506 rawContactEditor.getPhotoEditor().setSuperPrimary(false); 507 } 508 } 509 } else { 510 Log.w(TAG, "The contact that requested the photo is no longer present."); 511 } 512 513 mUpdatedPhotos.putParcelable(String.valueOf(rawContact), photoUri); 514 } 515 516 /** 517 * Finds raw contact editor view for the given rawContactId. 518 */ 519 public BaseRawContactEditorView getRawContactEditorView(long rawContactId) { 520 for (int i = 0; i < mContent.getChildCount(); i++) { 521 final View childView = mContent.getChildAt(i); 522 if (childView instanceof BaseRawContactEditorView) { 523 final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView; 524 if (editor.getRawContactId() == rawContactId) { 525 return editor; 526 } 527 } 528 } 529 return null; 530 } 531 532 /** 533 * Returns true if there is currently more than one photo on screen. 534 */ 535 private boolean hasMoreThanOnePhoto() { 536 int countWithPicture = 0; 537 final int numEntities = mState.size(); 538 for (int i = 0; i < numEntities; i++) { 539 final RawContactDelta entity = mState.get(i); 540 if (entity.isVisible()) { 541 final ValuesDelta primary = entity.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE); 542 if (primary != null && primary.getPhoto() != null) { 543 countWithPicture++; 544 } else { 545 final long rawContactId = entity.getRawContactId(); 546 final Uri uri = mUpdatedPhotos.getParcelable(String.valueOf(rawContactId)); 547 if (uri != null) { 548 try { 549 mContext.getContentResolver().openInputStream(uri); 550 countWithPicture++; 551 } catch (FileNotFoundException e) { 552 } 553 } 554 } 555 556 if (countWithPicture > 1) { 557 return true; 558 } 559 } 560 } 561 return false; 562 } 563 564 /** 565 * Custom photo handler for the editor. The inner listener that this creates also has a 566 * reference to the editor and acts as an {@link EditorListener}, and uses that editor to hold 567 * state information in several of the listener methods. 568 */ 569 private final class PhotoHandler extends PhotoSelectionHandler { 570 571 final long mRawContactId; 572 private final BaseRawContactEditorView mEditor; 573 private final PhotoActionListener mPhotoEditorListener; 574 575 public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode, 576 RawContactDeltaList state) { 577 super(context, editor.getPhotoEditor().getChangeAnchorView(), photoMode, false, state); 578 mEditor = editor; 579 mRawContactId = editor.getRawContactId(); 580 mPhotoEditorListener = new PhotoEditorListener(); 581 } 582 583 @Override 584 public PhotoActionListener getListener() { 585 return mPhotoEditorListener; 586 } 587 588 @Override 589 public void startPhotoActivity(Intent intent, int requestCode, Uri photoUri) { 590 mRawContactIdRequestingPhoto = mEditor.getRawContactId(); 591 mCurrentPhotoHandler = this; 592 mStatus = Status.SUB_ACTIVITY; 593 mCurrentPhotoUri = photoUri; 594 ContactEditorFragment.this.startActivityForResult(intent, requestCode); 595 } 596 597 private final class PhotoEditorListener extends PhotoSelectionHandler.PhotoActionListener 598 implements EditorListener { 599 600 @Override 601 public void onRequest(int request) { 602 if (!hasValidState()) return; 603 604 if (request == EditorListener.REQUEST_PICK_PHOTO) { 605 onClick(mEditor.getPhotoEditor()); 606 } 607 if (request == EditorListener.REQUEST_PICK_PRIMARY_PHOTO) { 608 useAsPrimaryChosen(); 609 } 610 } 611 612 @Override 613 public void onDeleteRequested(Editor removedEditor) { 614 // The picture cannot be deleted, it can only be removed, which is handled by 615 // onRemovePictureChosen() 616 } 617 618 /** 619 * User has chosen to set the selected photo as the (super) primary photo 620 */ 621 public void useAsPrimaryChosen() { 622 // Set the IsSuperPrimary for each editor 623 int count = mContent.getChildCount(); 624 for (int i = 0; i < count; i++) { 625 final View childView = mContent.getChildAt(i); 626 if (childView instanceof BaseRawContactEditorView) { 627 final BaseRawContactEditorView editor = 628 (BaseRawContactEditorView) childView; 629 final PhotoEditorView photoEditor = editor.getPhotoEditor(); 630 photoEditor.setSuperPrimary(editor == mEditor); 631 } 632 } 633 bindEditors(); 634 } 635 636 /** 637 * User has chosen to remove a picture 638 */ 639 @Override 640 public void onRemovePictureChosen() { 641 mEditor.setPhotoEntry(null); 642 643 // Prevent bitmap from being restored if rotate the device. 644 // (only if we first chose a new photo before removing it) 645 mUpdatedPhotos.remove(String.valueOf(mRawContactId)); 646 bindEditors(); 647 } 648 649 @Override 650 public void onPhotoSelected(Uri uri) throws FileNotFoundException { 651 final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(mContext, uri); 652 setPhoto(mRawContactId, bitmap, uri); 653 mCurrentPhotoHandler = null; 654 bindEditors(); 655 } 656 657 @Override 658 public Uri getCurrentPhotoUri() { 659 return mCurrentPhotoUri; 660 } 661 662 @Override 663 public void onPhotoSelectionDismissed() { 664 // Nothing to do. 665 } 666 } 667 } 668} 669