More on the Missing SAF

Last week, I mentioned:

The biggest is that device manufacturers may unilaterally eliminate the Storage Access Framework, by removing or replacing the activities that handle ACTION_OPEN_DOCUMENT and kin. Hopefully, manufacturers will stop doing this, as Android and its apps become more reliant on SAF. However, since Google does not seem to test whether devices support SAF, there is no real pressure for device manufacturers to allow SAF to function.

The link in that quoted section points to an issue that I filed two years ago, around the time that I wrote my original post about the missing SAF. I had not received any significant response to that issue… until this past Wednesday, when I found out that Google does indeed test SAF.

Sometimes.

So, first, I would like to apologize for mis-interpreting the original lack of response to my issue and for mis-interpreting the problem.

However, the response to the issue serves as a useful illustration of why we have compatibility problems despite the Compatibility Test Suite (CTS).


To the best of my knowledge, there is no iCanHazSAF() method, or the equivalent, anywhere in the Android SDK, to tell us if the device supports the Storage Access Framework. Similarly, there is no <uses-feature> value for this, the way there is for app widgets or WebView.

The closest thing that we had is to see if the device supports whatever SAF Intent action(s) we want to use, such as using resolveActivity() on Intent. If that returns null, we know that we cannot successfully start that activity. In principle, some users might not have access to SAF activities due to restricted profile configuration (e.g., work profiles). So, we should be checking for the availability of these activities before starting them, just in case.

(in reality, not everyone does this, and I’m as bad as anyone at forgetting to check these particular Intent actions)

So, from a compatibility standpoint, historically developers were stuck with:

  • If the SAF Intent actions resolve, assume that the activities work correctly

  • Hope that devices that do not support the SAF do not export activities that match the SAF Intent structure

Unfortunately, that second bullet did not hold true in practice, as my SAF issue points out.


Earlier, I said that Google tests the SAF in the CTS “sometimes”. Wednesday’s issue update states:

These intents have been very thoroughly CTS tested since they were first introduced in Android KitKat, so you can rely on them on all handheld devices. However, certain product teams have decided that these intents are not needed on their products (such as watches and TVs), which is why the tests are skipped on those devices.

It was great to hear that CTS does test the SAF, at least on most devices. However, the described testing does not quite match what developers need.

Ideally, testing would look like this (using the Google engineer’s terminology for device types):

  • On a handheld device, the SAF Intent actions MUST resolve and their activities MUST work

  • On a watch or TV, the SAF Intent actions MAY resolve, but if they do resolve their activities MUST work

The comment suggests that the testing is more akin to:

  • On a handheld device, the SAF Intent actions MUST resolve and their activities MUST work

  • On a watch or TV, ¯\_(ツ)_/¯

This is what burns developers on TVs. Some device manufacturers (e.g., Xiaomi) exported activities matching the SAF Intent structure but without actually allowing the user to perform SAF actions. This passes the CTS, because the CTS skips these tests on TV devices. And so we try starting the SAF activities on these broken devices and get poor results.

I can understand why Google does not want to enforce SAF requirements on watches. I’m less convinced about the TV argument, and as another issue comment points out, without SAF on TVs, our ability to access public portions of external storage is really limited. But I could live with TVs not supporting SAF. The bigger problem is the fact that there is no clear-cut way to determine if the SAF is supported on a device and no clear-cut testing to ensure that devices that claim to support the SAF really do.

If we assume that the statement from the Google engineer is literally true, then we “know” whether SAF is available or not based on hardware type:

  • android.hardware.type.television = no (even though some devices might actually support it)

  • android.hardware.type.watch = no

  • android.hardware.type.automotive = technically ¯\_(ツ)_/¯, but you hopefully are not trying to collect significant user input in this mode anyway

  • others = technically ¯\_(ツ)_/¯, but since there is no explicit hardware type for handheld devices, we have to treat this as “yes”

Unfortunately, AFAIK, this is not documented, and we do not know if this is really what Google wants and what device manufacturers are honoring. Plus, having the vast majority of devices covered by ¯\_(ツ)_/¯ does not inspire confidence. But, it is probably our best solution right now.


There is no nefarious intent here (not even a nefarious Intent). This is just another example of edge and corner cases not being covered in specifications, testing, or both. This sort of thing abounds in software development; this SAF scenario is far from unique. It’s just that at “Android scale”, even edge and corner cases might represent a million users or more. This is why “Android scale” compatibility is hard, and why we developers run into problems despite Google’s best and earnest efforts.


Nervous about how the newest version of Android affects your app? Consider subscribing, then asking questions in the office hours chats!