• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.editor;
18 
19 import com.android.contacts.ContactSaveService;
20 import com.android.contacts.R;
21 import com.android.contacts.activities.CompactContactEditorActivity;
22 import com.android.contacts.common.model.RawContactDelta;
23 import com.android.contacts.common.model.ValuesDelta;
24 import com.android.contacts.common.model.account.AccountWithDataSet;
25 import com.android.contacts.util.ContactPhotoUtils;
26 
27 import android.app.Activity;
28 import android.content.Intent;
29 import android.graphics.Bitmap;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.text.TextUtils;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.MenuItem;
36 import android.view.View;
37 import android.view.ViewGroup;
38 import android.widget.LinearLayout;
39 import android.widget.Toast;
40 
41 import java.io.FileNotFoundException;
42 import java.util.ArrayList;
43 
44 /**
45  * Contact editor with only the most important fields displayed initially.
46  */
47 public class CompactContactEditorFragment extends ContactEditorBaseFragment implements
48         CompactRawContactsEditorView.Listener, CompactPhotoEditorView.Listener {
49 
50     private static final String KEY_PHOTO_RAW_CONTACT_ID = "photo_raw_contact_id";
51     private static final String KEY_UPDATED_PHOTOS = "updated_photos";
52 
53     private long mPhotoRawContactId;
54     private Bundle mUpdatedPhotos = new Bundle();
55 
56     @Override
onCreate(Bundle savedState)57     public void onCreate(Bundle savedState) {
58         super.onCreate(savedState);
59 
60         if (savedState != null) {
61             mPhotoRawContactId = savedState.getLong(KEY_PHOTO_RAW_CONTACT_ID);
62             mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
63         }
64     }
65 
66     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState)67     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
68         setHasOptionsMenu(true);
69 
70         final View view = inflater.inflate(
71                 R.layout.compact_contact_editor_fragment, container, false);
72         mContent = (LinearLayout) view.findViewById(R.id.raw_contacts_editor_view);
73         return view;
74     }
75 
76     @Override
onSaveInstanceState(Bundle outState)77     public void onSaveInstanceState(Bundle outState) {
78         outState.putLong(KEY_PHOTO_RAW_CONTACT_ID, mPhotoRawContactId);
79         outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
80         super.onSaveInstanceState(outState);
81     }
82 
83     @Override
onOptionsItemSelected(MenuItem item)84     public boolean onOptionsItemSelected(MenuItem item) {
85         if (item.getItemId() == android.R.id.home) {
86             return revert();
87         }
88         return super.onOptionsItemSelected(item);
89     }
90 
91     @Override
bindEditors()92     protected void bindEditors() {
93         if (!isReadyToBindEditors()) {
94             return;
95         }
96 
97         // Add input fields for the loaded Contact
98         final CompactRawContactsEditorView editorView = getContent();
99         editorView.setListener(this);
100         editorView.setState(mState, getMaterialPalette(), mViewIdGenerator, mPhotoId,
101                 mHasNewContact, mIsUserProfile, mAccountWithDataSet);
102         if (mHasNewContact && !TextUtils.isEmpty(mReadOnlyDisplayName)) {
103             mReadOnlyNameEditorView = editorView.getPrimaryNameEditorView();
104             editorView.maybeSetReadOnlyDisplayNameAsPrimary(mReadOnlyDisplayName);
105         }
106 
107         // Set up the photo widget
108         editorView.setPhotoListener(this);
109         mPhotoRawContactId = editorView.getPhotoRawContactId();
110         // If there is an updated full resolution photo apply it now, this will be the case if
111         // the user selects or takes a new photo, then rotates the device.
112         final Uri uri = (Uri) mUpdatedPhotos.get(String.valueOf(mPhotoRawContactId));
113         if (uri != null) {
114             editorView.setFullSizePhoto(uri);
115         }
116 
117         // The editor is ready now so make it visible
118         editorView.setEnabled(isEnabled());
119         editorView.setVisibility(View.VISIBLE);
120 
121         // Refresh the ActionBar as the visibility of the join command
122         // Activity can be null if we have been detached from the Activity.
123         invalidateOptionsMenu();
124     }
125 
isReadyToBindEditors()126     private boolean isReadyToBindEditors() {
127         if (mState.isEmpty()) {
128             if (Log.isLoggable(TAG, Log.VERBOSE)) {
129                 Log.v(TAG, "No data to bind editors");
130             }
131             return false;
132         }
133         if (mIsEdit && !mExistingContactDataReady) {
134             if (Log.isLoggable(TAG, Log.VERBOSE)) {
135                 Log.v(TAG, "Existing contact data is not ready to bind editors.");
136             }
137             return false;
138         }
139         if (mHasNewContact && !mNewContactDataReady) {
140             if (Log.isLoggable(TAG, Log.VERBOSE)) {
141                 Log.v(TAG, "New contact data is not ready to bind editors.");
142             }
143             return false;
144         }
145         return true;
146     }
147 
148     @Override
getAggregationAnchorView(long rawContactId)149     protected View getAggregationAnchorView(long rawContactId) {
150         return getContent().getAggregationAnchorView();
151     }
152 
153     @Override
setGroupMetaData()154     protected void setGroupMetaData() {
155         if (mGroupMetaData != null) {
156             getContent().setGroupMetaData(mGroupMetaData);
157         }
158     }
159 
160     @Override
doSaveAction(int saveMode, Long joinContactId)161     protected boolean doSaveAction(int saveMode, Long joinContactId) {
162         final Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
163                 SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
164                 ((Activity) mContext).getClass(),
165                 CompactContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos,
166                 JOIN_CONTACT_ID_EXTRA_KEY, joinContactId);
167         return startSaveService(mContext, intent, saveMode);
168     }
169 
170     @Override
joinAggregate(final long contactId)171     protected void joinAggregate(final long contactId) {
172         final Intent intent = ContactSaveService.createJoinContactsIntent(
173                 mContext, mContactIdForJoin, contactId, CompactContactEditorActivity.class,
174                 CompactContactEditorActivity.ACTION_JOIN_COMPLETED);
175         mContext.startService(intent);
176     }
177 
removePhoto()178     public void removePhoto() {
179         getContent().removePhoto();
180         mUpdatedPhotos.remove(String.valueOf(mPhotoRawContactId));
181     }
182 
updatePhoto(Uri uri)183     public void updatePhoto(Uri uri) throws FileNotFoundException {
184         final Bitmap bitmap = ContactPhotoUtils.getBitmapFromUri(getActivity(), uri);
185         if (bitmap == null || bitmap.getHeight() <= 0 || bitmap.getWidth() <= 0) {
186             Toast.makeText(mContext, R.string.contactPhotoSavedErrorToast,
187                     Toast.LENGTH_SHORT).show();
188             return;
189         }
190         mUpdatedPhotos.putParcelable(String.valueOf(mPhotoRawContactId), uri);
191         getContent().updatePhoto(uri);
192     }
193 
setPrimaryPhoto(CompactPhotoSelectionFragment.Photo photo)194     public void setPrimaryPhoto(CompactPhotoSelectionFragment.Photo photo) {
195         getContent().setPrimaryPhoto(photo);
196 
197         // Update the photo ID we will try to match when selecting the photo to display
198         mPhotoId = photo.photoId;
199     }
200 
201     @Override
onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta)202     public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta) {
203         final Activity activity = getActivity();
204         if (activity == null || activity.isFinishing()) {
205             return;
206         }
207         acquireAggregationSuggestions(activity, rawContactId, valuesDelta);
208     }
209 
210     @Override
onRebindEditorsForNewContact(RawContactDelta oldState, AccountWithDataSet oldAccount, AccountWithDataSet newAccount)211     public void onRebindEditorsForNewContact(RawContactDelta oldState,
212             AccountWithDataSet oldAccount, AccountWithDataSet newAccount) {
213         mNewContactAccountChanged = true;
214         mAccountWithDataSet = newAccount;
215         rebindEditorsForNewContact(oldState, oldAccount, newAccount);
216     }
217 
218     @Override
onBindEditorsFailed()219     public void onBindEditorsFailed() {
220         final Activity activity = getActivity();
221         if (activity != null && !activity.isFinishing()) {
222             Toast.makeText(activity, R.string.compact_editor_failed_to_load,
223                     Toast.LENGTH_SHORT).show();
224             activity.setResult(Activity.RESULT_CANCELED);
225             activity.finish();
226         }
227     }
228 
229     @Override
onEditorsBound()230     public void onEditorsBound() {
231         getLoaderManager().initLoader(LOADER_GROUPS, null, mGroupsLoaderListener);
232     }
233 
234     @Override
onPhotoEditorViewClicked()235     public void onPhotoEditorViewClicked() {
236         if (isEditingMultipleRawContacts()) {
237             final ArrayList<CompactPhotoSelectionFragment.Photo> photos = getContent().getPhotos();
238             if (photos.size() > 1) {
239                 updatePrimaryForSelection(photos);
240                 // For aggregate contacts, the user may select a new super primary photo from among
241                 // the (non-default) raw contact photos, or source a new photo.
242                 getEditorActivity().selectPhoto(photos, getPhotoMode());
243                 return;
244             }
245         }
246         // For contacts composed of a single writable raw contact, or raw contacts have no more
247         // than 1 photo, clicking the photo view simply opens the source photo dialog
248         getEditorActivity().changePhoto(getPhotoMode());
249     }
250 
251     // This method override photo's primary flag based on photoId and set the photo currently
252     // shown in the editor to be the new primary no matter how many primary photos there are in
253     // the photo picker. This is because the photos returned by "getPhoto" may contain 0, 1,
254     // or 2+ primary photos and when we link contacts in the editor, the photos returned may change.
255     // We need to put check mark on the photo currently shown in editor, so we override "primary".
256     // This doesn't modify anything in the database,so there would be no pending changes.
updatePrimaryForSelection(ArrayList<CompactPhotoSelectionFragment.Photo> photos)257     private void updatePrimaryForSelection(ArrayList<CompactPhotoSelectionFragment.Photo> photos) {
258         for (CompactPhotoSelectionFragment.Photo photo : photos) {
259             if (photo.photoId == mPhotoId) {
260                 photo.primary = true;
261             } else {
262                 photo.primary = false;
263             }
264             updateContentDescription(photo);
265         }
266     }
267 
updateContentDescription(CompactPhotoSelectionFragment.Photo photo)268     private void updateContentDescription(CompactPhotoSelectionFragment.Photo photo) {
269         if (!TextUtils.isEmpty(photo.accountType)) {
270             photo.contentDescription = getResources().getString(photo.primary ?
271                             R.string.photo_view_description_checked :
272                             R.string.photo_view_description_not_checked,
273                     photo.accountType, photo.accountName);
274             photo.contentDescriptionChecked = getResources().getString(
275                     R.string.photo_view_description_checked,
276                     photo.accountType, photo.accountName);
277         } else {
278             photo.contentDescription = getResources().getString(photo.primary ?
279                     R.string.photo_view_description_checked_no_info :
280                     R.string.photo_view_description_not_checked_no_info);
281             photo.contentDescriptionChecked = getResources().getString(
282                     R.string.photo_view_description_checked_no_info);
283         }
284     }
285 
286     @Override
onRawContactSelected(Uri uri, long rawContactId, boolean isReadOnly)287     public void onRawContactSelected(Uri uri, long rawContactId, boolean isReadOnly) {
288         final Activity activity = getActivity();
289         if (activity != null && !activity.isFinishing()) {
290             final Intent intent = EditorIntents.createEditContactIntentForRawContact(
291                     activity, uri, rawContactId, isReadOnly);
292             activity.startActivity(intent);
293         }
294     }
295 
296     @Override
getUpdatedPhotos()297     public Bundle getUpdatedPhotos() {
298         return mUpdatedPhotos;
299     }
300 
getPhotoMode()301     private int getPhotoMode() {
302         if (getContent().isWritablePhotoSet()) {
303             return isEditingMultipleRawContacts()
304                     ? PhotoActionPopup.Modes.MULTIPLE_WRITE_ABLE_PHOTOS
305                     : PhotoActionPopup.Modes.WRITE_ABLE_PHOTO;
306         }
307         return PhotoActionPopup.Modes.NO_PHOTO;
308     }
309 
getEditorActivity()310     private CompactContactEditorActivity getEditorActivity() {
311         return (CompactContactEditorActivity) getActivity();
312     }
313 
getContent()314     private CompactRawContactsEditorView getContent() {
315         return (CompactRawContactsEditorView) mContent;
316     }
317 }
318