I am creating an application in which I want to capture a image and then I want to send that image in the email as a attachment.
I am opening a camera using android.provider.MediaStore.ACTION_IMAGE_CAPTURE intent action and I am passing the Uri of the file as a parameter EXTRA_OUTPUT to get the image back to the file. This is working perfectly and I am able to get the captured image if I use the external storage uri as a EXTRA_OUTPUT but if I use the data folder uri it is not working and the camera is not closing and its all buttons are not working.
Here is my code for get the result in the external storage directory
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File out = Environment.getExternalStorageDirectory();
out = new File(out, imagename);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(i, CAMERA_RESULT);
And this code is for get the image in the data folder
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File out = getFilesDir();
out = new File(out, MyPharmacyOptions.PRESCRIPTION_IMAGE_NAME);
i.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(out));
startActivityForResult(i, CAMERA_RESULT);
I knew that the data folder is not accessible to third application so may be this causes an issue so I have create one content provider to share the file.
Here is my content provide class
public class MyContentProvider extends ContentProvider {
private static final String Tag = RingtonContentProvider.class.getName();
public static final Uri CONTENT_URI = Uri
.parse("content://x.y.z/");
private static final HashMap<String, String> MIME_TYPES = new HashMap<String, String>();
static {
MIME_TYPES.put(".mp3", "audio/mp3");
MIME_TYPES.put(".wav", "audio/mp3");
MIME_TYPES.put(".jpg", "image/jpeg");
}
#Override
public boolean onCreate() {
return true;
}
#Override
public String getType(Uri uri) {
String path = uri.toString();
for (String extension : MIME_TYPES.keySet()) {
if (path.endsWith(extension)) {
return (MIME_TYPES.get(extension));
}
}
return (null);
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
File f = new File(getContext().getFilesDir(), uri.getPath());
if (f.exists()) {
return (ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY));
}
throw new FileNotFoundException(uri.getPath());
}
#Override
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sort) {
throw new RuntimeException("Operation not supported");
}
#Override
public Uri insert(Uri uri, ContentValues initialValues) {
File file = new File(getContext().getFilesDir(), uri.getPath());
if(file.exists()) file.delete();
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return Uri.fromFile(file);
}
#Override
public int update(Uri uri, ContentValues values, String where,
String[] whereArgs) {
throw new RuntimeException("Operation not supported");
}
#Override
public int delete(Uri uri, String where, String[] whereArgs) {
File f = new File(getContext().getFilesDir(), "image1.jpg");
if(f.exists()) f.delete();
f = new File(getContext().getFilesDir(), "image2.jpg");
if(f.exists()) f.delete();
getContext().getContentResolver().notifyChange(CONTENT_URI, null);
}
}
So to use this content provide I am using following code to pass the uri to the camera activity
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
Uri uri = MyContentProvider.CONTENT_URI;
uri = Uri.withAppendedPath(uri, imagename);
getContentResolver().insert(uri, null);
getContentResolver().notifyChange(RingtonContentProvider.CONTENT_URI, null);
Log.d(Tag, uri.toString());
i.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(i, CAMERA_RESULT);
Now if I pass the url other then external storage directory the camera is opening but it is not closing in emulator but in device the camera is going to closed but I am not getting the result.
I have declared this content provide in the manifest file
<provider
android:name=".contentproviders.MyContentProvider"
android:authorities="x.y.z" />
Also I have given the permission to write the external storage and also for use the camera.
I am able to capture the image using the external storage but I want to store the image in the data directory instead of external storage because if the external storage in not available I want to capture the image and want to send mail.
If I create content provide then I can also share my image to the email application.
If we not provide the extras with the camera intent it will return the image as a byte[] in the activity result as a data extra but this is for the purpose of the thumbnail so I can't get the high resolution image using this way.
There are two ways to solve this problem.
1. Save bitmap which you received from onActivityResult method
You can start camera through intent to capture photo using below code
Intent cameraIntent=new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
After capture photo, you will get bitmap in onActivityResult method
if (requestCode == CAMERA_REQUEST) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
}
Now you can simply save this bitmap to internal storage
Note: Here bitmap object consists of thumb image, it will not have a full resolution image
2. Save bitmap directly to internal storage using content provider
Here we will create content provider class to allow permission of local storage directory to camera activity
Sample provider example as per below
public class MyFileContentProvider extends ContentProvider {
public static final Uri CONTENT_URI = Uri.parse
("content://com.example.camerademo/");
private static final HashMap<String, String> MIME_TYPES =
new HashMap<String, String>();
static {
MIME_TYPES.put(".jpg", "image/jpeg");
MIME_TYPES.put(".jpeg", "image/jpeg");
}
#Override
public boolean onCreate() {
try {
File mFile = new File(getContext().getFilesDir(), "newImage.jpg");
if(!mFile.exists()) {
mFile.createNewFile();
}
getContext().getContentResolver().notifyChange(CONTENT_URI, null);
return (true);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
#Override
public String getType(Uri uri) {
String path = uri.toString();
for (String extension : MIME_TYPES.keySet()) {
if (path.endsWith(extension)) {
return (MIME_TYPES.get(extension));
}
}
return (null);
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
File f = new File(getContext().getFilesDir(), "newImage.jpg");
if (f.exists()) {
return (ParcelFileDescriptor.open(f,
ParcelFileDescriptor.MODE_READ_WRITE));
}
throw new FileNotFoundException(uri.getPath());
}
}
After that you can simply use the URI to pass to camera activity using the below code
Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
i.putExtra(MediaStore.EXTRA_OUTPUT, MyFileContentProvider.CONTENT_URI);
startActivityForResult(i, CAMERA_RESULT);
If you don't want to create your own provider then you can use FileProvider from support-library-v4. For detailed help you can look into this post
Best solution I found is: FileProvider (needs support-library-v4)
It uses the internal storage!
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Define your FileProvider in Manifest in Application element:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="your.package.name.fileprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/image_path" />
</provider>
Add permissions in manifest root element:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
Define your image paths in for example res/xml/image_path.xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="captured_image" path="your/path/"/>
</paths>
Java:
private static final int IMAGE_REQUEST_CODE = 1;
// your authority, must be the same as in your manifest file
private static final String CAPTURE_IMAGE_FILE_PROVIDER = "your.package.name.fileprovider";
4.1 capture intent:
File path = new File(activity.getFilesDir(), "your/path");
if (!path.exists()) path.mkdirs();
File image = new File(path, "image.jpg");
Uri imageUri = FileProvider.getUriForFile(activity, CAPTURE_IMAGE_FILE_PROVIDER, image);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, IMAGE_REQUEST_CODE);
4.2 onActivityResult():
#Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == IMAGE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
File path = new File(getFilesDir(), "your/path");
if (!path.exists()) path.mkdirs();
File imageFile = new File(path, "image.jpg");
// use imageFile to open your image
}
}
super.onActivityResult(requestCode, resultCode, intent);
}
Intent to call to capture photo,
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
Then Take Bitmap in ActivityResult
if (requestCode == CAMERA_REQUEST) {
Bitmap photo = (Bitmap) data.getExtras().get("data");
}
Then Write that Into Internal Memory, see this
// The openfileOutput() method creates a file on the phone/internal storage in the context of your application
final FileOutputStream fos = openFileOutput("my_new_image.jpg", Context.MODE_PRIVATE);
// Use the compress method on the BitMap object to write image to the OutputStream
bm.compress(CompressFormat.JPEG, 90, fos);
Then next time to read that file,
Bitmap bitmap = BitmapFactory.decodeFile(file);
At first save came photo in your external storage and try it -
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
this.imageView = (ImageView)this.findViewById(R.id.imageView1);
Button photoButton = (Button) this.findViewById(R.id.button1);
photoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, CAMERA_REQUEST);
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_REQUEST) {
Bitmap bmp = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray(); // convert camera photo to byte array
// save it in your external storage.
FileOutputStream fo = new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/_camera.png"));
fo.write(byteArray);
fo.flush();
fo.close();
}
}
Next target -
File cameraFile = new File(Environment.getExternalStorageDirectory() + "/_camera.png");
startActivityForResult(Intent.createChooser(new Intent(Intent.ACTION_SEND)
.setType("image/jpg")
.putExtra(Intent.EXTRA_SUBJECT, "Subject")
.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(cameraFile))
.putExtra(Intent.EXTRA_TEXT, textBody), "Send your message using"), Constant.EMAIL);
You can also do this without needing a content provider since you will need the sd card to open the camera image capture intent anyway. You can of course hack around the presence of the sd card but not with the camera intent capture....So you are checking for external storage but need it at this point.... FYI you should also check out a crop library like crop-image instead of using native, as it is not well supported across devices.
File mediaStorageDir;
String photoFileName = "photo.jpg";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// page = getArguments().getInt("someInt", 0);
// title = getArguments().getString("someTitle");
// Get safe storage directory for photos
mediaStorageDir = new File(
Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
APP_TAG);
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists() && !mediaStorageDir.mkdirs()) {
Log.d(APP_TAG, "Directory exists: " + mediaStorageDir.isDirectory());
Log.d(APP_TAG, "Directory exists: " + mediaStorageDir.getPath());
Log.d(APP_TAG,
"Directory exists: "
+ Environment.getExternalStorageState());
Log.d(APP_TAG, "failed to create directory");
}
}
in your 'take the pic' code:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, getPhotoFileUri(photoFileName));
...
public Uri getPhotoFileUri(String fileName) {
return Uri.fromFile(new File(mediaStorageDir.getPath() + File.separator
+ fileName));
}
After researching this bug for some time, I have noticed that the activity that called the camera intent is only restarted when the phone is running out of memory.
so because the activity is restarted, the object holding the path or Uri to the captured image is refreshed (nulled)
so I would suggest you catch/ detect the null object in the onActivityResult, and prompt the user to free up space on their device or restart their phone for a quick temporary fix.
Related
I am trying to open a camera intent and load the captured image in Android. The issue is that the camera app writes to the input URI correctly and the written data can be successfully decoded into a Bitmap only on the first call. On subsequent calls, it does not write any bytes to the input file and I checked that the file located at that URI still has 0 bytes after control returns from the camera app.
Here is the code for creating the file URI for input to camera app.
private #NonNull Uri getImageUri() {
Uri outputFileUri = null;
final String imageFileName = "JPEG_"
+ new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".jpeg" ;
File imagePath = new File(getFilesDir(), "images");
if(!imagePath.isDirectory()) {
imagePath.mkdirs();
}
File newFile = new File(imagePath, imageFileName);
if (newFile.exists()) {
newFile.delete();
}
try {
if(!newFile.createNewFile())
Log.e(MyActivity.class.getSimpleName(), "Error creating file");
} catch (IOException e) {
e.printStackTrace();
}
if(!(null != newFile && newFile.isFile())) {
throw new IllegalStateException("Cannot create file ");
}
outputFileUri = FileProvider.getUriForFile(
this.getApplicationContext(), "com.myapp.android.fileprovider", newFile);
if(null == outputFileUri){
throw new IllegalStateException( "Cannot create file for clicking image");
}
Log.e(MyActivity.class.getSimpleName(), "output file uri " + outputFileUri);
return outputFileUri;
}
Below is the code which opens the camera intent:
private List<Intent> getCameraIntents(#NonNull final Uri path){
if(!mCameraIntents.isEmpty()) return mCameraIntents;
#NonNull final Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
#NonNull final List<ResolveInfo> listCam =
getPackageManager().queryIntentActivities(captureIntent, 0);
#NonNull final ArrayList<Intent> cameraIntents = new ArrayList<>(1);
for (ResolveInfo res : listCam) {
Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
intent.putExtra(MediaStore.EXTRA_OUTPUT, path);
cameraIntents.add(intent);
}
mCameraIntents.addAll(cameraIntents);
return cameraIntents;
}
/**
* Create a chooser intent to select the source to get image from.<br />
* The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).<br />
* All possible sources are added to the intent chooser.
*/
private Intent imageChooser() {
// Determine Uri of camera image to save.
#NonNull final Uri outputFileUri = getImageUri();
#NonNull final List<Intent> allIntents = getCameraIntents(outputFileUri);
allIntents.addAll(getGalleryIntents());
#NonNull final Intent mainIntent = allIntents.remove(allIntents.size() - 1);
// Create a chooser from the main intent
Intent chooserIntent = Intent.createChooser(
mainIntent,
getResources().getString(R.string.snap_app_chooser_message));
// Add all other intents
chooserIntent.putExtra(
Intent.EXTRA_INITIAL_INTENTS,
allIntents.toArray(new Parcelable[allIntents.size()]));
mSnapUri = outputFileUri;
return chooserIntent;
}
Then I simply call this,
startActivityForResult(imageChooser(), REQUEST_IMAGE_CAPTURE);
Below is the code for decoding the captured image written in the file URI by the camera app.
#NonNull #Override protected Bitmap doInBackground(#NonNull final Uri... snapUris) {
Bitmap snap = null;
try {
Log.e(MyActivity.class.getSimpleName(), "snap uri " + snapUris[0]);
snap = MediaStore.Images.Media.getBitmap(
mActivity.get().getContentResolver(),
snapUris[0]);
if(null == snap ){
InputStream is =
mActivity.get().getContentResolver()
.openInputStream(snapUris[0]);
snap = BitmapFactory.decodeStream(is);
}
if (null == snap) {
Log.e(MyActivity.class.getSimpleName(), "Problem with uri path");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
return snap;
}
}
Can anyone help me in understanding why the camera app is not writing the captured image into the file URI after the first call? What changes between the first time the camera intent in invoked and the next time it is invoked that it cannot write into the second and the subsequent file URIs. Is the outputstream of the camera app not properly closing after the first call?
I tested it on Xiaomi and Lenovo phones and am getting the same behavior.
I want to take image from camera and store it and view it from internal storage.
I use this code to take image from camera.
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PIC);
I tried the following to save the bitmap in internal storage.
public String saveToInternalSorage(Bitmap bitmapImage, String fileName){
File file = new File(createBasePath(), fileName + ".png");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
return file.getName();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKE_PIC && resultCode == RESULT_OK) {
Intent i=new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(output), "image/png");
startActivity(i);
}
}
My path is /data/user/0/com.dev/app/1454351400000/33352/capture_Image1.png
But here I am facing one issue. The bit map size is very small. I want exact image what I taken from camera.
Then I found one solution. Set the path before intent. So I tried like this.
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
output = new File(createBasePath(), "capture_Image1" + ".png");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(output));
startActivityForResult(intent, TAKE_PIC);
When I use this code the image is not showing. on onActivityResult the resultCode showing -1.
If I use the following code
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File dir= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
output=new File(dir, "CameraContentDemo.png");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(output));
startActivityForResult(intent, TAKE_PIC);
This code is working fine. After taking the image it showing image.
So please let me know store and retrieve the image from internal db with original quality.
Below is code to save the image to internal directory.
private String saveToInternalStorage(Bitmap bitmapImage){
ContextWrapper cw = new ContextWrapper(getApplicationContext());
// path to imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Now Create imageDir
File mypath=new File(directory,"abc.jpg");
FileOutputStream foss = null;
try {
foss = new FileOutputStream(mypath);
// Using compress method on the BitMap object to write image to the OutputStream
bitmapImage.compress(Bitmap.CompressFormat.PNG, 100, foss);
} catch (Exception e) {
e.printStackTrace();
} finally {
foss.close();
}
return directory.getAbsolutePath();
}
Use below code for Reading a file from internal storage
private void loadImageFromStorage(String path)
{
try {
File f=new File(path, "abc.jpg");
Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
ImageView img=(ImageView)findViewById(R.id.imgPicker);
img.setImageBitmap(b);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
}
void openMultiSelectGallery() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
fileUri =getOutputMediaFile();
intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
/* start activity for result pass intent as argument and request code */
startActivityForResult(intent, CAMERA_REQUEEST_CODE);
}
/**
* This method set the path for the captured image from camera for updating
* the profile pic
*/
private Uri getOutputMediaFile() {
File mediaStorageDir = new File(
Environment.getExternalStorageDirectory(), "."
+ Constants.CONTAINER);
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
mediaStorageDir.mkdirs();
}
File mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + System.currentTimeMillis() + ".png");
Uri uri = null;
if (mediaFile != null) {
uri = Uri.fromFile(mediaFile);
}
return uri;
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK
&& requestCode == CAMERA_REQUEEST_CODE) {
String path =fileUri.getPath();
//decode the path to bitmap here
}
}
I am trying to get the full image after taking a picture from a Fragment.
If I use the Uri from the file (Uri.fromFile(file)), the camera won't exit after taking the photo and tapping on the 'ok' button (looks like can't write to the Uri or who knows what).
Using the File String, in the form of '/data/data/com.package.bla/cache/img198346262jpg', it's not working as well (The file is there, but it's empty because the camera is not saving anything on it).
What I tried so far:
Deleting the file after creating it, as this example does. However, the file doesn't exist after the camera exits.
Added External Storage READ permission, just in case
So I have no idea why the image is not being saved and already spent/wasted a lot of time testing and figuring why it's not working.
Fragment:
private void launchCamera() {
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
File outputDir = getActivity().getCacheDir();
File file = null;
try {
file = File.createTempFile("img", "jpg", outputDir);
} catch (IOException e) {
e.printStackTrace();
}
if (file != null) {
mImageUri = Uri.fromFile(file); //using Uri is not even exiting the camera
//mImageUri = File.toString(); //If I use String instead of an Uri, it works better (ie, can accept camera photo)
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
startActivityForResult(cameraIntent, RESULT_TAKE_IMAGE);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
Bitmap original = BitmapFactory.decodeFile(mImageUri.toString(), bounds);
}
}
Edited code, mImageUri. As explained, if I use Uri I can't even accept the photo in the camera app. Using a String will let me accept the photo, though the photo is not actually saved (ie the file has 0 bytes inside it).
EXPLANATION: The problem was related to saving into the cache directory. Maybe it's a bug, I am missing a permission or the camera app just can't save into your application private data directory. Adding Permission FLAG_GRANT_WRITE_URI_PERMISSION didn't solve it. Related posts: Store image from camera into private app cache directory AND Saving camera data to cache when launched via intent
UPDATE From Android 2.2 onwards getExternalCacheDir() method can be used instead of getCacheDir()
from android 26+ Uri.fromFile will not work, you should use File provider instead.
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
.........
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mydomain.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
</provider>
</application>
res/xml/file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
</paths>
finally
final Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
// output file
File path = new File(Environment.getExternalStorageDirectory(), "tmp.mp4");
// com.mydomain.fileprovider is authorities (manifest)
// getUri from file
Uri uri = FileProvider.getUriForFile(this, "com.mydomain.fileprovider", path);
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takeVideoIntent, 99);
tested on android 8.0 and 5.1.1
Update: on some device built-in camera would not support for EXTRA_OUTPUT, so if you want to work on all devices, build your own camera module.
Why not saving it in a new File
final File root = new File(Environment.getExternalStorageDirectory() + File.separator + "MyDir" + File.separator);
root.mkdirs();
final String fname = "img_"+ System.currentTimeMillis() + ".jpg";
final File sdImageMainDirectory = new File(root, fname);
mImageUri = Uri.fromFile(sdImageMainDirectory);
And then pass that uri to the intent
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
Try this is working like charm with me
private String selectedImagePath = "";
final private int PICK_IMAGE = 1;
final private int CAPTURE_IMAGE = 2;
public Uri setImageUri() {
// Store image in dcim
File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/", "image" + new Date().getTime() + ".png");
Uri imgUri = Uri.fromFile(file);
this.imgPath = file.getAbsolutePath();
return imgUri;
}
public String getImagePath() {
return imgPath;
}
btnGallery.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, ""), PICK_IMAGE);
}
});
btnCapture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri());
startActivityForResult(intent, CAPTURE_IMAGE);
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_CANCELED) {
if (requestCode == PICK_IMAGE) {
selectedImagePath = getAbsolutePath(data.getData());
imgUser.setImageBitmap(decodeFile(selectedImagePath));
} else if (requestCode == CAPTURE_IMAGE) {
selectedImagePath = getImagePath();
imgUser.setImageBitmap(decodeFile(selectedImagePath));
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
public Bitmap decodeFile(String path) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 70;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeFile(path, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
public String getAbsolutePath(Uri uri) {
String[] projection = { MediaColumns.DATA };
#SuppressWarnings("deprecation")
Cursor cursor = managedQuery(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
I just want to save a picture in my Imagefolder in my phone.
I have got 2 examples which I tried.
1. Example
My app crashes when I activate the onClick Method:
public void onClick(View arg0) {
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, 1337);
}});
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if( requestCode == 1337)
{
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());
}
else
{
Toast.makeText(AndroidCamera.this, "Picture NOt taken", Toast.LENGTH_LONG);
}
super.onActivityResult(requestCode, resultCode, data);
}
2. Example
Before I saved my taken Picture with Uri. But it saved my picture in a folder, which I can only access on my PC or with a FileApp. I donĀ“t know how I can change the Path direction with Uri to my existing default image folder in my phone.
Uri uriTarget = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());
This is how I manage with saving images to specified imagefolder
When starting camera intent I define path and directory, where my image should be saved, and pass this as intetn extra when starting camera:
private void startCameraIntent() {
//create file path
final String photoStorePath = getProductPhotoDirectory().getAbsolutePath();
//create file uri
final Uri fileUri = getPhotoFileUri(photoStorePath);
//create camera intent
final Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//put file ure to intetn - this will tell camera where to save file with image
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
// start activity
startActivityForResult(cameraIntent, REQUEST_CODE_PHOTO_FROM_CAMERA);
//start image scanne to add photo to gallery
addProductPhotoToGallery(fileUri);
}
And here are some of helper methods used in code above
private File getProductPhotoDirectory() {
//get directory where file should be stored
return new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES),
"myPhotoDir");
}
private Uri getPhotoFileUri(final String photoStorePath) {
//timestamp used in file name
final String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss",
Locale.US).format(new Date());
// file uri with timestamp
final Uri fileUri = Uri.fromFile(new java.io.File(photoStorePath
+ java.io.File.separator + "IMG_" + timestamp + ".jpg"));
return fileUri;
}
private void addProductPhotoToGallery(Uri photoUri) {
//create media scanner intetnt
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
//set uri to scan
mediaScanIntent.setData(photoUri);
//start media scanner to discover new photo and display it in gallery
this.sendBroadcast(mediaScanIntent);
}
I have a fragment that takes a canvas drawing and saves it to external memory. I go into the device by connecting the USB and searching the file directory. I find it under Android/data/appname/files/img/nameofimage.png. Now I have a 2nd fragment that is saving pictures when the camera takes them but I can't find them.
Camera
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check that request code matches ours:
if (requestCode == CALL_BACK) {
// Check if your application folder exists in the external storage,
// if not create it:
File imageStorageFolder = new File(
Environment.getExternalStorageDirectory() + File.separator
+ "Camera");
if (!imageStorageFolder.exists()) {
imageStorageFolder.mkdirs();
Log.d("FILE",
"Folder created at: " + imageStorageFolder.toString());
}
// Check if data in not null and extract the Bitmap:
if (data != null) {
String filename = "image";
String fileNameExtension = ".jpg";
File sdCard = Environment.getExternalStorageDirectory();
String imageStorageFolderName = File.separator + "Camera"
+ File.separator;
File destinationFile = new File(sdCard, imageStorageFolderName
+ filename + fileNameExtension);
Log.d("FILE", "the destination for image file is: "
+ destinationFile);
if (data.getExtras() != null) {
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
try {
FileOutputStream out = new FileOutputStream(
destinationFile);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
Log.e("FILE", "ERROR:" + e.toString());
}
}
}
}
}
Canvas
capSig.setView(sign = new Sign(this.getActivity(), null))
.setMessage(R.string.store_question)
.setPositiveButton(R.string.save,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
try {
sign.setDrawingCacheEnabled(true);
sign.getDrawingCache()
.compress(
Bitmap.CompressFormat.PNG,
10,
new FileOutputStream(
new File(
getActivity()
.getExternalFilesDir(
"img"),
"signature.png")));
} catch (Exception e) {
Log.e("Error ", e.toString());
}
onClick
private class ClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(intent, CALL_BACK);
}
}
I don't fully understand the code, why is this saving to a different location. Also what would I need to do to get it to save under Android/data/appname/files/Camera/ ?
edit
the logcat tells me its being saved here: 06-08 16:21:49.333: D/FILE(4818): the destination for image file is: /storage/emulated/0/Camera/image.jpg Which I assume is listed as private in the files and that's why I cant find it. This does not tell me why its being saved here though.
2nd Edit
Current Code
private class ClickListener implements View.OnClickListener {
#Override
public void onClick(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File sdCard = Environment.getExternalStorageDirectory();
String path = sdCard.getAbsolutePath() + "/Camera" ;
File dir = new File(path);
if (!dir.exists()) {
if (dir.mkdirs()) {
}
}
String FileName = "image";
File file = new File(path, FileName + ".jpg");
Uri outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, CALL_BACK);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
// Check that request code matches ours:
if (requestCode == CALL_BACK) {
Log.v("RESULT", "Picture Taken");
}
}
Try this code
private void TakePhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File sdCard = Environment.getExternalStorageDirectory();
String path = sdCard.getAbsolutePath() + "/Camera" ;
File dir = new File(path);
if (!dir.exists()) {
if (dir.mkdirs()) {
}
}
String FileName = "image";
File file = new File(path, FileName + ".jpg");
Uri outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
startActivityForResult(intent, TAKE_PICTURE);
}
Remember
You need this Permission in your Manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />