1. Are you ready for the Galaxy S20? Here is everything we know so far!

Secret camera, fails to save or I can't find files

Discussion in 'Android Development' started by Nightpoison, Jul 30, 2020.

  1. Nightpoison

    Nightpoison Newbie
    Thread Starter

    testing on Pixel 3a, Android API 29 +

    So I'm writing an application that needs to take a picture based on an event, other than a user pressing a camera button. No big deal. I just set the event rather than an onclicklistner, right. Sure. The first problem was most of the information out there revolved around intent and calling the basic camera application. So I had to dig into the camera API's. Camera, Camera2, CameraX. Well I'm now looking at Camera2 and CameraX. CameraX seems a lot simpler.

    Anyway moving on. I have pulled two different examples that I'm going to strip down to look at just the capture functionality. Both examples have a preview screen, and a button. I'm going to throw the preview screen out and create a take picture event.

    The problem I'm having is one application fails to save the picture while the other application I can't find where the pictures are being saved. I believe there is a permission issue that I'm having trouble with.

    BOTH
    with both applications I have permissions set in my manifest file.

    Code (Text):
    1. <uses-permission android:name="android.permission.CAMERA" />
    2.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    3.     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    I also check for permission on both API's for both camera and storage access during onCreate()

    Code (Java):
    1. if(allPermissionsGranted()){
    2.     Toast.makeText(MainActivity.this, "Granted", Toast.LENGTH_SHORT).show();
    3.     startCamera(); //start camera if permission has been granted by user
    4. } else{
    5.     Toast.makeText(MainActivity.this, "Denied", Toast.LENGTH_SHORT).show();
    6.     ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
    7. }
    8.  
    9. private boolean allPermissionsGranted(){
    10.  
    11.     for(String permission : REQUIRED_PERMISSIONS){
    12.         if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
    13.             return false;
    14.         }
    15.     }
    16.     return true;
    17. }
    CameraX

    Here is were things differ. I create the file the image is to be saved in this way.

    Code (Java):
    1. SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
    2. File file = new File(getBatchDirectoryName(), mDateFormat.format(new Date())+ ".jpg");
    3.  
    4. public String getBatchDirectoryName() {
    5.  
    6.     String app_folder_path = "";
    7.     app_folder_path = Environment.getExternalStorageDirectory() + "/images";
    8.     File dir = new File(app_folder_path);
    9.     if (!dir.exists() && !dir.mkdirs()) {
    10.         Toast.makeText(MainActivity.this, "Trip", Toast.LENGTH_SHORT).show();
    11.     }
    12.  
    13.     return app_folder_path;
    This is where I believe the root issue is for some reason I think its a permission issue. When ever I check if the directory exists and then create the directory if it doesn't exist, and try's to create the directory it always fails. I always see the Toast message. I took a look at the stacktrace and I see the following errors.

    Code (Text):
    1. W/System.err: androidx.camera.core.ImageCaptureException: Failed to write or close the file
    2. W/System.err:     at androidx.camera.core.ImageCapture$3.onError(ImageCapture.java:669)
    3.         at androidx.camera.core.ImageSaver.lambda$postError$1$ImageSaver(ImageSaver.java:263)
    4.         at androidx.camera.core.-$$Lambda$ImageSaver$eAp-cZyzsEk-LVLazzLE-ezQzwo.run(Unknown Source:8)
    5.         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    6.         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    7. W/System.err:     at java.lang.Thread.run(Thread.java:919)
    8. W/System.err: Caused by: java.io.FileNotFoundException: /storage/emulated/0/images/20200730085024.jpg: open failed: ENOENT (No such file or directory)
    9.         at libcore.io.IoBridge.open(IoBridge.java:496)
    10. W/System.err:     at java.io.FileOutputStream.<init>(FileOutputStream.java:235)
    11.         at java.io.FileOutputStream.<init>(FileOutputStream.java:186)
    12.         at androidx.camera.core.ImageSaver.run(ImageSaver.java:97)
    13.         ... 3 more
    14. W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
    15.         at libcore.io.Linux.open(Native Method)
    16. W/System.err:     at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
    17.         at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
    18.         at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
    19.         at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7255)
    20.         at libcore.io.IoBridge.open(IoBridge.java:482)
    21.         ... 6 more
    22. D/EGL_emulation: eglMakeCurrent: 0xe09de0c0: ver 3 0 (tinfo 0xe0a8fb90)
    23. W/example.camera: JNI critical lock held for 18.377ms on Thread[15,tid=8749,Runnable,Thread*=0xd531e600,peer=0x13c40348,"Binder:8690_3"]
    24. W/example.camera: JNI critical lock held for 19.631ms on Thread[15,tid=8749,Runnable,Thread*=0xd531e600,peer=0x13c40348,"Binder:8690_3"]
    25.  
    It appears that it can't find the file/directory. Based on passed experience with .csv files, and the reading I should be able to look at the device via the Device File Explorer. However when I open it and look at the /storage/emulated/ folder it just gives me a permission denied message.

    upload_2020-7-30_9-13-45.png

    This is the case even if I'm running an emulator or the app directly on the device.

    Camera2
    The application that I'm running the Camera2 API appears to save the image, but I cant find the images. I get the same access issue from the screen shot above, and the images are stored in this location. So I feel like its a permission issue still.

    For this application I don't attempt to create any new directories.

    Code (Java):
    1. file = new File(Environment.getExternalStorageDirectory()+"/"+UUID.randomUUID().toString()+".jpg");
    The problem with this is, in the final code, I will be creating a new folder for each time the application is run, as each time the app is run will be its own log of files. There will be photos and data files that will need to be organized by instance.

    But with that said, even if I port this way of saving data to the device, as it appears to save the images, doesn't fail, I still don't have access to the images.

    Any insight?
     


    Tharpebb63 likes this.
  2. Thargorsson

    Thargorsson Lurker
    Recognized Developer

    Since youre already running Q or android R, theres something called "Scoped storage" which isolates your process to only access certain directories... Iirc you had to set some specific flags to allow access outside of those.

    In particular you wanna look at:
    https://developer.android.com/reference/android/R.attr#requestLegacyExternalStorage

    Keep in mind that with android R this flag is ignored and youre forced to use your app /data/data dir and some other ones...

    Also see this as reference:
    https://developer.android.com/preview/privacy/storage
     
    Nightpoison and codesplice like this.
  3. Nightpoison

    Nightpoison Newbie
    Thread Starter

    Based on help from @Thagorsson, I was able to make changes to my Manifest file to allow access to external storage.

    I was able to update my permissions to allow legacy access.

    Because in Android Q they have disabled direct file access, they have added a work around to allow legacy support. This is, and as others have mentioned, only a temporary fix for the issue. You will need to follow the new format for saving files going forward with Android R. In my situation, I am only developing a proof of concept and will not need to worry about future versions of Android, at this time.

    To make the temporary fix, do the following

    set up your manifest file similar to this.

    Code (Text):
    1. android:requestLegacyExternalStorage="true">
    2. inside your <application bracket on the manifest file. Should look similar to this
    3.  
    4.     <?xml version="1.0" encoding="utf-8"?>
    5. ...
    6.    package="com.example.camerax">
    7.  
    8. ...
    9.  
    10.    <application
    11.        ...
    12.        android:requestLegacyExternalStorage="true">
    13.        <activity android:name=".MainActivity">
    14.            <intent-filter>
    15.                ...
    16.            </intent-filter>
    17.        </activity>
    18.    </application>
    remember this is not a long term fix, and will not work when a device is updated to Android R
     
Loading...

Share This Page

Loading...