Last active
January 16, 2019 10:57
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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