'Scoped Storage won't allow FileInputStream access to file in DOWNLOADS, is there a workaround?

I import data from a downloaded spreadsheet into a Room database. This is what I need to do :

String filePath = Environment
              .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
              .getAbsolutePath();

            String fileName = context.getString(R.my_file_name);
            
            File importFile = new File(filePath + File.separator, fileName);

            try {
                FileInputStream stream = new FileInputStream(importFile);
        
        // do stuff 
     
    } catch (Exception e1) {e1.printStackTrace();}

So, this doesn't work anymore(?) I haven't been able to find a concise explanation (in JAVA) of how to accomplish this simple operation going forward without asking for the MANAGE_EXTERNAL_STORAGE permission (an unacceptable solution) Help from the gurus?



Solution 1:[1]

So, need to set up intent in manifest, and leave old permissions for legacy android

Manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28"/>

<application
    
    android:requestLegacyExternalStorage="true"
   
    >

    <activity
        
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
       
    </activity>
</application>

in mainActivity, set up file picker, create method to launch the picker, and create method to process picker result.

Main Activity :

private ActivityResultLauncher<Intent> launchFilePicker;
public File importFile;

 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    filePath = Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_DOWNLOADS).
            getAbsolutePath();

    launchFilePicker = registerForActivityResult(
            new ActivityResultContract<Intent, Uri>() {
                @NonNull
                @Override
                public Intent createIntent(@NonNull Context context, Intent input) {
                    return input;
                }

                @Override
                public Uri parseResult(int resultCode, @Nullable Intent result) {
                    if (result == null || resultCode != Activity.RESULT_OK) {
                        return null;
                    }
                    return result.getData();
                }
            },
            this::getFileFromUri);

...

 public void launchFileFinder() {
    Intent pickerIntent = new Intent(ACTION_OPEN_DOCUMENT);
    pickerIntent.addCategory(Intent.CATEGORY_OPENABLE);
    pickerIntent.setType(" your mime type ");
    pickerIntent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, Environment
            .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
    launchFilePicker.launch(pickerIntent);
}

...

public void getFileFromUri(Uri result) {
    
String fileName = context.getString(R.my_file_name);        
File importFile = new File(filePath + File.separator, fileName);
InputStream stream = null;
            try {
                stream = AppMainActivity.this.getContentResolver().openInputStream(result);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            if (stream != null) {
                try {
                    FileInputStream stream = new FileInputStream(importFile);
                } catch (IOException | InvalidFormatException e) {
                    e.printStackTrace();
                }
            }
        }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mmcclure2257