Loading src/com/android/contacts/ContactSaveService.java +1 −0 Original line number Diff line number Diff line Loading @@ -506,6 +506,7 @@ public class ContactSaveService extends IntentService { } } finally { outputStream.close(); photoFile.delete(); } } catch (IOException e) { Log.e(TAG, "Failed to write photo: " + photoFile.toString() + " because: " + e); Loading src/com/android/contacts/activities/AttachPhotoActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -80,7 +80,7 @@ public class AttachPhotoActivity extends ContactsActivity { mTempPhotoUri = Uri.parse(icicle.getString(KEY_TEMP_PHOTO_URI)); mTempPhotoFile = new File(mTempPhotoUri.getPath()); } else { mTempPhotoFile = ContactPhotoUtils.generateTempPhotoFile(); mTempPhotoFile = ContactPhotoUtils.generateTempPhotoFile(this); mTempPhotoUri = Uri.fromFile(mTempPhotoFile); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); Loading src/com/android/contacts/activities/PhotoSelectionActivity.java +58 −18 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.contacts.R; import com.android.contacts.detail.PhotoSelectionHandler; import com.android.contacts.editor.PhotoActionPopup; import com.android.contacts.model.EntityDeltaList; import com.android.contacts.util.ContactPhotoUtils; import com.android.contacts.util.SchedulingUtils; import android.animation.Animator; Loading @@ -42,7 +43,6 @@ import android.view.ViewGroup.MarginLayoutParams; import android.widget.FrameLayout.LayoutParams; import android.widget.ImageView; import java.io.File; /** * Popup activity for choosing a contact photo within the Contacts app. Loading @@ -60,6 +60,12 @@ public class PhotoSelectionActivity extends Activity { /** Number of ms for the animation to hide the backdrop on finish. */ private static final int BACKDROP_FADEOUT_DURATION = 100; /** Key used to persist photo-filename (NOT full file-path). */ private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile"; /** Key used to persist whether a sub-activity is currently in progress. */ private static final String KEY_SUB_ACTIVITY_IN_PROGRESS = "subinprogress"; /** Intent extra to get the photo URI. */ public static final String PHOTO_URI = "photo_uri"; Loading Loading @@ -131,15 +137,24 @@ public class PhotoSelectionActivity extends Activity { private boolean mCloseActivityWhenCameBackFromSubActivity; /** * A photo result received by the activity, persisted across activity lifecycle. */ private PendingPhotoResult mPendingPhotoResult; /** * The photo file being interacted with, if any. Saved/restored between activity instances. */ private File mCurrentPhotoFile; private String mCurrentPhotoFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.photoselection_activity); if (savedInstanceState != null) { mCurrentPhotoFile = savedInstanceState.getString(KEY_CURRENT_PHOTO_FILE); mSubActivityInProgress = savedInstanceState.getBoolean(KEY_SUB_ACTIVITY_IN_PROGRESS); } // Pull data out of the intent. final Intent intent = getIntent(); Loading Loading @@ -394,12 +409,20 @@ public class PhotoSelectionActivity extends Activity { BACKDROP_FADEOUT_DURATION).start(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile); outState.putBoolean(KEY_SUB_ACTIVITY_IN_PROGRESS, mSubActivityInProgress); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (mPhotoHandler != null) { mSubActivityInProgress = false; if (mPhotoHandler.handlePhotoActivityResult(requestCode, resultCode, data)) { // Result was handled. We'll get a callback later. // Clear out any pending photo result. mPendingPhotoResult = null; } else { // User cancelled the sub-activity and returning to the photo selection activity. if (mCloseActivityWhenCameBackFromSubActivity) { Loading @@ -410,8 +433,8 @@ public class PhotoSelectionActivity extends Activity { } } } else { // The result comes back before we prepare the handler? This activity won't get // re-created for orientation changes, so this shouldn't happen. // Create a pending photo result to be handled when the photo handler is created. mPendingPhotoResult = new PendingPhotoResult(requestCode, resultCode, data); } } Loading @@ -428,6 +451,11 @@ public class PhotoSelectionActivity extends Activity { mPhotoHandler = new PhotoHandler(this, mPhotoView, mode, mState); if (mPendingPhotoResult != null) { mPhotoHandler.handlePhotoActivityResult(mPendingPhotoResult.mRequestCode, mPendingPhotoResult.mResultCode, mPendingPhotoResult.mData); mPendingPhotoResult = null; } else { // Setting the photo in displayPhoto() resulted in a relayout // request... to avoid jank, wait until this layout has happened. SchedulingUtils.doAfterLayout(mBackdrop, new Runnable() { Loading @@ -437,6 +465,7 @@ public class PhotoSelectionActivity extends Activity { } }); } } private final class PhotoHandler extends PhotoSelectionHandler { private final PhotoActionListener mListener; Loading @@ -454,27 +483,27 @@ public class PhotoSelectionActivity extends Activity { } @Override public void startPhotoActivity(Intent intent, int requestCode, File photoFile) { public void startPhotoActivity(Intent intent, int requestCode, String photoFile) { mSubActivityInProgress = true; mCurrentPhotoFile = photoFile; PhotoSelectionActivity.this.startActivityForResult(intent, requestCode); } private final class PhotoListener extends PhotoActionListener { @Override public void onPhotoSelected(Bitmap bitmap) { EntityDeltaList delta = getDeltaForAttachingPhotoToContact(); long rawContactId = getWritableEntityId(); String filePath = mCurrentPhotoFile.getAbsolutePath(); final String croppedPath = ContactPhotoUtils.pathForCroppedPhoto( PhotoSelectionActivity.this, mCurrentPhotoFile); Intent intent = ContactSaveService.createSaveContactIntent( mContext, delta, "", 0, mIsProfile, null, null, rawContactId, filePath); mContext, delta, "", 0, mIsProfile, null, null, rawContactId, croppedPath); startService(intent); finish(); } @Override public File getCurrentPhotoFile() { public String getCurrentPhotoFile() { return mCurrentPhotoFile; } Loading @@ -486,4 +515,15 @@ public class PhotoSelectionActivity extends Activity { } } } private static class PendingPhotoResult { final private int mRequestCode; final private int mResultCode; final private Intent mData; private PendingPhotoResult(int requestCode, int resultCode, Intent data) { mRequestCode = requestCode; mResultCode = resultCode; mData = data; } } } src/com/android/contacts/detail/PhotoSelectionHandler.java +37 −26 Original line number Diff line number Diff line Loading @@ -115,12 +115,15 @@ public abstract class PhotoSelectionHandler implements OnClickListener { final PhotoActionListener listener = getListener(); if (resultCode == Activity.RESULT_OK) { switch (requestCode) { // Photo was chosen (either new or existing from gallery), and cropped. case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: { Bitmap bitmap = BitmapFactory.decodeFile( listener.getCurrentPhotoFile().getAbsolutePath()); final String path = ContactPhotoUtils.pathForCroppedPhoto( mContext, listener.getCurrentPhotoFile()); Bitmap bitmap = BitmapFactory.decodeFile(path); listener.onPhotoSelected(bitmap); return true; } // Photo was successfully taken, now crop it. case REQUEST_CODE_CAMERA_WITH_DATA: { doCropPhoto(listener.getCurrentPhotoFile()); return true; Loading Loading @@ -183,23 +186,28 @@ public abstract class PhotoSelectionHandler implements OnClickListener { } /** Used by subclasses to delegate to their enclosing Activity or Fragment. */ protected abstract void startPhotoActivity(Intent intent, int requestCode, File photoFile); protected abstract void startPhotoActivity(Intent intent, int requestCode, String photoFile); /** * Sends a newly acquired photo to Gallery for cropping */ private void doCropPhoto(File f) { private void doCropPhoto(String fileName) { try { // Obtain the absolute paths for the newly-taken photo, and the destination // for the soon-to-be-cropped photo. final String newPath = ContactPhotoUtils.pathForNewCameraPhoto(fileName); final String croppedPath = ContactPhotoUtils.pathForCroppedPhoto(mContext, fileName); // Add the image to the media store MediaScannerConnection.scanFile( mContext, new String[] { f.getAbsolutePath() }, new String[] { newPath }, new String[] { null }, null); // Launch gallery to crop the photo final Intent intent = getCropImageIntent(f); startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, f); final Intent intent = getCropImageIntent(newPath, croppedPath); startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, fileName); } catch (Exception e) { Log.e(TAG, "Cannot crop image", e); Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); Loading @@ -212,7 +220,7 @@ public abstract class PhotoSelectionHandler implements OnClickListener { * what should be returned by * {@link PhotoSelectionHandler.PhotoActionListener#getCurrentPhotoFile()}. */ private void startTakePhotoActivity(File photoFile) { private void startTakePhotoActivity(String photoFile) { final Intent intent = getTakePhotoIntent(photoFile); startPhotoActivity(intent, REQUEST_CODE_CAMERA_WITH_DATA, photoFile); } Loading @@ -223,7 +231,7 @@ public abstract class PhotoSelectionHandler implements OnClickListener { * stored by the content-provider. * {@link PhotoSelectionHandler#handlePhotoActivityResult(int, int, Intent)}. */ private void startPickFromGalleryActivity(File photoFile) { private void startPickFromGalleryActivity(String photoFile) { final Intent intent = getPhotoPickIntent(photoFile); startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, photoFile); } Loading @@ -243,41 +251,44 @@ public abstract class PhotoSelectionHandler implements OnClickListener { /** * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap. */ private Intent getPhotoPickIntent(File photoFile) { Uri photoUri = Uri.fromFile(photoFile); Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); private Intent getPhotoPickIntent(String photoFile) { final String croppedPhotoPath = ContactPhotoUtils.pathForCroppedPhoto(mContext, photoFile); final Uri croppedPhotoUri = Uri.fromFile(new File(croppedPhotoPath)); final Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); intent.setType("image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", mPhotoPickSize); intent.putExtra("outputY", mPhotoPickSize); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); intent.putExtra(MediaStore.EXTRA_OUTPUT, croppedPhotoUri); return intent; } /** * Constructs an intent for image cropping. */ private Intent getCropImageIntent(File photoFile) { Uri photoUri = Uri.fromFile(photoFile); private Intent getCropImageIntent(String inputPhotoPath, String croppedPhotoPath) { final Uri inputPhotoUri = Uri.fromFile(new File(inputPhotoPath)); final Uri croppedPhotoUri = Uri.fromFile(new File(croppedPhotoPath)); Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(photoUri, "image/*"); intent.setDataAndType(inputPhotoUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", mPhotoPickSize); intent.putExtra("outputY", mPhotoPickSize); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); intent.putExtra(MediaStore.EXTRA_OUTPUT, croppedPhotoUri); return intent; } /** * Constructs an intent for capturing a photo and storing it in a temporary file. */ public static Intent getTakePhotoIntent(File f) { private static Intent getTakePhotoIntent(String fileName) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); final String newPhotoPath = ContactPhotoUtils.pathForNewCameraPhoto(fileName); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(newPhotoPath))); return intent; } Loading @@ -296,10 +307,10 @@ public abstract class PhotoSelectionHandler implements OnClickListener { public void onTakePhotoChosen() { try { // Launch camera to take photo for selected contact startTakePhotoActivity(ContactPhotoUtils.generateTempPhotoFile()); startTakePhotoActivity(ContactPhotoUtils.generateTempPhotoFileName()); } catch (ActivityNotFoundException e) { Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); Toast.makeText( mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); } } Loading @@ -307,10 +318,10 @@ public abstract class PhotoSelectionHandler implements OnClickListener { public void onPickFromGalleryChosen() { try { // Launch picker to choose photo for selected contact startPickFromGalleryActivity(ContactPhotoUtils.generateTempPhotoFile()); startPickFromGalleryActivity(ContactPhotoUtils.generateTempPhotoFileName()); } catch (ActivityNotFoundException e) { Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); Toast.makeText( mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); } } Loading @@ -325,7 +336,7 @@ public abstract class PhotoSelectionHandler implements OnClickListener { * fragment's responsibility to maintain this in saved state, since this handler instance * will not survive rotation. */ public abstract File getCurrentPhotoFile(); public abstract String getCurrentPhotoFile(); /** * Called when the photo selection dialog is dismissed. Loading src/com/android/contacts/editor/ContactEditorFragment.java +19 −19 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import com.android.contacts.R; import com.android.contacts.activities.ContactEditorAccountsChangedActivity; import com.android.contacts.activities.ContactEditorActivity; import com.android.contacts.activities.JoinContactActivity; import com.android.contacts.activities.PhotoSelectionActivity; import com.android.contacts.detail.PhotoSelectionHandler; import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion; import com.android.contacts.editor.Editor.EditorListener; Loading @@ -35,6 +36,7 @@ import com.android.contacts.model.EntityDeltaList; import com.android.contacts.model.EntityModifier; import com.android.contacts.model.GoogleAccountType; import com.android.contacts.util.AccountsListAdapter; import com.android.contacts.util.ContactPhotoUtils; import com.android.contacts.util.AccountsListAdapter.AccountListFilter; import com.android.contacts.util.HelpUtils; Loading Loading @@ -195,7 +197,7 @@ public class ContactEditorFragment extends Fragment implements private Cursor mGroupMetaData; private File mCurrentPhotoFile; private String mCurrentPhotoFile; private Bundle mUpdatedPhotos = new Bundle(); private Context mContext; Loading Loading @@ -410,10 +412,7 @@ public class ContactEditorFragment extends Fragment implements mRawContactIdRequestingPhoto = savedState.getLong( KEY_RAW_CONTACT_ID_REQUESTING_PHOTO); mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR); String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE); if (fileName != null) { mCurrentPhotoFile = new File(fileName); } mCurrentPhotoFile = savedState.getString(KEY_CURRENT_PHOTO_FILE); mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN); mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN); mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS); Loading Loading @@ -918,10 +917,10 @@ public class ContactEditorFragment extends Fragment implements // help menu depending on whether this is inserting or editing if (Intent.ACTION_INSERT.equals(mAction)) { // inserting HelpUtils.prepareHelpMenuItem(getActivity(), helpMenu, R.string.help_url_people_add); HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add); } else if (Intent.ACTION_EDIT.equals(mAction)) { // editing HelpUtils.prepareHelpMenuItem(getActivity(), helpMenu, R.string.help_url_people_edit); HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit); } else { // something else, so don't show the help menu helpMenu.setVisible(false); Loading Loading @@ -966,7 +965,7 @@ public class ContactEditorFragment extends Fragment implements // If we just started creating a new contact and haven't added any data, it's too // early to do a join if (mState.size() == 1 && mState.get(0).isContactInsert() && !hasPendingChanges()) { Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact, Toast.makeText(mContext, R.string.toast_join_with_empty_contact, Toast.LENGTH_LONG).show(); return true; } Loading Loading @@ -1024,10 +1023,11 @@ public class ContactEditorFragment extends Fragment implements saveDefaultAccountIfNecessary(); // Save contact Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState, SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(), getActivity().getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos); getActivity().startService(intent); Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState, SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(), ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos); mContext.startService(intent); // Don't try to save the same photos twice. mUpdatedPhotos = new Bundle(); Loading Loading @@ -1543,9 +1543,7 @@ public class ContactEditorFragment extends Fragment implements outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto); outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator); if (mCurrentPhotoFile != null) { outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString()); } outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile); outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin); outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin); outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId); Loading Loading @@ -1606,7 +1604,7 @@ public class ContactEditorFragment extends Fragment implements /** * Sets the photo stored in mPhoto and writes it to the RawContact with the given id */ private void setPhoto(long rawContact, Bitmap photo, File photoFile) { private void setPhoto(long rawContact, Bitmap photo, String photoFile) { BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact); if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) { Loading @@ -1620,7 +1618,9 @@ public class ContactEditorFragment extends Fragment implements Log.w(TAG, "The contact that requested the photo is no longer present."); } mUpdatedPhotos.putString(String.valueOf(rawContact), photoFile.getAbsolutePath()); final String croppedPhotoPath = ContactPhotoUtils.pathForCroppedPhoto(mContext, mCurrentPhotoFile); mUpdatedPhotos.putString(String.valueOf(rawContact), croppedPhotoPath); } /** Loading Loading @@ -1757,7 +1757,7 @@ public class ContactEditorFragment extends Fragment implements } @Override public void startPhotoActivity(Intent intent, int requestCode, File photoFile) { public void startPhotoActivity(Intent intent, int requestCode, String photoFile) { mRawContactIdRequestingPhoto = mEditor.getRawContactId(); mStatus = Status.SUB_ACTIVITY; mCurrentPhotoFile = photoFile; Loading Loading @@ -1819,7 +1819,7 @@ public class ContactEditorFragment extends Fragment implements } @Override public File getCurrentPhotoFile() { public String getCurrentPhotoFile() { return mCurrentPhotoFile; } Loading Loading
src/com/android/contacts/ContactSaveService.java +1 −0 Original line number Diff line number Diff line Loading @@ -506,6 +506,7 @@ public class ContactSaveService extends IntentService { } } finally { outputStream.close(); photoFile.delete(); } } catch (IOException e) { Log.e(TAG, "Failed to write photo: " + photoFile.toString() + " because: " + e); Loading
src/com/android/contacts/activities/AttachPhotoActivity.java +1 −1 Original line number Diff line number Diff line Loading @@ -80,7 +80,7 @@ public class AttachPhotoActivity extends ContactsActivity { mTempPhotoUri = Uri.parse(icicle.getString(KEY_TEMP_PHOTO_URI)); mTempPhotoFile = new File(mTempPhotoUri.getPath()); } else { mTempPhotoFile = ContactPhotoUtils.generateTempPhotoFile(); mTempPhotoFile = ContactPhotoUtils.generateTempPhotoFile(this); mTempPhotoUri = Uri.fromFile(mTempPhotoFile); Intent intent = new Intent(Intent.ACTION_GET_CONTENT); Loading
src/com/android/contacts/activities/PhotoSelectionActivity.java +58 −18 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.contacts.R; import com.android.contacts.detail.PhotoSelectionHandler; import com.android.contacts.editor.PhotoActionPopup; import com.android.contacts.model.EntityDeltaList; import com.android.contacts.util.ContactPhotoUtils; import com.android.contacts.util.SchedulingUtils; import android.animation.Animator; Loading @@ -42,7 +43,6 @@ import android.view.ViewGroup.MarginLayoutParams; import android.widget.FrameLayout.LayoutParams; import android.widget.ImageView; import java.io.File; /** * Popup activity for choosing a contact photo within the Contacts app. Loading @@ -60,6 +60,12 @@ public class PhotoSelectionActivity extends Activity { /** Number of ms for the animation to hide the backdrop on finish. */ private static final int BACKDROP_FADEOUT_DURATION = 100; /** Key used to persist photo-filename (NOT full file-path). */ private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile"; /** Key used to persist whether a sub-activity is currently in progress. */ private static final String KEY_SUB_ACTIVITY_IN_PROGRESS = "subinprogress"; /** Intent extra to get the photo URI. */ public static final String PHOTO_URI = "photo_uri"; Loading Loading @@ -131,15 +137,24 @@ public class PhotoSelectionActivity extends Activity { private boolean mCloseActivityWhenCameBackFromSubActivity; /** * A photo result received by the activity, persisted across activity lifecycle. */ private PendingPhotoResult mPendingPhotoResult; /** * The photo file being interacted with, if any. Saved/restored between activity instances. */ private File mCurrentPhotoFile; private String mCurrentPhotoFile; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.photoselection_activity); if (savedInstanceState != null) { mCurrentPhotoFile = savedInstanceState.getString(KEY_CURRENT_PHOTO_FILE); mSubActivityInProgress = savedInstanceState.getBoolean(KEY_SUB_ACTIVITY_IN_PROGRESS); } // Pull data out of the intent. final Intent intent = getIntent(); Loading Loading @@ -394,12 +409,20 @@ public class PhotoSelectionActivity extends Activity { BACKDROP_FADEOUT_DURATION).start(); } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile); outState.putBoolean(KEY_SUB_ACTIVITY_IN_PROGRESS, mSubActivityInProgress); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (mPhotoHandler != null) { mSubActivityInProgress = false; if (mPhotoHandler.handlePhotoActivityResult(requestCode, resultCode, data)) { // Result was handled. We'll get a callback later. // Clear out any pending photo result. mPendingPhotoResult = null; } else { // User cancelled the sub-activity and returning to the photo selection activity. if (mCloseActivityWhenCameBackFromSubActivity) { Loading @@ -410,8 +433,8 @@ public class PhotoSelectionActivity extends Activity { } } } else { // The result comes back before we prepare the handler? This activity won't get // re-created for orientation changes, so this shouldn't happen. // Create a pending photo result to be handled when the photo handler is created. mPendingPhotoResult = new PendingPhotoResult(requestCode, resultCode, data); } } Loading @@ -428,6 +451,11 @@ public class PhotoSelectionActivity extends Activity { mPhotoHandler = new PhotoHandler(this, mPhotoView, mode, mState); if (mPendingPhotoResult != null) { mPhotoHandler.handlePhotoActivityResult(mPendingPhotoResult.mRequestCode, mPendingPhotoResult.mResultCode, mPendingPhotoResult.mData); mPendingPhotoResult = null; } else { // Setting the photo in displayPhoto() resulted in a relayout // request... to avoid jank, wait until this layout has happened. SchedulingUtils.doAfterLayout(mBackdrop, new Runnable() { Loading @@ -437,6 +465,7 @@ public class PhotoSelectionActivity extends Activity { } }); } } private final class PhotoHandler extends PhotoSelectionHandler { private final PhotoActionListener mListener; Loading @@ -454,27 +483,27 @@ public class PhotoSelectionActivity extends Activity { } @Override public void startPhotoActivity(Intent intent, int requestCode, File photoFile) { public void startPhotoActivity(Intent intent, int requestCode, String photoFile) { mSubActivityInProgress = true; mCurrentPhotoFile = photoFile; PhotoSelectionActivity.this.startActivityForResult(intent, requestCode); } private final class PhotoListener extends PhotoActionListener { @Override public void onPhotoSelected(Bitmap bitmap) { EntityDeltaList delta = getDeltaForAttachingPhotoToContact(); long rawContactId = getWritableEntityId(); String filePath = mCurrentPhotoFile.getAbsolutePath(); final String croppedPath = ContactPhotoUtils.pathForCroppedPhoto( PhotoSelectionActivity.this, mCurrentPhotoFile); Intent intent = ContactSaveService.createSaveContactIntent( mContext, delta, "", 0, mIsProfile, null, null, rawContactId, filePath); mContext, delta, "", 0, mIsProfile, null, null, rawContactId, croppedPath); startService(intent); finish(); } @Override public File getCurrentPhotoFile() { public String getCurrentPhotoFile() { return mCurrentPhotoFile; } Loading @@ -486,4 +515,15 @@ public class PhotoSelectionActivity extends Activity { } } } private static class PendingPhotoResult { final private int mRequestCode; final private int mResultCode; final private Intent mData; private PendingPhotoResult(int requestCode, int resultCode, Intent data) { mRequestCode = requestCode; mResultCode = resultCode; mData = data; } } }
src/com/android/contacts/detail/PhotoSelectionHandler.java +37 −26 Original line number Diff line number Diff line Loading @@ -115,12 +115,15 @@ public abstract class PhotoSelectionHandler implements OnClickListener { final PhotoActionListener listener = getListener(); if (resultCode == Activity.RESULT_OK) { switch (requestCode) { // Photo was chosen (either new or existing from gallery), and cropped. case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: { Bitmap bitmap = BitmapFactory.decodeFile( listener.getCurrentPhotoFile().getAbsolutePath()); final String path = ContactPhotoUtils.pathForCroppedPhoto( mContext, listener.getCurrentPhotoFile()); Bitmap bitmap = BitmapFactory.decodeFile(path); listener.onPhotoSelected(bitmap); return true; } // Photo was successfully taken, now crop it. case REQUEST_CODE_CAMERA_WITH_DATA: { doCropPhoto(listener.getCurrentPhotoFile()); return true; Loading Loading @@ -183,23 +186,28 @@ public abstract class PhotoSelectionHandler implements OnClickListener { } /** Used by subclasses to delegate to their enclosing Activity or Fragment. */ protected abstract void startPhotoActivity(Intent intent, int requestCode, File photoFile); protected abstract void startPhotoActivity(Intent intent, int requestCode, String photoFile); /** * Sends a newly acquired photo to Gallery for cropping */ private void doCropPhoto(File f) { private void doCropPhoto(String fileName) { try { // Obtain the absolute paths for the newly-taken photo, and the destination // for the soon-to-be-cropped photo. final String newPath = ContactPhotoUtils.pathForNewCameraPhoto(fileName); final String croppedPath = ContactPhotoUtils.pathForCroppedPhoto(mContext, fileName); // Add the image to the media store MediaScannerConnection.scanFile( mContext, new String[] { f.getAbsolutePath() }, new String[] { newPath }, new String[] { null }, null); // Launch gallery to crop the photo final Intent intent = getCropImageIntent(f); startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, f); final Intent intent = getCropImageIntent(newPath, croppedPath); startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, fileName); } catch (Exception e) { Log.e(TAG, "Cannot crop image", e); Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); Loading @@ -212,7 +220,7 @@ public abstract class PhotoSelectionHandler implements OnClickListener { * what should be returned by * {@link PhotoSelectionHandler.PhotoActionListener#getCurrentPhotoFile()}. */ private void startTakePhotoActivity(File photoFile) { private void startTakePhotoActivity(String photoFile) { final Intent intent = getTakePhotoIntent(photoFile); startPhotoActivity(intent, REQUEST_CODE_CAMERA_WITH_DATA, photoFile); } Loading @@ -223,7 +231,7 @@ public abstract class PhotoSelectionHandler implements OnClickListener { * stored by the content-provider. * {@link PhotoSelectionHandler#handlePhotoActivityResult(int, int, Intent)}. */ private void startPickFromGalleryActivity(File photoFile) { private void startPickFromGalleryActivity(String photoFile) { final Intent intent = getPhotoPickIntent(photoFile); startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, photoFile); } Loading @@ -243,41 +251,44 @@ public abstract class PhotoSelectionHandler implements OnClickListener { /** * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap. */ private Intent getPhotoPickIntent(File photoFile) { Uri photoUri = Uri.fromFile(photoFile); Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); private Intent getPhotoPickIntent(String photoFile) { final String croppedPhotoPath = ContactPhotoUtils.pathForCroppedPhoto(mContext, photoFile); final Uri croppedPhotoUri = Uri.fromFile(new File(croppedPhotoPath)); final Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); intent.setType("image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", mPhotoPickSize); intent.putExtra("outputY", mPhotoPickSize); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); intent.putExtra(MediaStore.EXTRA_OUTPUT, croppedPhotoUri); return intent; } /** * Constructs an intent for image cropping. */ private Intent getCropImageIntent(File photoFile) { Uri photoUri = Uri.fromFile(photoFile); private Intent getCropImageIntent(String inputPhotoPath, String croppedPhotoPath) { final Uri inputPhotoUri = Uri.fromFile(new File(inputPhotoPath)); final Uri croppedPhotoUri = Uri.fromFile(new File(croppedPhotoPath)); Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(photoUri, "image/*"); intent.setDataAndType(inputPhotoUri, "image/*"); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", mPhotoPickSize); intent.putExtra("outputY", mPhotoPickSize); intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); intent.putExtra(MediaStore.EXTRA_OUTPUT, croppedPhotoUri); return intent; } /** * Constructs an intent for capturing a photo and storing it in a temporary file. */ public static Intent getTakePhotoIntent(File f) { private static Intent getTakePhotoIntent(String fileName) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); final String newPhotoPath = ContactPhotoUtils.pathForNewCameraPhoto(fileName); intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(newPhotoPath))); return intent; } Loading @@ -296,10 +307,10 @@ public abstract class PhotoSelectionHandler implements OnClickListener { public void onTakePhotoChosen() { try { // Launch camera to take photo for selected contact startTakePhotoActivity(ContactPhotoUtils.generateTempPhotoFile()); startTakePhotoActivity(ContactPhotoUtils.generateTempPhotoFileName()); } catch (ActivityNotFoundException e) { Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); Toast.makeText( mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); } } Loading @@ -307,10 +318,10 @@ public abstract class PhotoSelectionHandler implements OnClickListener { public void onPickFromGalleryChosen() { try { // Launch picker to choose photo for selected contact startPickFromGalleryActivity(ContactPhotoUtils.generateTempPhotoFile()); startPickFromGalleryActivity(ContactPhotoUtils.generateTempPhotoFileName()); } catch (ActivityNotFoundException e) { Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); Toast.makeText( mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); } } Loading @@ -325,7 +336,7 @@ public abstract class PhotoSelectionHandler implements OnClickListener { * fragment's responsibility to maintain this in saved state, since this handler instance * will not survive rotation. */ public abstract File getCurrentPhotoFile(); public abstract String getCurrentPhotoFile(); /** * Called when the photo selection dialog is dismissed. Loading
src/com/android/contacts/editor/ContactEditorFragment.java +19 −19 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import com.android.contacts.R; import com.android.contacts.activities.ContactEditorAccountsChangedActivity; import com.android.contacts.activities.ContactEditorActivity; import com.android.contacts.activities.JoinContactActivity; import com.android.contacts.activities.PhotoSelectionActivity; import com.android.contacts.detail.PhotoSelectionHandler; import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion; import com.android.contacts.editor.Editor.EditorListener; Loading @@ -35,6 +36,7 @@ import com.android.contacts.model.EntityDeltaList; import com.android.contacts.model.EntityModifier; import com.android.contacts.model.GoogleAccountType; import com.android.contacts.util.AccountsListAdapter; import com.android.contacts.util.ContactPhotoUtils; import com.android.contacts.util.AccountsListAdapter.AccountListFilter; import com.android.contacts.util.HelpUtils; Loading Loading @@ -195,7 +197,7 @@ public class ContactEditorFragment extends Fragment implements private Cursor mGroupMetaData; private File mCurrentPhotoFile; private String mCurrentPhotoFile; private Bundle mUpdatedPhotos = new Bundle(); private Context mContext; Loading Loading @@ -410,10 +412,7 @@ public class ContactEditorFragment extends Fragment implements mRawContactIdRequestingPhoto = savedState.getLong( KEY_RAW_CONTACT_ID_REQUESTING_PHOTO); mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR); String fileName = savedState.getString(KEY_CURRENT_PHOTO_FILE); if (fileName != null) { mCurrentPhotoFile = new File(fileName); } mCurrentPhotoFile = savedState.getString(KEY_CURRENT_PHOTO_FILE); mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN); mContactWritableForJoin = savedState.getBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN); mAggregationSuggestionsRawContactId = savedState.getLong(KEY_SHOW_JOIN_SUGGESTIONS); Loading Loading @@ -918,10 +917,10 @@ public class ContactEditorFragment extends Fragment implements // help menu depending on whether this is inserting or editing if (Intent.ACTION_INSERT.equals(mAction)) { // inserting HelpUtils.prepareHelpMenuItem(getActivity(), helpMenu, R.string.help_url_people_add); HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add); } else if (Intent.ACTION_EDIT.equals(mAction)) { // editing HelpUtils.prepareHelpMenuItem(getActivity(), helpMenu, R.string.help_url_people_edit); HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit); } else { // something else, so don't show the help menu helpMenu.setVisible(false); Loading Loading @@ -966,7 +965,7 @@ public class ContactEditorFragment extends Fragment implements // If we just started creating a new contact and haven't added any data, it's too // early to do a join if (mState.size() == 1 && mState.get(0).isContactInsert() && !hasPendingChanges()) { Toast.makeText(getActivity(), R.string.toast_join_with_empty_contact, Toast.makeText(mContext, R.string.toast_join_with_empty_contact, Toast.LENGTH_LONG).show(); return true; } Loading Loading @@ -1024,10 +1023,11 @@ public class ContactEditorFragment extends Fragment implements saveDefaultAccountIfNecessary(); // Save contact Intent intent = ContactSaveService.createSaveContactIntent(getActivity(), mState, SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(), getActivity().getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos); getActivity().startService(intent); Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState, SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(), ((Activity)mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos); mContext.startService(intent); // Don't try to save the same photos twice. mUpdatedPhotos = new Bundle(); Loading Loading @@ -1543,9 +1543,7 @@ public class ContactEditorFragment extends Fragment implements outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto); outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator); if (mCurrentPhotoFile != null) { outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile.toString()); } outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile); outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin); outState.putBoolean(KEY_CONTACT_WRITABLE_FOR_JOIN, mContactWritableForJoin); outState.putLong(KEY_SHOW_JOIN_SUGGESTIONS, mAggregationSuggestionsRawContactId); Loading Loading @@ -1606,7 +1604,7 @@ public class ContactEditorFragment extends Fragment implements /** * Sets the photo stored in mPhoto and writes it to the RawContact with the given id */ private void setPhoto(long rawContact, Bitmap photo, File photoFile) { private void setPhoto(long rawContact, Bitmap photo, String photoFile) { BaseRawContactEditorView requestingEditor = getRawContactEditorView(rawContact); if (photo == null || photo.getHeight() < 0 || photo.getWidth() < 0) { Loading @@ -1620,7 +1618,9 @@ public class ContactEditorFragment extends Fragment implements Log.w(TAG, "The contact that requested the photo is no longer present."); } mUpdatedPhotos.putString(String.valueOf(rawContact), photoFile.getAbsolutePath()); final String croppedPhotoPath = ContactPhotoUtils.pathForCroppedPhoto(mContext, mCurrentPhotoFile); mUpdatedPhotos.putString(String.valueOf(rawContact), croppedPhotoPath); } /** Loading Loading @@ -1757,7 +1757,7 @@ public class ContactEditorFragment extends Fragment implements } @Override public void startPhotoActivity(Intent intent, int requestCode, File photoFile) { public void startPhotoActivity(Intent intent, int requestCode, String photoFile) { mRawContactIdRequestingPhoto = mEditor.getRawContactId(); mStatus = Status.SUB_ACTIVITY; mCurrentPhotoFile = photoFile; Loading Loading @@ -1819,7 +1819,7 @@ public class ContactEditorFragment extends Fragment implements } @Override public File getCurrentPhotoFile() { public String getCurrentPhotoFile() { return mCurrentPhotoFile; } Loading