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