user6487002
user6487002

Reputation:

Using camera to take photo and save to gallery

I have went through several documentation and stacks, however I'm not quite sure how do I implement this...

And help or sample codes would really help me understand more.

Here are the sets of codes that runs the camera and it's working perfectly fine, my next question is, how do I let it automatically saved into phone gallery?

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        tvCameraTiles = (TextView) findViewById(R.id.tvCameraTiles);

        tvCameraTiles.setOnClickListener(new  View.OnClickListener()
        {
             @Override
             public void onClick(View v)
             {
                 dispatchTakePictureIntent();
             }
         });
    }

    private void dispatchTakePictureIntent()
    {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

        if (takePictureIntent.resolveActivity(getPackageManager()) != null)
        {
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK)
        {
            //Get Camera Image File Data
//            Bundle extras = data.getExtras();
//            Bitmap imageBitmap = (Bitmap) extras.get("data");
//            mImageView.setImageBitmap(imageBitmap);
        }
    }

Upvotes: 5

Views: 17069

Answers (4)

Baskar PC
Baskar PC

Reputation: 189

I have experimented for past 1 week with most of the stackoverflow threads but couldn't find a comprehensive solution, but all the threads helped me. Here is the working code which I have tested in Android 11,12 and 13(Google Pixex 6a)

AndroidManifest.xml will have the following

   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
   <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
   </provider>

This what I have mentioned in provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>

call the below method on onclick event

dispatchTakePictureIntent();

In onActivityResult

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch(requestCode) {
        case STApplication.SHOW_TAKEPICTURE:
            //Uri selectedImage=null;
            if (resultCode == Activity.RESULT_OK) {
                try{
                    //Bundle extras = data.getExtras();
                    Bitmap imageBitmap =  MediaStore.Images.Media.getBitmap(getContentResolver(), OldURI);
                    //galleryAddPic();
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        try {
                            saveImageInAndroidApi29AndAbove(imageBitmap);
                        } catch (Exception e) {
                            //show error to user that operatoin failed
                        }
                    } else {
                        saveImageInAndroidApi28AndBelow(imageBitmap);
                    }
                    
                    btnPicture.setText(getString(R.string.picture_taken));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            }
        }
}   

Then finally include all the below methods and variables inside your activity class

    String currentPhotoPath;
    Uri ImageURI;
    public static final int SHOW_TAKEPICTURE = 99;
    

    private void dispatchTakePictureIntent() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // Create the File where the photo should go
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (IOException ex) {
                // Error occurred while creating the File
            }
            // Continue only if the File was successfully created
            if (photoFile != null) {
                Uri photoURI = FileProvider.getUriForFile(this,
                        BuildConfig.APPLICATION_ID + ".provider",
                        photoFile);
                ImageURI=photoURI;
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(takePictureIntent, SHOW_TAKEPICTURE);
            }
        }
    }


    private File createImageFile() throws IOException {
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );

        // Save a file: path for use with ACTION_VIEW intents
        currentPhotoPath = image.getAbsolutePath();
        return image;
    }

    private boolean saveImageInAndroidApi28AndBelow(Bitmap bitmap) {
        OutputStream fos;
        String imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
        File image = new File(imagesDir, "IMG_" + System.currentTimeMillis() + ".png");
        try {
            fos = new FileOutputStream(image);
            bitmap.compress(Bitmap.CompressFormat.PNG, 95, fos);
            Objects.requireNonNull(fos).close();
        } catch (IOException e) {
            e.printStackTrace();
            //isSuccess = false;
            return false;
        }
        //isSuccess = true;
        return true;
    }

    @NonNull
    public Uri saveImageInAndroidApi29AndAbove(@NonNull final Bitmap bitmap) throws IOException {
        final ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, "IMG_" + System.currentTimeMillis());
        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
        }
        final ContentResolver resolver = getApplicationContext().getContentResolver();
        Uri uri = null;
        try {
            final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            uri = resolver.insert(contentUri, values);
            if (uri == null) {
                //isSuccess = false;
                throw new IOException("Failed to create new MediaStore record.");
            }
            try (final OutputStream stream = resolver.openOutputStream(uri)) {
                if (stream == null) {
                    //isSuccess = false;
                    throw new IOException("Failed to open output stream.");
                }
                if (!bitmap.compress(Bitmap.CompressFormat.PNG, 95, stream)) {
                    //isSuccess = false;
                    throw new IOException("Failed to save bitmap.");
                }
            }
            //isSuccess = true;
            return uri;
        } catch (IOException e) {
            if (uri != null) {
                resolver.delete(uri, null, null);
            }
            throw e;
        }
    }

Upvotes: 1

Vlad Vasiljev
Vlad Vasiljev

Reputation: 55

I tried out Rex B code snippet, but ended up getting a error on Android Studio.

 android.os.FileUriExposedException: file:///storage/emulated/0/example6941495009290613124.jpg exposed beyond app through ClipData.Item.getUri()

If anyone got this error, I found a simple fix

StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());

I added these two lines to the onClick method

  Button photoButton = (Button) findViewById(R.id.photobutton);
    photoButton.setOnClickListener(new  View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
        StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
        StrictMode.setVmPolicy(builder.build());
            dispatchTakePictureIntent();
        }
    });
}

I know this is old post, but I'm sure someone will come by this one day.

Upvotes: 2

Rex B
Rex B

Reputation: 51

have you read this https://developer.android.com/training/camera/photobasics.html ?

Especially the part:

private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

You don't seem to save the photo in the external storage, so it should work.

EDIT: I tried to make a really basic application following the documentation with the method galleryAddPic.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button photoButton = (Button) findViewById(R.id.photobutton);
    photoButton.setOnClickListener(new  View.OnClickListener()
    {
        @Override
        public void onClick(View v)
        {
            dispatchTakePictureIntent();
        }
    });
}

static final int REQUEST_IMAGE_CAPTURE = 1;

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        //Bundle extras = data.getExtras();
        //Bitmap imageBitmap = (Bitmap) extras.get("data");
        //mImageView.setImageBitmap(imageBitmap);
        galleryAddPic();
    }
}

String mCurrentPhotoPath;

private File createImageFile() throws IOException {
    File storageDir = Environment.getExternalStorageDirectory();
    File image = File.createTempFile(
            "example",  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        if (photoFile != null) {
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }
}

private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

This is working for me! I take a picture using the camera app, and then it's showed in the gallery app. I modified the code regarding the FileProvider part, now it passes the Uri with the help of the method Uri.fromFile(photoFile). I save the photo in a different position too, check the code in the method createImageFile for this one.

In the Android Studio emulator is working fine, let me know about you.

Upvotes: 5

Noorul
Noorul

Reputation: 3444

First the file will be created and the ByteStream will be written on the file and saved. you don't do anything for this file to be present in the gallery. This will automatically refreshed by gallery.

Upvotes: 0

Related Questions