Skip to content

Instantly share code, notes, and snippets.

@koral--
Last active January 16, 2019 10:57
Show Gist options
  • Save koral--/6173683 to your computer and use it in GitHub Desktop.
Save koral--/6173683 to your computer and use it in GitHub Desktop.
Helper for sending ACTION_IMAGE_CAPTURE intent and retrieve its results. Handles all low level operations
//MIT License
//Copyright (c) 2015 Karol Wrótniak, Droids On Roids
package pl.droidsonroids.imagehelpers;
import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.MediaColumns;
/**
* Helper for sending ACTION_IMAGE_CAPTURE intent and retrieve its results. Handles all low level operations
* <br>
* Usage:<br>
* <ol>
* <li>Launch camera app by calling {@link #launchCameraApp(int, Activity, String)}, save resulting Uri, handle (or ignore) exceptions.</li>
* <li>In your onActivityResult(int requestCode, int resultCode, Intent data) call {@link #retrievePhotoResult(Activity, String) ) }. You may want to inform user if photo cannot be read despite the result is RESULT_OK.</li>
* </ol>
* @author koral--
*
*/
public class ImageCaptureHelper
{
private ImageCaptureHelper ()
{}
private static final String[] PROJECTION = new String[] { MediaColumns.DATA };
private static final ContentValues CONTENT_VALUES = new ContentValues( 1 );
private static final String PHOTO_SHARED_PREFS_NAME = "photo_shared";
private static final String PHOTO_URI = "photo_uri";
/**
* Description text inserted into @link{ImageColumns.DESCRIPTION} column
*/
public static final String DESCRIPTION="Photo taken with example application" ;
static
{
CONTENT_VALUES.put( ImageColumns.DESCRIPTION, DESCRIPTION);
}
/**
* Tries to obtain File containing taken photo. Perform cleanups if photo was not taken or it is empty.
* @param caller caller Activity
* @param photoKey key in Shared Preferences for taken image, can be null
* @return File containing photo or null if no or empty photo was saved by camera app.
*/
public static File retrievePhotoResult ( Activity caller, String photoKey )
{
try
{
if ( photoKey == null )
{
photoKey = PHOTO_URI;
}
SharedPreferences prefs = caller.getSharedPreferences( PHOTO_SHARED_PREFS_NAME, Context.MODE_PRIVATE );
String takenPhotoUriString = prefs.getString( photoKey, null );
prefs.edit().remove( photoKey ).commit();
if ( takenPhotoUriString == null )
{
return null;
}
Uri takenPhotoUri = Uri.parse( takenPhotoUriString );
ContentResolver cr = caller.getContentResolver();
File out = new File( getPhotoFilePath( takenPhotoUri, cr ) );
if ( !out.isFile() || ( out.length() == 0 ) )
{
cr.delete( takenPhotoUri, null, null );
}
else
{
return out;
}
}
catch ( Exception ex )
{
// no-op
}
return null;
}
/**
* Tries to create photo placeholder and launch camera app
* @param requestCode your unique code that will be returned in onActivityResult
* @param caller caller Activity
* @param photoKey key in Shared Preferences for taken image, can be null
* @throws ActivityNotFoundException if no camera app was found
* @throws Exception if there is a problem with create photo eg. SDcard is not mounted. It may be eg. {@link IllegalStateException} or {@link UnsupportedOperationException} depending on {@link ContentResolver}.
*/
public static void launchCameraApp ( int requestCode, Activity caller, String photoKey ) throws ActivityNotFoundException, Exception
{
if ( photoKey == null )
{
photoKey = PHOTO_URI;
}
ContentResolver cr = caller.getContentResolver();
Uri takenPhotoUri = cr.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, CONTENT_VALUES );
if ( takenPhotoUri == null )
{
throw new IllegalStateException( "Photo insertion failed" );
}
Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE );
intent.putExtra( MediaStore.EXTRA_OUTPUT, getIntentUri( takenPhotoUri, cr ) );
caller.startActivityForResult( intent, requestCode );
SharedPreferences prefs = caller.getSharedPreferences( PHOTO_SHARED_PREFS_NAME, Context.MODE_PRIVATE );
prefs.edit().putString( photoKey, takenPhotoUri.toString() ).commit();
}
private static Uri getIntentUri ( Uri takenPhotoUri, ContentResolver cr )
{
String path = getPhotoFilePath( takenPhotoUri, cr );
if ( path == null )
{
throw new IllegalStateException( "Photo resolution failed" );
}
return Uri.fromFile( new File( path ) );
}
private static String getPhotoFilePath ( Uri takenPhotoUri, ContentResolver cr )
{
Cursor cursor = cr.query( takenPhotoUri, PROJECTION, null, null, null );
String res = null;
if ( cursor != null )
{
int dataIdx = cursor.getColumnIndex( MediaColumns.DATA );
if (dataIdx>=0&&cursor.moveToFirst())
res = cursor.getString( dataIdx );
cursor.close();
}
return res;
}
/**
* Dirty hack for API level <8 to get a top-level public external storage directory where Camera photos should be placed.<br>
* Empty photo is inserted, path of its parent directory is retrieved and then photo is deleted.<br>
* If photo cannot be inserted eg. external storage is not mounted, then "DCIM" folder in root of the external storage is used as a fallback.
* @param cr {@link ContentResolver} used to resolve image Uris
* @return path to directory where camera app places photos (may be fallback)
*/
public static String getPhotoDirPath(ContentResolver cr)
{
String fallback=Environment.getExternalStorageDirectory()+"/DCIM";
Uri takenPhotoUri =null;
String photoFilePath=null;
try
{
takenPhotoUri=cr.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, CONTENT_VALUES );
if ( takenPhotoUri == null )
return fallback;
photoFilePath=getPhotoFilePath( takenPhotoUri, cr );
cr.delete( takenPhotoUri, null, null );
}
catch (Exception ex)
{
//igonred
}
if (photoFilePath==null)
return fallback;
String parent = new File(photoFilePath).getParent();
Matcher m = Pattern.compile( "/DCIM(/|$)").matcher( parent );
if (m.find())
parent= parent.substring( 0, m.end() );
return parent;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment