Skip to content

Instantly share code, notes, and snippets.

@cutiko
Last active August 24, 2021 10:58
Show Gist options
  • Save cutiko/5502fc0dcddee6a727e0c20177ad43a6 to your computer and use it in GitHub Desktop.
Save cutiko/5502fc0dcddee6a727e0c20177ad43a6 to your computer and use it in GitHub Desktop.
Take photo using camera and gallery selection for Android (please see readme first)

Photos in Android: Camera and Gallery

I have to apologize in advance if this snippet is not thorough enough, it has several issues. By example, creating a new file and using Picasso could be improve, by creating a reduced size version of that file and setting it directly in to the UI.

I strongly recommend to simply use MagicalCamera, is really magical. Read this, then go a head, you can compare.

Also there are a big problems not taking into consideration here. First, this doesnt add the photo in to the gallery. Android gallery must receive an intent of the photo to add it, this is pending for now. And second, the orientation of the photo is not taken in consideration, this is not a minor issue cause there are several disparities in orientation metada across devices.

If you are having problems with getting the full size photo from camera this should help you.

In case you are wondering why is there a PhotoData.java file, it is because orientation changes can reset the variables in the Activity. At first I used to rely on the configChanges being resilient to orientation changes (the Activity attribute in AndroidManfest.xml), but with time, I rather to be safe than sorry. The SharedPreference will include the uri from the photo we need, this way is persistent.

Instructions

  1. In your Activity find the views you will use, in this case a button for the camera intent, another for the gallery, and an ImageView for showing the picture.
  2. There is a second file that handles the data, like file creation and uri from the photo, create it
  3. The camera intent what does is to create a file using the aux class, then pass the uri to the intent and save it using the aux file
  4. When the user is return the onActivityResult method will directly put the photo in the UI cause the uri is saved allready
  5. If the intent is to the gallery, the first thing done in onActivityResult is to get the uri from the selected photo
  6. Then that uri is saved to the method
  7. And the image can be set in the UI
  8. Please dont forget to add the needed permissions in the AndroidManifest.xml (see manifest_tweak.xml file)
  9. And by all means include the configuration for the Activity as shown in the manifest_tweak.xml file
public class ExampleActivity extends AppCompatActivity {
private static final int CAMERA_INTENT = 111;
private static final int GALLERY_INTENT = 222;
private PhotoData photoData;
private ImageView photoPreview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
photoData = new PhotoData(this);
Button photoBtn = (Button) findViewById(R.id.photBtn);
photoBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
takePhoto();
}
});
Button galleryBtn = (Button) findViewById(R.id.galleryBtn);
galleryBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
galleryPhoto();
}
});
//This will be use to set the image
photoPreview = (ImageView) findViewById(R.id.photoPreview);
}
private void takePhoto() {
File photo = null;
try {
photo = photoData.createImageFile();
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
photoData.saveUriPath(Uri.fromFile(photo).getPath());
startActivityForResult(intent, CAMERA_INTENT);
} catch (IOException e) {
//TODO warn the user the photo fail
}
}
private void galleryPhoto() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto, GALLERY_INTENT);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//If the intent to camera or gallery worked then the code is
if (Activity.RESULT_OK == resultCode) {
if (CAMERA_INTENT == requestCode) {
showPhoto();
} else if (data != null && GALLERY_INTENT == requestCode) {
//This first part is for getting the Uri path of the photo
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
// Get the cursor
Cursor cursor = getActivity().getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
// Move to first row
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String imgDecodableString = cursor.getString(columnIndex);
cursor.close();
//Why save this if we are back in the activity, cause we can reuse the method
photoData.saveUriPath(imgDecodableString);
showPhoto();
} else {
//TODO warn the user the operation failed
}
} else {
//TODO warn the user the action was cancelled
}
}
private void showPhoto() {
//To keep this snippet short we are using Picasso
//We have to retrive the photo uri path from our shared prefference memory now
Picasso.with(context)
.load(new File(photoData.getUriPath))
.into(holder.photoImg);
//Creating another File instance is not perfect, it works, but could be improve
}
}
<!-- Permissions -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA"/>
<!-- Activity configuration -->
<activity
android:name="ExampleActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>
public class PhotoData {
/*The reason of this, is pure paranoia, Im not kidding, the configuration changes in the manifest,
* should be enough to the variables not to reset during the go to the camera, take the picture,
* come back to the activity, but some time doesnt work!
* So we at least save the last picture taken here*/
private Context context;
private static final String PHOTO_NAME_PREFIX = "YOUR_APPLICATION_NAME"
private static final String PHOTO_PREFERENCE_NAME = "COMMONLY_THIS_COULD_BE_THE_PACKAGE_NAME"
private static final String PHOTO_KEY = "IMAGE_URI_PATH";
public PhotoData(Context context) {
this.context = context;
}
protected File createImageFile() throws IOException {
// Create an image file
// To get the photo taken you have to pass a Uri from a file, this will create the file
//A standarized name for the photo so every photo taken by your app have it in common, plus the current time in milli second to make unique
String imageFileName = PHOTO_NAME_PREFIX + "_" + String.valueOf(System.currentTimeMillis());
//Getting the device photo directory
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
//This file is temporary, but the way Android works is very ambiguos with temporary files, so it work, is persistent. There is a method for not temporal files you can use it
File image = File.createTempFile(
imageFileName, /*prefix*/
PHOTO_NAME_PREFIX, /*suffix*/
storageDir /*directory*/
);
return image;
}
protected void saveUriPath(String selectedImageUriPath) {
SharedPreferences savePhotoData = context.getSharedPreferences(PHOTO_PREFERENCE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor prefEditor = savePhotoData.edit();
prefEditor.putString(PHOTO_KEY, selectedImageUriPath);
prefEditor.commit();
}
protected String getUriPath() {
SharedPreferences getSelectedImageUriPath = context.getSharedPreferences(PHOTO_PREFERENCE_NAME, Context.MODE_PRIVATE);
return getSelectedImageUriPath.getString(PHOTO_KEY, null);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment