Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method getExternalStorageDirectory is deprecated (could effect the external viewer calls) #130

Closed
WRPSoft opened this issue Feb 26, 2021 · 7 comments

Comments

@WRPSoft
Copy link

WRPSoft commented Feb 26, 2021

Great GPS logger app that I'm often using when I don't have a GPS device with me.

A suggestion for improvement: if possible, the method getExternalStorageDirectory (e.g. GPSApplication.java) should be replaced in the future, as it was declared as deprecated by Google and first problems appear under current Android versions >= 10 (https://developer.android.com/reference/android/os/Environment#getExternalStorageDirectory()).

I have programmed a small free GPS Viewer app and I must embedd application android: requestLegacyExternalStorage = "true" in the manifest, otherwise my app cannot be used as an optional viewer in GPS Logger under Android 10 (no access to the file intent when calling the external viewer app). It is difficult to debug, the problem does not appear in Android Studio Emulator (emulating an Android 10 device), but on various Xiaomi phones that run on Android 10.

If I assign the requestLegacyExternalStorage option in the manifest, the viewer function also works on Xiaomi phones, but from Android 11 at the latest, this temporary option should no longer work (https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage).

But again, nice lightweight GPS logger app that is limited to the essentials. Even my not the youngest mother is using this app sometimes when she is on a hike :).

Thanks you for sharing this app.

@GrazianoCapelli
Copy link
Member

The problem is that the introduction of Scoped Storage is making a Mess for apps that implement the Intent.ACTION_VIEW with shared folders.

The Android Apps currently have 2 ways to pass the Uri to an intent: the old method is Uri.fromFile, the new is with FileProvider using FileProvider.getUriForFile.

The problem arises because some Apps follow the old approach (like GPX Viewer): when the Uri points to a shared Folder (like the ExternalStorageDirectory and sub folders), the app opens the specified file; when the Uri is from a FileProvider, the app make a copy of the file into its own folder and opens it from here (in order to avoid any permission loss). In this case, if we use the FileProvider method, the app will make a new copy of the file every time it opens it.
Other Apps uses the new approach and don't save any copy of the file in any case. But some of them don't ask for Storage permission, and others stop to support the legacy getExternalStorageDirectory call.

Currently we implemented both approaches to pass the KML/GPX Files to Intent.ACTION_VIEW, but we are still using the old one by default. We use the new one only for Earth, that refuses to open files with the old method.

We set the use of Content Provider for Earth here:


You could enable it for your app (for testing purpose) by adding the following line to GPS Logger's exceptions:

if (a.PackageName.equals("YOUR_APP_PACKAGE")) a.requiresFileProvider = true;

We have in plan to enable the new method by Default (it could be enabled on the next App's Update), but we must first test the behaviour with all the apps we know are working as GPX/KML Viewer.
To enable it, is sufficient to set the following value to true:


In the future, when Google will force to update the API level to 30+, we will have to remove all the usages of the legacy APIs (like getExternalStorageDirectory) from GPS Logger in favour of new ones. But for now we are waiting a clearer guidelines.

@WRPSoft
Copy link
Author

WRPSoft commented Mar 4, 2021

Dear @GrazianoCapelli

Thank you very much for the really detailed answer. I've learned a lot reading your comment.

I already thought that all of this stuff is not so easy to handle because Google repeatedly throws all (former) file handling overboard (it seems that everything is deprecated in the Android world :-) :-( )

My app was initially file-based, after I had struggled through the Google Docs, I then switched the internal file handling completely to 'Uri based' handling because the file handling no longer worked well under some current Android versions (filename to uri conversion and vice versa is always a topic at stackoverflow.com).

I cached files beforehand in order to get access rights and to be able to open them in my app (as you described). Now most of this special handling is no more needed, but I still can't really make out all of Google's new guidelines.

It took me several days of trying out and put together the right intent filters for my app and the underlaying file handling.

Now everything seems to work relatively fine and after I have included 'requestLegacyExternalStorage = "true"' in the manifest, I can easily integrate my app as a viewer in GPS logger on Xiaomi's phones running under Android 10 too.
I will update my app in the Playstore the next days and first wait some time to see how the interaction with GPS Logger will work in the future. The two apps complement each other quite well, as both are very lightweight :-)

My conclusion: I've been in the professional software development for more than 25 years now (but no Android till now) and I've never stumbled upon so many deprecated traps as I do with Android.

I only do Android programming on a hobby basis, the much free time in the Corona crisis practically drove me to do it and I'm certainly still an Android beginner when it comes to programming, but in general regarding programming I think I'm a little bit skilled due of my daily work . But that doesn't help you with Android that much, because you always have to go back to start :-) Studying Android developer docs seems to be a life's work (writing Android programming guides too) :)

Thanks for sharing GPS Logger with us, it's really a great app!

Regards Ralph

This is my intent (file) handling (some code fragments):

  Intent intent = getIntent();
  if (intent == null)
      return false;

     ```
   String scheme = intent.getScheme();
   if (scheme == null)
      return false;
		
   if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0 || cheme.compareTo(ContentResolver.SCHEME_FILE) == 0) {

       // primarily for 'debugging' -> implementing and dealing with intent filters is really awful in Android 
       if (scheme.compareTo(ContentResolver.SCHEME_CONTENT) == 0)
                Toast.makeText(MainActivity.this, "Intent: ContentResolver", Toast.LENGTH_LONG).show();
       else if (scheme.compareTo(ContentResolver.SCHEME_FILE) == 0)
              Toast.makeText(MainActivity.this, "Intent: File", Toast.LENGTH_LONG).show();

       Uri uri = intent.getData();
       if (uri != null) {
	  xmltools.loadGPXFile(uri);
       }
}
		
public void loadGPXFile(Uri uri) throws FileNotFoundException {

        GPXParser mParser = new GPXParser();

	Gpx parsedGpx = null;
	try {
		// RW: 23.02.2021 migrate to Uri handling (Android programming means -> really everything will become deprecated sometime :( )
		// InputStream in = new FileInputStream(filename);
		InputStream in = mcontext.getContentResolver().openInputStream(uri);

		parsedGpx = mParser.parse(in);

	} catch (IOException | XmlPullParserException e) {
		// do something with this exception
		e.printStackTrace();
	}				

}

@GrazianoCapelli
Copy link
Member

Dear @WRPSoft

I found a WRPElevationChart on the Play Store: Hoping I'm not wrong, I assume you are speaking of it.
It is lightweight, without ads and in-app purchases. Very good job!
The App accepts the GPX format (our preferred for Viewers), and opens well both GPX 1.0 and 1.1 we export.
Among other things, I found a link to BasicAirData GPS Logger on About Screen (Thanks on behalf of the whole BasicAirData Team!).

We are happy to be aware of a free and compatible Track Viewer on the Play Store.
We added your app to the list of the compatible Viewers to be checked when we'll switch to FileProvider.

I haven't found any reference to License and any Issue Tracker, so I am writing to you here to report a small issue I faced with WRPElevationChart:
The first time your App is used as a Viewer it shows the Storage permission request but, if the File is in a position that requires that permission, it doesn't open it also if the permission is granted by the user.
Starting from the second time, when the permission has been yet granted, the App works perfectly as Viewer.

It seems that the method that opens the Track runs independently from the permission.
Let me explain better, considering the two cases:

  • If I try to send a file using the FileProvider, your app asks the Storage Permission also if it is not needed (because the file passed via FileProvider doesn't require Storage Permission), and in the meantime it opens the file in the Background.
  • Conversely, if I try to send the file with the old method - the File URI - that requires the Storage Permission, your App asks to grant it (this time the permission is needed to open the file, thus it is correct to ask for it) but, if I grant that permission, the Track is not open (i think because the method that opens the track runs before the permission has been granted, and is not deferred to onRequestPermissionsResult).

Please consider that the consideration I written here above is made without browsing your code, and could be wrong.
If you have an issue Tracker please consider to link it here: I will post this issue in the right place!

@WRPSoft
Copy link
Author

WRPSoft commented Mar 16, 2021

Dear @GrazianoCapelli,

Maybe I should have asked before referring to GPS Logger, but I've been a little pressed for time the past few days and really enjoy using GPS Logger. So I really wanted to refer to GPS logger app.

But I am glad that you are okay with that.

By the way, this is my first real Android app. Professionally, I work in desktop development and as said before, there are really many traps in the Android development world.

Thanks for the bug report and the nice words. Indeed there are still a few passages that I should revise a little more. In fact, when accessing files, I would have to consider the RequestPermissionsResult (at least when handling the intent).
Normally the permissions should be queried and assigned when the app is started for the first time, then it would fit if one assumes that the user opens the newly installed apps first. On the other hand, you're right, you should never assume a specific keyflow on the user side. The exception determines the rule in the IT world. :)

But all this permission management with regard to file handling is not so easy to do under Android, especially now that Google is again fundamentally changing some things.
And if I have understood correctly, an app do not need any special rights for file handling anymore if using FileProvider or/and the system file picker to select a file. But I will need the file permissions anyway for using the OSMDroid library, I assume.

I'll take a closer look this weekend, already knowing that I'll come across the words deprecated a few times again and again, but we have to deal with that :)
You see, I still have a to fight sometimes with Android, which acts like a ill-tempered diva at times.

@GrazianoCapelli
Copy link
Member

The incoming GPS Logger v3.0.0 will use the FileProvider by default to view tracks, also for WRPElevationChart.
We tested it, works like a charm.
We added some exceptions for the apps that still saves a local copy of the files when passed with the FileProvider, in order to avoid data duplication on the device, but it is a matter of time and we'll have to switch to this new method.

@WRPSoft
Copy link
Author

WRPSoft commented May 26, 2021

Hi @GrazianoCapelli,

The incoming GPS Logger v3.0.0 will use the FileProvider by default to view tracks, also for WRPElevationChart.
We tested it, works like a charm.

Nice to hear and thanks for the feedback and 'cooperation' :). I'm waiting for version 3.0.0 (my mother, who still do a lot of hiking, too) :)

We added some exceptions for the apps that still saves a local copy of the files when passed with the FileProvider, in order to avoid data duplication on the device, but it is a matter of time and we'll have to switch to this new method.

Just mentioned as a side note, Android programming runs on the side for me, so I'm certainly not that skilled in terms of system-specific things, but file handling is getting worse and worse under Android.

I implemented a small browser functionality that must scan GPS specific files in the download folder for example in order to be able to browse through them. Under Android >= 11, access to the download folder seems to be severely limited for Apps targeted to Android >= 11.
It will be difficult for small apps to get the corresponding extended rights for this functionality from Google if it is not a file manager or something like that app type.

Time for Google to offer its own MediaStore-like access for ALL GPS-based data types, otherwise it will get very complicated at some point: for developers but for user too.

@GrazianoCapelli
Copy link
Member

I close this issue because we opened the #141 and the #148 in order to discuss and implement the related features with the new Scoped Storage approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants