Android Stories. Source of truth.

What is it all about?

How many times did you spend hours to solve some dev problem? Speaking for myself: a lot. So my little stories will be all about this every-day investigations.

Sharing is caring

Monday, 1 pm, day was nice, lunch was delicious. Going to start new task, searching for good one to improve project and made user experience better. When your app is social net (in my case it is), you want people to have options for sharing things. Android is great in sharing, you just using Intents, preparing right action and right data structures, system will figure out itself who to address it (or user will with nice IntentChooser). This is what social app must have.

TICKET-1798: Not able to share to Instagram

Intents are good but they are not delivering files (photos/videos), only simple primitive data and one more problem is permissions, other app cannot read files from you sandbox directories. We have already used FileProvider, Lollipop feature, when you are able to share Uri for file and give other apps one-shot permission to use it. So that was the reported bug all about, FileProvider were not working properly. Logs (thx QA) showed that:

java.lang.IllegalArgumentException: Failed to find configured root that contains <path>

I know I know

“Yeah” - I said to myself. We’ve just recently changed paths for our file caches, just need to change config for FileProvider. Previous path was returned by Context.getCacheDir() and now it is Context.getExternalCacheDirs(). Looked into documentation to properly configure paths.

<external-cache-path name="name" path="path" />

Easy peasy, commit… push… I know, I know… but sometimes you just did. So I did, PR was merged, documentation was self-explanatory. Coffee, yeah, one cup with milk and sugar, just to reward myself.


Fail: reproduced with same steps

God help this QA, f#$@%, all has to work correctly. Ok, non-believer, lets reproduce it… sh%t, same error… why??? What is not correct, checking paths — correct, dirs names — correct, documentation again — all seems clear and correct. Ok, SODD, help me. All answers were pointing to things that I’ve re-checked already: dir names, paths, typos. But all SO examples were using file-path, cache-path and external-path, but not external-cache-path. Lets, revert to Context.getCacheDir(), it seemed to be working. Ok, working, now what? Why does external-cache-path not working, when it has to? Hour of change-compile-debug recursion showed that all working, but not what is needed. Thx to college with great idea — “try to look sources”. Its support-v4, it can be decompiled (at that time we were using target=24 without sources for awhile, but enough to become annoying and making you to get use to fact that there is no sources at hand)

Source of truth

And its the only one. FileProvider.java

...
if (TAG_ROOT_PATH.equals(tag)) {
target = buildPath(DEVICE_ROOT, path);
} else if (TAG_FILES_PATH.equals(tag)) {
target = buildPath(context.getFilesDir(), path);
} else if (TAG_CACHE_PATH.equals(tag)) {
target = buildPath(context.getCacheDir(), path);
} else if (TAG_EXTERNAL.equals(tag)) {
target = buildPath(Environment.getExternalStorageDirectory(), path);
}
...

These are processed paths. No external-cache-path at all =(. So there is wrong docs or implementation. To go deeper there is an opened issue about related problems, from 2013, reopened recently in June.

Hope

So that was long and exhausting 2 hours for simple one line (actually more that 5 lines, refactoring, you know) change. Hope next time I won’t forget, hope next time docs will be changed already.

Star the issue and thank you for reading.