0

So I'm trying to implement the new Storage Access Framework stuff introduced in Android 4.4 (KitKat). I've extended a DocumentsProvider class as described on YouTube, which works great when I try it on KitKat (API 19) devices. I have a content provider, and my app acts as a client-- it's a great file picker to replace the one I had to custom-write.

But when the code is run on older devices, such as API 8 (Froyo), it dies on launch with an error that looks like this:

E/AndroidRuntime(  702): FATAL EXCEPTION: main
E/AndroidRuntime(  702): java.lang.RuntimeException: Unable to get provider com.example.MyProvider: java.lang.ClassNotFoundException: com.example.MyProvider in loader dalvik.system.PathClassLoader[/data/app/com.example-2.apk]

Makes perfect sense-- The DocumentsProvider class was introduced in KitKat, so of course it doesn't run in Froyo (API 8).

To try to deal with older devices and make it fallback to the file picker I wrote previously, I wrapped all the code referencing MyProvider (my DocumentsProvider) with a if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) conditional... so you'd think I'd be safe...

Trouble is, DocumentsProvider requires the provider be registered in AndroidManifest.xml within a <provider> element. I see no way of saying "Ignore this and don't try to load MyProvider on older APIs." And I don't see any way of declaring <provider> programmatically either. Or any kind of legacy solution. It seems to be an all-or-nothing thing hard-coded into the Manifest.

If I remove the <provider> stuff from the manifest, the app runs perfectly in Froyo without errors (it's not trying to load or use DocumentsProvider at all). But I do need it there for KitKat to work with the new Storage Access stuff.

Anyone have any thoughts? Is it possible to use DocumentProvider in a way that it works on API >= 19 but is completely ignored on older devices? Some kind of tricky wrapper-class... or a stub ContentProvider class... or something? Whatever class I can get Froyo to think is there, it'll never get called/used, at least by my app.

Much thanks.

Community
  • 1
  • 1
fattire
  • 6,823
  • 3
  • 25
  • 38

1 Answers1

3

Define a boolean in your resources. Set it to true for api level 19, false for everything else.

So in res/values/bool.xml:

<item name="provider_enabled" type="bool">false</item>

In res/values-v19/bool.xml:

<item name="provider_enabled" type="bool">true</item>

Now in the Manifest, add the following to your provider:

android:enabled="@bool/provider_enabled"
Benito Bertoli
  • 25,285
  • 12
  • 54
  • 61
  • Holy cow. So easy. Last night I was trying to figure how to get a /values-v19 to apply to the manifest and had no idea you could do this-- it worked great. (I used the `` item for simplicity) Thanks. As soon as I get enough reputation points I'll be back to up-arrow this. – fattire Nov 26 '13 at 18:29
  • UPDATE: Oh wow-- a similar technique is actually suggested in the http://developer.android.com/guide/topics/providers/document-provider.html docs using a boolean called "atMostJellyBeanMR2" so anyone following those instructions might want to reuse it. – fattire Nov 26 '13 at 18:39
  • --never mind, don't re-use it. It's false when you want it to be true, and vice-versa. Just set up another bool :) – fattire Nov 29 '13 at 02:04