PhotoSelectionHandler.java revision e5d3f897689c8ba0f275c7679c72eacb190ae9b8
16fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro/* 26fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Copyright (C) 2011 The Android Open Source Project 36fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * 46fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Licensed under the Apache License, Version 2.0 (the "License"); 56fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * you may not use this file except in compliance with the License. 66fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * You may obtain a copy of the License at 76fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * 86fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * http://www.apache.org/licenses/LICENSE-2.0 96fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * 106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Unless required by applicable law or agreed to in writing, software 116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * distributed under the License is distributed on an "AS IS" BASIS, 126fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * See the License for the specific language governing permissions and 146fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * limitations under the License. 156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 166fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 176fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoropackage com.android.contacts.detail; 186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 196fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.R; 206fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.editor.PhotoActionPopup; 216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.model.AccountType; 226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.model.EntityDelta; 236fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.model.EntityDelta.ValuesDelta; 246fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.model.EntityDeltaList; 256fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport com.android.contacts.model.EntityModifier; 26e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargusimport com.android.contacts.util.ContactPhotoUtils; 276fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 286fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.app.Activity; 296fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.content.ActivityNotFoundException; 306fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.content.Context; 316fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.content.Intent; 326fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.database.Cursor; 336fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.graphics.Bitmap; 34e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargusimport android.graphics.BitmapFactory; 356fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.media.MediaScannerConnection; 366fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.net.Uri; 376fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.provider.ContactsContract.CommonDataKinds.Photo; 386fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.provider.ContactsContract.DisplayPhoto; 396fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.provider.MediaStore; 406fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.util.Log; 416fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.view.View; 426fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.view.View.OnClickListener; 436fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.widget.ListPopupWindow; 446fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.widget.PopupWindow.OnDismissListener; 456fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport android.widget.Toast; 466fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoroimport java.io.File; 476fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro/** 496fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Handles displaying a photo selection popup for a given photo view and dealing with the results 506fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * that come back. 516fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 52e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Garguspublic abstract class PhotoSelectionHandler implements OnClickListener { 536fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 546fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private static final String TAG = PhotoSelectionHandler.class.getSimpleName(); 556fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 566fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private static final int REQUEST_CODE_CAMERA_WITH_DATA = 1001; 576fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private static final int REQUEST_CODE_PHOTO_PICKED_WITH_DATA = 1002; 586fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 59e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus protected final Context mContext; 606fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private final View mPhotoView; 616fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private final int mPhotoMode; 626fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private final int mPhotoPickSize; 636fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private final EntityDeltaList mState; 646fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private final boolean mIsDirectoryContact; 656fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private ListPopupWindow mPopup; 666fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private AccountType mWritableAccount; 676fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private PhotoActionListener mListener; 686fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 696fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public PhotoSelectionHandler(Context context, View photoView, int photoMode, 706fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro boolean isDirectoryContact, EntityDeltaList state) { 716fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mContext = context; 726fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPhotoView = photoView; 736fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPhotoMode = photoMode; 746fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mIsDirectoryContact = isDirectoryContact; 756fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mState = state; 766fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPhotoPickSize = getPhotoPickSize(); 77e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus 78e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus // NOTE: subclasses should call setListener() 796fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 806fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void destroy() { 826fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro if (mPopup != null) { 836fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPopup.dismiss(); 846fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 856fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 866fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 87e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus public abstract PhotoActionListener getListener(); 886fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 896fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro @Override 906fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void onClick(View v) { 916fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro if (mListener != null) { 926fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro if (getWritableEntityIndex() != -1) { 936fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPopup = PhotoActionPopup.createPopupMenu( 946fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mContext, mPhotoView, mListener, mPhotoMode); 95e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus final PhotoActionListener listener = mListener; // a bit more bulletproof 966fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPopup.setOnDismissListener(new OnDismissListener() { 976fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro @Override 986fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void onDismiss() { 99e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus listener.onPhotoSelectionDismissed(); 1006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1016fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro }); 1026fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mPopup.show(); 1036fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1046fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1056fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1066fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 1076fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 1086fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Attempts to handle the given activity result. Returns whether this handler was able to 1096fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * process the result successfully. 1106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * @param requestCode The request code. 1116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * @param resultCode The result code. 1126fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * @param data The intent that was returned. 1136fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * @return Whether the handler was able to process the result. 1146fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 1156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public boolean handlePhotoActivityResult(int requestCode, int resultCode, Intent data) { 1166fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro if (resultCode == Activity.RESULT_OK) { 1176fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro switch (requestCode) { 1186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro case REQUEST_CODE_PHOTO_PICKED_WITH_DATA: { 119e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus Bitmap bitmap = BitmapFactory.decodeFile( 120e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus mListener.getCurrentPhotoFile().getAbsolutePath()); 1216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mListener.onPhotoSelected(bitmap); 1226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return true; 1236fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1246fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro case REQUEST_CODE_CAMERA_WITH_DATA: { 1256fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro doCropPhoto(mListener.getCurrentPhotoFile()); 1266fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return true; 1276fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1286fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1296fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1306fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return false; 1316fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1326fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 1336fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 1346fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Return the index of the first entity in the contact data that belongs to a contact-writable 1356fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * account, or -1 if no such entity exists. 1366fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 1376fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private int getWritableEntityIndex() { 1386fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Directory entries are non-writable. 139e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus if (mIsDirectoryContact) return -1; 140e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus return mState.indexOfFirstWritableRawContact(mContext); 1416fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1426fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 1436fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 144e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus * Return the raw-contact id of the first entity in the contact data that belongs to a 145e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus * contact-writable account, or -1 if no such entity exists. 146e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus */ 147e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus protected long getWritableEntityId() { 148e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus int index = getWritableEntityIndex(); 149e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus if (index == -1) return -1; 150e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus return mState.get(index).getValues().getId(); 151e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus } 152e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus 153e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus /** 1546fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Utility method to retrieve the entity delta for attaching the given bitmap to the contact. 1556fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * This will attach the photo to the first contact-writable account that provided data to the 1566fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * contact. It is the caller's responsibility to apply the delta. 1576fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * @return An entity delta list that can be applied to associate the bitmap with the contact, 1586fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * or null if the photo could not be parsed or none of the accounts associated with the 1596fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * contact are writable. 1606fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 161e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus public EntityDeltaList getDeltaForAttachingPhotoToContact() { 1626fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Find the first writable entity. 1636fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro int writableEntityIndex = getWritableEntityIndex(); 1646fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro if (writableEntityIndex != -1) { 1656fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Note - guaranteed to have contact data if we have a writable entity index. 1666fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro EntityDelta delta = mState.get(writableEntityIndex); 1676fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro ValuesDelta child = EntityModifier.ensureKindExists( 1686fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro delta, mWritableAccount, Photo.CONTENT_ITEM_TYPE); 1696fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro child.setFromTemplate(false); 1706fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro child.put(Photo.IS_SUPER_PRIMARY, 1); 1716fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 1726fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return mState; 1736fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1746fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return null; 1756fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1766fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 177e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus /** Used by subclasses to delegate to their enclosing Activity or Fragment. */ 178e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus protected abstract void startPhotoActivity(Intent intent, int requestCode, File photoFile); 179e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus 1806fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 1816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Sends a newly acquired photo to Gallery for cropping 1826fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 1836fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private void doCropPhoto(File f) { 1846fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro try { 1856fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Add the image to the media store 1866fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro MediaScannerConnection.scanFile( 1876fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro mContext, 1886fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro new String[] { f.getAbsolutePath() }, 1896fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro new String[] { null }, 1906fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro null); 1916fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 1926fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Launch gallery to crop the photo 193e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus final Intent intent = getCropImageIntent(f); 194e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, f); 1956fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } catch (Exception e) { 1966fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Log.e(TAG, "Cannot crop image", e); 1976fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Toast.makeText(mContext, R.string.photoPickerNotFoundText, Toast.LENGTH_LONG).show(); 1986fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 1996fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 201e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus /** 202e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * Should initiate an activity to take a photo using the camera. 203e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * @param photoFile The file path that will be used to store the photo. This is generally 204e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * what should be returned by 205e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * {@link PhotoSelectionHandler.PhotoActionListener#getCurrentPhotoFile()}. 206e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus */ 207e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus private void startTakePhotoActivity(File photoFile) { 208e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus final Intent intent = getTakePhotoIntent(photoFile); 209e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus startPhotoActivity(intent, REQUEST_CODE_CAMERA_WITH_DATA, photoFile); 2106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 212e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus /** 213e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * Should initiate an activity pick a photo from the gallery. 214e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * @param photoFile The temporary file that the cropped image is written to before being 215e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * stored by the content-provider. 216e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus * {@link PhotoSelectionHandler#handlePhotoActivityResult(int, int, Intent)}. 217e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus */ 218e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus private void startPickFromGalleryActivity(File photoFile) { 219e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus final Intent intent = getPhotoPickIntent(photoFile); 220e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus startPhotoActivity(intent, REQUEST_CODE_PHOTO_PICKED_WITH_DATA, photoFile); 221e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus } 222e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus 2236fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro private int getPhotoPickSize() { 2246fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Note that this URI is safe to call on the UI thread. 2256fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Cursor c = mContext.getContentResolver().query(DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI, 2266fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null); 2276fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro try { 2286fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro c.moveToFirst(); 2296fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return c.getInt(0); 2306fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } finally { 2316fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro c.close(); 2326fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2336fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2346fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2356fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 2366fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Constructs an intent for picking a photo from Gallery, cropping it and returning the bitmap. 2376fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 238e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus private Intent getPhotoPickIntent(File photoFile) { 239e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus Uri photoUri = Uri.fromFile(photoFile); 2406fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null); 2416fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.setType("image/*"); 2426fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("crop", "true"); 2436fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("aspectX", 1); 2446fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("aspectY", 1); 2456fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("outputX", mPhotoPickSize); 2466fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("outputY", mPhotoPickSize); 247e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); 2486fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return intent; 2496fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2506fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2516fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 2526fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Constructs an intent for image cropping. 2536fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 254e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus private Intent getCropImageIntent(File photoFile) { 255e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus Uri photoUri = Uri.fromFile(photoFile); 2566fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Intent intent = new Intent("com.android.camera.action.CROP"); 2576fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.setDataAndType(photoUri, "image/*"); 2586fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("crop", "true"); 2596fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("aspectX", 1); 2606fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("aspectY", 1); 2616fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("outputX", mPhotoPickSize); 2626fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra("outputY", mPhotoPickSize); 263e692e010ca02200087997280e7c239ebf94aa8f9Josh Gargus intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); 2646fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return intent; 2656fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2666fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2676fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 2686fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Constructs an intent for capturing a photo and storing it in a temporary file. 2696fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 2706fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public static Intent getTakePhotoIntent(File f) { 2716fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null); 2726fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f)); 2736fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro return intent; 2746fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2756fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2766fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public abstract class PhotoActionListener implements PhotoActionPopup.Listener { 2776fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro @Override 2786fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void onUseAsPrimaryChosen() { 2796fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // No default implementation. 2806fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2816fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2826fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro @Override 2836fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void onRemovePictureChosen() { 2846fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // No default implementation. 2856fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2866fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2876fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro @Override 2886fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void onTakePhotoChosen() { 2896fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro try { 2906fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Launch camera to take photo for selected contact 291e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus startTakePhotoActivity(ContactPhotoUtils.generateTempPhotoFile()); 2926fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } catch (ActivityNotFoundException e) { 2936fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Toast.makeText(mContext, R.string.photoPickerNotFoundText, 2946fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Toast.LENGTH_LONG).show(); 2956fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2966fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 2976fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 2986fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro @Override 2996fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public void onPickFromGalleryChosen() { 3006fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro try { 3016fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro // Launch picker to choose photo for selected contact 302e5d3f897689c8ba0f275c7679c72eacb190ae9b8Josh Gargus startPickFromGalleryActivity(ContactPhotoUtils.generateTempPhotoFile()); 3036fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } catch (ActivityNotFoundException e) { 3046fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Toast.makeText(mContext, R.string.photoPickerNotFoundText, 3056fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro Toast.LENGTH_LONG).show(); 3066fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 3076fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 3086fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 3096fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 3106fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Called when the user has completed selection of a photo. 3116fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * @param bitmap The selected and cropped photo. 3126fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 3136fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public abstract void onPhotoSelected(Bitmap bitmap); 3146fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 3156fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 3166fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Gets the current photo file that is being interacted with. It is the activity or 3176fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * fragment's responsibility to maintain this in saved state, since this handler instance 3186fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * will not survive rotation. 3196fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 3206fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public abstract File getCurrentPhotoFile(); 3216fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro 3226fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro /** 3236fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro * Called when the photo selection dialog is dismissed. 3246fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro */ 3256fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro public abstract void onPhotoSelectionDismissed(); 3266fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro } 3276fa7384a1a5576ace18159de61af91c8b7c34dc6Dave Santoro} 328