I am trying to upgrade my targetSdkVersion to 30. A download manager in the legacy code, expects a File object and creates a file at the file path. I was creating the file using this syntax : File("${Environment.getExternalStorageDirectory()}/$directoryPath").
Since the introduction of Scoped Storage, i can no longer do so.
According to official document document:
I can either create the file in my app directory
Or I can add the file to Shared Storage (which is the preferred use case for me)
Method 2 suggest use of Storage Access Framework. But for that i will have to replace the Download Manager. And that will be huge task and lot for refactoring.
However, i came across this answer on SO
which suggests using File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString()+File.separator+directoryPath) and strangely, it works on both android 10 and 11.
Wondering how it works even though it is deprecated, and is it the right way of doing things?
Related
In Android 11, the getExternalStorageDirectory method that returns the path to external memory is deprecated. Instead, new APIs appeared for working with specific public folders or application folder.
But for a work task, I need to work with folders and files located at the root of external memory. I haven't found an example of a new API that allows this. In the Google documentation, in fact, only how to get permission (via ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) is not a problem. In addition to working with files from Kotlin, I also need to interact with files from C++. There are no problems with the deprecated API, there you can get full paths to files and do whatever you want with them. But what about the new APIs? Or just use the old API, hoping that it won't be released in the next versions?
PS The application will not go to the market, so I can get any permissions and do whatever I want :)
The below link does answer the question about alternatives.
Environment.getExternalStorageDirectory() deprecated in API level 29 java
It answers how to not use the external storage directory and use the internal app specific directories.
And also how to access media files using the other available API's.
Non media files can be accessed only via the System picker, which is the main concern here. I am using my app as a file manager and I will request for MANAGE_EXTERNAL_STORAGE and will follow the process which is totally fine for me.
But the issue is , I want to replace this deprecated function with its alternative. The function which gives me the external storage directory path which looks something like:
storage/emulated/0/
But I get from the alternatives mentioned in android developers page and the above link is :
storage/Android/users/data/0/com.mypackagename.myapp/
I can still use the deprecated function as it still works , but for filemanagers or antivirus apps(which have special access with MANAGE_EXTERNAL_STORAGE permission), what is alternative for Environment.getExternalStorageDirectory() , if Google says that it is deprecated. Without using this deprecated function , there is no way that any filemanagers can get the path of the external storage directory.
I understand in current SDKs that external storage files for my app are created in the /data/data/"package" folder. However, I am integrating with another app that I have no control over and it reads from the "Internal Storage" (Which is the PRIMARY EXTERNAL STORAGE? AARG! :) folder on my Android 10 (R) phone. I've searched for 2 days now how to create a simple .csv file in the folder labeled "Internal Storage" (My Files->Internal Storage) and simply can't find a solution to getting the path to that location.
I'm setting my Android Studio to minSdkVersion at 16, complileSdkVersion to 28, so at least I can use some of the earlier methods for file management. I expect my app to run on phones/tablets at least 3 years old and newer. There is NO UI necessary (picker-as new doc suggests to use) to select a folder to save the file, just simply create a file there is all I need. I'm an old Java programmer but new to Android. Most posts point to deprecated functions we lose in >28 SDKs.
I understand in current SDKs that external storage files for my app are created in the /data/data/"package" folder.
No, that is internal storage.
However, I am integrating with another app that I have no control over and it reads from the "Internal Storage" (Which is the PRIMARY EXTERNAL STORAGE? AARG! :) folder on my Android 10 (R) phone
That app will need to be updated soon.
I've searched for 2 days now how to create a simple .csv file in the folder labeled "Internal Storage" (My Files->Internal Storage) and simply can't find a solution to getting the path to that location
For Android 10 and below, you can use Environment.getExternalStorageDirectory() for the root of external storage. Note that for Android 10 itself, you will need to add android:requestLegacyExternalStorage="true" in the <application> element.
On Android 11+, you can no longer write to the root of external storage using filesystem APIs, unless you hold MANAGE_EXTERNAL_STORAGE. That permission will require justification for use, if you plan on distributing your app via the Play Store (and perhaps elsewhere).
There is NO UI necessary (picker-as new doc suggests to use) to select a folder to save the file
The user may disagree with you. Google definitely disagrees with you. On Android 11, if you do not want your app to be banned from the Play Store, you will need to use ACTION_CREATE_DOCUMENT or ACTION_OPEN_DOCUMENT_TREE and allow the user to decide where the user's file goes on the user's device.
Most posts point to deprecated functions we lose in >28 SDKs.
"Deprecated" in Android does not always mean "lose". It always means "there is another option that Google wishes for you to consider. So, for example, Environment.getExternalStorageDirectory() still exists, even in Android 11. It is just less useful, and Google would prefer that you use methods on StorageVolume instead.
In Android 29, I want to be able to share large files between multiple Android users. Is it possible to make a shared directory that users can access? And can that directory be made browse-able by applications that the users have installed?
Or perhaps have one user with the original directory and files, and other users have a mounted/symlinked directory?
It is important for my implementation that an installed app can access this directory.
I have been navigating the Android filesystem and trying to get my head around:
/mnt/user/0, /storage/emulated/0, and /data/media/0/ but I cannot see a way to make a symlink in another user's home directory to a folder within these directories.
The directory that you are looking for is actually /storage/emulated/0 in your case. I mean the only directory that could be used/accessible by all other applications is the external storage.
However, from Android Q (targetSDKVersion 29), the external storage permission has quite a few changes.
I would recommend looking into the documentation of getExternalStoragePublicDirectory if you are on an Android version that is less than Android Q.
For Android Q and greater, I would recommend looking into the documentation of getExternalFileDir.
Also, there is a great article from #CommonsWare regarding this. Please have a look here in his blog post. I am quoting from his blog here.
For Android Q, you can add
android:requestLegacyExternalStorage="true" to your <application>
element in the manifest. This opts you into the legacy storage model,
and your existing external storage code will work.
Technically, you only need this once you update your
targetSdkVersion to 29. Apps with lower targetSdkVersion values
default to opting into legacy storage and would need
android:requestLegacyExternalStorage="false" to opt-out.
I've been going over the Android file access documentation lately, but I seem to be unable to figure out how to actually open a file given as a string containing the path to the file I'd like to open.
What I (eventually) want to accomplish is something like this:
The user selects a specific kind of text file using Intents, receiving a URI to the file. From this I derive the path (getPath()) and pass this string to the native C++ code.
The native C++ opens the file from the string, parsing the content.
Perform some actual work with the above.
From what I've found so far, it seems like it is no longer possible to open files this way (as of SDK version 26 at least):
A hard-coded path to a file I know exists gives me permission denied.
The path itself received from getPath() triggers a No such file or directory error.
One workaround called for opening the file on the Java side using the ContentResolver, and then passing the file descriptor to the native side. This works, but it's problematic: the files can contain references to other files to be opened ("include files") making such a solution of limited use.
Just to make things clear, these files reside locally on the "USB" partition of the Android system, unrelated to the app itself. Not as resources/assets to the APK or anything similar which other questions of this kind seem to require.
In summary, I guess the question is this: Is it possible to open a file, and possibly any other files it refers to, given a path from the Java side of the application? Is there any requirements for doing this, such as requesting the correct permissions for folders or something similar?
As of Android 6.0 (API level 23) you need to request permissions every time your app starts for "dangerous actions" such as accessing the filesystem or reading contacts. The linked pages already have a snippet of code you can copy.
On older phones requesting permissions in the manifest was sufficient, but the target SDK version was recenly upped to 8.0 (=26). If you want to support devices pre-6.0, the Android compatibility library will allow you to call the same API.