2

I want to call the camera through intent, capture images, and save it locally in the gallery and in the app-specific storage how can I achieve that?

I went through this question also but the code is not working I don't know why.

Yechiel babani
  • 344
  • 3
  • 13
parker
  • 41
  • 2
  • 13
  • are you running it on Android 12? – user16930239 Jan 14 '22 at 17:45
  • No, I am running it on my emulator and android device both are android 11 @Jabbar – parker Jan 14 '22 at 18:36
  • Do you want to save an image in two locations? And you did not describe any problem you encountered. – blackapps Jan 14 '22 at 20:19
  • The media store does not scan files in app specific storages. Are you asking it should? Describe your problem! – blackapps Jan 14 '22 at 20:21
  • since android 11, the scope of the storage has changed. so you need to check what is the version of the android and create the specific path depending on the android version – Yechiel babani Jan 16 '22 at 16:13
  • Hi, I encountered the same issue , the image has been successfully stored in app-specific scope storage but default gallery cannot scan it. so I have to save it in some shared folder so that any other app can access it. the pic has been taken by default camera using the new Api for that. – Miftah Classifieds Feb 03 '23 at 22:40

4 Answers4

1

I have done something like this Before, I Share my code with you and others that may help.
in this scenario if you want to save captured image, you have to check which api level that device is running with. for api level 28 and below you have to use specific method and for api level 28 above you have specific way. so first step, start from:
AndroidManifest.xml

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" tools:ignore="ScopedStorage"/>

and add this line in to your AndroidManifest.xml application tag:

android:requestLegacyExternalStorage="true"

if your project targetSdkVersion is 28 and above, you have to use ActivityResultLauncher otherwise you have to override onRequestPermissionResult in your fragment or activity.
if you use fragment you have to register your ActivityResultLauncher in onAttach method, if not register it in onCreate of your Activity, so do this:

public class YourFragment extends Fragment {
   private Bitmap bitmap;
   private ActivityResultLauncher<String> storageResultActivity;


    @Override
    public void onAttach(@NonNull @NotNull Context context) {
       super.onAttach(context);
       registerWriteExternalStoragePermission();
    }

registerWriteExternalStoragePermission has this codes:

    private void registerWriteExternalStoragePermission() {
    storageResultActivity = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
        if (isGranted) {
            checkStoragePermissionAndSaveImage(bitmap);
        }
    });
}

so next step is to get back result of captured image from intent and change it to Bitmap for this section we need another activityResultLauncher so do this in onAttach of your fragment or onCreate of your activity:

ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
    if (result.getResultCode() == RESULT_OK) {
       Intent data = result.getData();
       if (data == null || data.getData() == null) {
          //showError
       }
       Uri uri = data.getData();
        if (Build.VERSION.SDK_INT < 29) {
            bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
        } else {
            ImageDecoder.Source source = ImageDecoder.createSource(context.getContentResolver(), uri);
            bitmap = ImageDecoder.decodeBitmap(source);
        }
    }

so next step is to check your app has storage permission or not:

    if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
        saveImageInAndroidApi28AndBelow(bitmap);
    } else if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
        //show user app can't save image for storage permission denied
    } else {
        storageResultActivity.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

ok as we near the end of this answer :) you have to implement saveImageInAndroidApi28AndBelow method, se lets go to do it:

    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;
}

and the final step is to implement saveImageInAndroidApi29AndAbove method do it like this:

@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 (SDK_INT >= Build.VERSION_CODES.Q) {
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
    }
    final ContentResolver resolver = requireContext().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;
    }
}

so you have to check which API Level that device is running and with with little code handle what you want:

            if (SDK_INT >= Build.VERSION_CODES.Q) {
            try {
                saveImageInAndroidApi29AndAbove(bitmap);
            } catch (Exception e) {
               //show error to user that operatoin failed
            }
        } else {
            saveImageInAndroidApi28AndBelow(bitmap);
        }

Don't FORGET TO call .launch ON YOUR ActivityResultLauncher

have a good time with the codes :)

OneDev
  • 557
  • 3
  • 14
0

I'm assuming the app-specific storage is some sort of cache, in your onActivityResult() wouldn't you save the picture first to app-specific storage and then copy it to Environment.DIRECTORY_PICTURES?

REInVent
  • 103
  • 7
0

Simple, make a Launcher attach the camera and gallery and you have everything in one place, here I send you 2 links to make a launcher

https://code.tutsplus.com/es/tutorials/build-a-custom-launcher-on-android--cms-21358

https://steemit.com/utopian-io/@ideba/how-to-build-a-custom-android-launcher-and-home-screen-application-part-1

Rene
  • 1
  • 1
-1

Whenever you take a photo from the device, you the image uri in the onActivityResult. Now to save it to another location, you can use the code given below

void savefile(Uri sourceuri){
    String sourceFilename= sourceuri.getPath();
    String destinationFilename = android.os.Environment.getExternalStorageDirectory().getPath()+File.separatorChar+"abc.mp3";

    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;

    try {
      bis = new BufferedInputStream(new FileInputStream(sourceFilename));
      bos = new BufferedOutputStream(new FileOutputStream(destinationFilename, false));
      byte[] buf = new byte[1024];
      bis.read(buf);
      do {
         bos.write(buf);
      } while(bis.read(buf) != -1);
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (bis != null) bis.close();
        if (bos != null) bos.close();
      } catch (IOException e) {
            e.printStackTrace();
      }
   }
}

And in the onActivityResult, you can call it like this

saveFile(data.getData());
Sambhav Khandelwal
  • 3,585
  • 2
  • 7
  • 38