Add the option to create local files for the album art

The data for those files still comes from the application's assets,
but this illustrates what to do with bytes that would be received from
a remote uri.

Test: manual

Change-Id: I5fa590d632df477df215231319e40bd05f5eb90b
diff --git a/TestMediaApp/AndroidManifest.xml b/TestMediaApp/AndroidManifest.xml
index 09e850c..911145e 100644
--- a/TestMediaApp/AndroidManifest.xml
+++ b/TestMediaApp/AndroidManifest.xml
@@ -28,10 +28,11 @@
         android:supportsRtl="true"
         android:theme="@style/TestMediaAppTheme" >
 
+        <!-- This provider is read-only, only returns album art, and is not a security risk -->
         <provider
-            android:name=".TmaAssetProvider"
+            android:name=".TmaPublicProvider"
             android:exported="true"
-            android:authorities="com.android.car.media.testmediaapp.assets"/>
+            android:authorities="com.android.car.media.testmediaapp.public"/>
 
         <service
             android:name=".TmaBrowser"
diff --git a/TestMediaApp/assets/media_items/album_art/art_nodes.json b/TestMediaApp/assets/media_items/album_art/art_nodes.json
index 434ed23..974268b 100644
--- a/TestMediaApp/assets/media_items/album_art/art_nodes.json
+++ b/TestMediaApp/assets/media_items/album_art/art_nodes.json
@@ -52,6 +52,15 @@
         "DISPLAY_TITLE": "Nature 1024"
       },
       "INCLUDE":"media_items/album_art/nature/art_nature_1024.json"
+    },
+    {
+      "FLAGS": "browsable",
+      "PLAYABLE_HINT": "GRID",
+      "METADATA": {
+        "MEDIA_ID": "album_art/art_nodes nature files",
+        "DISPLAY_TITLE": "Nature files"
+      },
+      "INCLUDE":"media_items/album_art/nature/art_nature_files.json"
     }
   ]
 }
\ No newline at end of file
diff --git a/TestMediaApp/assets/media_items/album_art/nature/art_nature_1024.json b/TestMediaApp/assets/media_items/album_art/nature/art_nature_1024.json
index b1759f2..c34ed80 100644
--- a/TestMediaApp/assets/media_items/album_art/nature/art_nature_1024.json
+++ b/TestMediaApp/assets/media_items/album_art/nature/art_nature_1024.json
@@ -13,7 +13,7 @@
         "MEDIA_ID": "art_nature_1024_leaves bee",
         "DISPLAY_TITLE": "Bee",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/bee.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/bee.jpg"
       }
     },
     {
@@ -22,7 +22,7 @@
         "MEDIA_ID": "art_nature_1024_leaves clouds",
         "DISPLAY_TITLE": "Clouds",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/clouds.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/clouds.jpg"
       }
     },
     {
@@ -31,7 +31,7 @@
         "MEDIA_ID": "art_nature_1024_leaves flower1",
         "DISPLAY_TITLE": "Flower 1",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/flower1.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/flower1.jpg"
       }
     },
     {
@@ -40,7 +40,7 @@
         "MEDIA_ID": "art_nature_1024_leaves flower2",
         "DISPLAY_TITLE": "Flower 2",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/flower2.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/flower2.jpg"
       }
     },
     {
@@ -49,7 +49,7 @@
         "MEDIA_ID": "art_nature_1024_leaves flower3",
         "DISPLAY_TITLE": "Flower3 ",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/flower3.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/flower3.jpg"
       }
     },
     {
@@ -58,7 +58,7 @@
         "MEDIA_ID": "art_nature_1024_leaves flowers",
         "DISPLAY_TITLE": "Flowers",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/flowers.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/flowers.jpg"
       }
     },
     {
@@ -67,7 +67,7 @@
         "MEDIA_ID": "art_nature_1024_leaves leaves",
         "DISPLAY_TITLE": "Leaves",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/leaves.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/leaves.jpg"
       }
     },
     {
@@ -76,7 +76,7 @@
         "MEDIA_ID": "art_nature_1024_leaves sage",
         "DISPLAY_TITLE": "Sage",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/sage.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/sage.jpg"
       }
     },
     {
@@ -85,7 +85,7 @@
         "MEDIA_ID": "art_nature_1024_leaves tree",
         "DISPLAY_TITLE": "Tree",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-1024/tree.jpg"
+        "ART_URI": "assets/bitmaps/nature-1024/tree.jpg"
       }
     }
   ]
diff --git a/TestMediaApp/assets/media_items/album_art/nature/art_nature_128.json b/TestMediaApp/assets/media_items/album_art/nature/art_nature_128.json
index 0fdd629..67200e8 100644
--- a/TestMediaApp/assets/media_items/album_art/nature/art_nature_128.json
+++ b/TestMediaApp/assets/media_items/album_art/nature/art_nature_128.json
@@ -13,7 +13,7 @@
         "MEDIA_ID": "art_nature_128 bee",
         "DISPLAY_TITLE": "Bee",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/bee.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/bee.jpg"
       }
     },
     {
@@ -22,7 +22,7 @@
         "MEDIA_ID": "art_nature_128 clouds",
         "DISPLAY_TITLE": "Clouds",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/clouds.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/clouds.jpg"
       }
     },
     {
@@ -31,7 +31,7 @@
         "MEDIA_ID": "art_nature_128 flower1",
         "DISPLAY_TITLE": "Flower 1",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/flower1.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/flower1.jpg"
       }
     },
     {
@@ -40,7 +40,7 @@
         "MEDIA_ID": "art_nature_128 flower2",
         "DISPLAY_TITLE": "Flower 2",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/flower2.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/flower2.jpg"
       }
     },
     {
@@ -49,7 +49,7 @@
         "MEDIA_ID": "art_nature_128 flower3",
         "DISPLAY_TITLE": "Flower3 ",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/flower3.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/flower3.jpg"
       }
     },
     {
@@ -58,7 +58,7 @@
         "MEDIA_ID": "art_nature_128 flowers",
         "DISPLAY_TITLE": "Flowers",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/flowers.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/flowers.jpg"
       }
     },
     {
@@ -67,7 +67,7 @@
         "MEDIA_ID": "art_nature_128 leaves",
         "DISPLAY_TITLE": "Leaves",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/leaves.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/leaves.jpg"
       }
     },
     {
@@ -76,7 +76,7 @@
         "MEDIA_ID": "art_nature_128 sage",
         "DISPLAY_TITLE": "Sage",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/sage.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/sage.jpg"
       }
     },
     {
@@ -85,7 +85,7 @@
         "MEDIA_ID": "art_nature_128 tree",
         "DISPLAY_TITLE": "Tree",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-128/tree.jpg"
+        "ART_URI": "assets/bitmaps/nature-128/tree.jpg"
       }
     }
   ]
diff --git a/TestMediaApp/assets/media_items/album_art/nature/art_nature_256.json b/TestMediaApp/assets/media_items/album_art/nature/art_nature_256.json
index 200ecc1..719665e 100644
--- a/TestMediaApp/assets/media_items/album_art/nature/art_nature_256.json
+++ b/TestMediaApp/assets/media_items/album_art/nature/art_nature_256.json
@@ -13,7 +13,7 @@
         "MEDIA_ID": "art_nature_256 bee",
         "DISPLAY_TITLE": "Bee",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/bee.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/bee.jpg"
       }
     },
     {
@@ -22,7 +22,7 @@
         "MEDIA_ID": "art_nature_256 clouds",
         "DISPLAY_TITLE": "Clouds",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/clouds.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/clouds.jpg"
       }
     },
     {
@@ -31,7 +31,7 @@
         "MEDIA_ID": "art_nature_256 flower1",
         "DISPLAY_TITLE": "Flower 1",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/flower1.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/flower1.jpg"
       }
     },
     {
@@ -40,7 +40,7 @@
         "MEDIA_ID": "art_nature_256 flower2",
         "DISPLAY_TITLE": "Flower 2",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/flower2.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/flower2.jpg"
       }
     },
     {
@@ -49,7 +49,7 @@
         "MEDIA_ID": "art_nature_256 flower3",
         "DISPLAY_TITLE": "Flower3 ",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/flower3.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/flower3.jpg"
       }
     },
     {
@@ -58,7 +58,7 @@
         "MEDIA_ID": "art_nature_256 flowers",
         "DISPLAY_TITLE": "Flowers",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/flowers.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/flowers.jpg"
       }
     },
     {
@@ -67,7 +67,7 @@
         "MEDIA_ID": "art_nature_256 leaves",
         "DISPLAY_TITLE": "Leaves",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/leaves.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/leaves.jpg"
       }
     },
     {
@@ -76,7 +76,7 @@
         "MEDIA_ID": "art_nature_256 sage",
         "DISPLAY_TITLE": "Sage",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/sage.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/sage.jpg"
       }
     },
     {
@@ -85,7 +85,7 @@
         "MEDIA_ID": "art_nature_256 tree",
         "DISPLAY_TITLE": "Tree",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-256/tree.jpg"
+        "ART_URI": "assets/bitmaps/nature-256/tree.jpg"
       }
     }
   ]
diff --git a/TestMediaApp/assets/media_items/album_art/nature/art_nature_512.json b/TestMediaApp/assets/media_items/album_art/nature/art_nature_512.json
index 56bb6a4..29cb783 100644
--- a/TestMediaApp/assets/media_items/album_art/nature/art_nature_512.json
+++ b/TestMediaApp/assets/media_items/album_art/nature/art_nature_512.json
@@ -13,7 +13,7 @@
         "MEDIA_ID": "art_nature_512 bee",
         "DISPLAY_TITLE": "Bee",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/bee.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/bee.jpg"
       }
     },
     {
@@ -22,7 +22,7 @@
         "MEDIA_ID": "art_nature_512 clouds",
         "DISPLAY_TITLE": "Clouds",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/clouds.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/clouds.jpg"
       }
     },
     {
@@ -31,7 +31,7 @@
         "MEDIA_ID": "art_nature_512 flower1",
         "DISPLAY_TITLE": "Flower 1",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/flower1.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/flower1.jpg"
       }
     },
     {
@@ -40,7 +40,7 @@
         "MEDIA_ID": "art_nature_512 flower2",
         "DISPLAY_TITLE": "Flower 2",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/flower2.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/flower2.jpg"
       }
     },
     {
@@ -49,7 +49,7 @@
         "MEDIA_ID": "art_nature_512 flower3",
         "DISPLAY_TITLE": "Flower3 ",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/flower3.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/flower3.jpg"
       }
     },
     {
@@ -58,7 +58,7 @@
         "MEDIA_ID": "art_nature_512 flowers",
         "DISPLAY_TITLE": "Flowers",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/flowers.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/flowers.jpg"
       }
     },
     {
@@ -67,7 +67,7 @@
         "MEDIA_ID": "art_nature_512 leaves",
         "DISPLAY_TITLE": "Leaves",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/leaves.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/leaves.jpg"
       }
     },
     {
@@ -76,7 +76,7 @@
         "MEDIA_ID": "art_nature_512 sage",
         "DISPLAY_TITLE": "Sage",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/sage.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/sage.jpg"
       }
     },
     {
@@ -85,7 +85,7 @@
         "MEDIA_ID": "art_nature_512 tree",
         "DISPLAY_TITLE": "Tree",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-512/tree.jpg"
+        "ART_URI": "assets/bitmaps/nature-512/tree.jpg"
       }
     }
   ]
diff --git a/TestMediaApp/assets/media_items/album_art/nature/art_nature_64.json b/TestMediaApp/assets/media_items/album_art/nature/art_nature_64.json
index 913dd07..72a3f41 100644
--- a/TestMediaApp/assets/media_items/album_art/nature/art_nature_64.json
+++ b/TestMediaApp/assets/media_items/album_art/nature/art_nature_64.json
@@ -13,7 +13,7 @@
         "MEDIA_ID": "art_nature_64 bee",
         "DISPLAY_TITLE": "Bee",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/bee.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/bee.jpg"
       }
     },
     {
@@ -22,7 +22,7 @@
         "MEDIA_ID": "art_nature_64 clouds",
         "DISPLAY_TITLE": "Clouds",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/clouds.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/clouds.jpg"
       }
     },
     {
@@ -31,7 +31,7 @@
         "MEDIA_ID": "art_nature_64 flower1",
         "DISPLAY_TITLE": "Flower 1",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/flower1.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/flower1.jpg"
       }
     },
     {
@@ -40,7 +40,7 @@
         "MEDIA_ID": "art_nature_64 flower2",
         "DISPLAY_TITLE": "Flower 2",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/flower2.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/flower2.jpg"
       }
     },
     {
@@ -49,7 +49,7 @@
         "MEDIA_ID": "art_nature_64 flower3",
         "DISPLAY_TITLE": "Flower3 ",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/flower3.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/flower3.jpg"
       }
     },
     {
@@ -58,7 +58,7 @@
         "MEDIA_ID": "art_nature_64 flowers",
         "DISPLAY_TITLE": "Flowers",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/flowers.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/flowers.jpg"
       }
     },
     {
@@ -67,7 +67,7 @@
         "MEDIA_ID": "art_nature_64 leaves",
         "DISPLAY_TITLE": "Leaves",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/leaves.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/leaves.jpg"
       }
     },
     {
@@ -76,7 +76,7 @@
         "MEDIA_ID": "art_nature_64 sage",
         "DISPLAY_TITLE": "Sage",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/sage.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/sage.jpg"
       }
     },
     {
@@ -85,7 +85,7 @@
         "MEDIA_ID": "art_nature_64 tree",
         "DISPLAY_TITLE": "Tree",
         "DURATION": 10000,
-        "ART_URI": "bitmaps/nature-64/tree.jpg"
+        "ART_URI": "assets/bitmaps/nature-64/tree.jpg"
       }
     }
   ]
diff --git a/TestMediaApp/assets/media_items/album_art/nature/art_nature_files.json b/TestMediaApp/assets/media_items/album_art/nature/art_nature_files.json
new file mode 100644
index 0000000..2643829
--- /dev/null
+++ b/TestMediaApp/assets/media_items/album_art/nature/art_nature_files.json
@@ -0,0 +1,92 @@
+{
+  "FLAGS": "browsable",
+
+  "METADATA": {
+    "MEDIA_ID": "art_nature_files_leaves",
+    "DISPLAY_TITLE": "Art nature files"
+  },
+
+  "CHILDREN": [
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves bee",
+        "DISPLAY_TITLE": "Bee",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/bee.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves clouds",
+        "DISPLAY_TITLE": "Clouds",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/clouds.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves flower1",
+        "DISPLAY_TITLE": "Flower 1",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/flower1.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves flower2",
+        "DISPLAY_TITLE": "Flower 2",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/flower2.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves flower3",
+        "DISPLAY_TITLE": "Flower3 ",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/flower3.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves flowers",
+        "DISPLAY_TITLE": "Flowers",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/flowers.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves leaves",
+        "DISPLAY_TITLE": "Leaves",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/leaves.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves sage",
+        "DISPLAY_TITLE": "Sage",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/sage.jpg"
+      }
+    },
+    {
+      "FLAGS": "playable",
+      "METADATA": {
+        "MEDIA_ID": "art_nature_files_leaves tree",
+        "DISPLAY_TITLE": "Tree",
+        "DURATION": 10000,
+        "ART_URI": "files/bitmaps/nature-1024/tree.jpg"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaAssetProvider.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaAssetProvider.java
deleted file mode 100644
index fc9fd49..0000000
--- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaAssetProvider.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.car.media.testmediaapp;
-
-import android.content.ContentProvider;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.car.media.testmediaapp.prefs.TmaPrefs;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-public class TmaAssetProvider extends ContentProvider {
-
-    private static final String TAG = "TmaAssetProvider";
-
-    private static final String PACKAGE_NAME = "com.android.car.media.testmediaapp";
-
-    private static final String ASSET_URI_PREFIX =
-            ContentResolver.SCHEME_CONTENT + "://" + PACKAGE_NAME + ".assets/";
-
-    private static final String RESOURCE_URI_PREFIX =
-            ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + PACKAGE_NAME + "/";
-
-
-    public static String buildUriString(String localArt) {
-        String prefix = localArt.startsWith("drawable") ? RESOURCE_URI_PREFIX : ASSET_URI_PREFIX;
-        return prefix + localArt;
-    }
-
-    private int mAssetDelay = 0;
-
-    @Override
-    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
-        Log.i(TAG, "TmaAssetProvider#openAssetFile " + uri);
-
-        try {
-            Thread.sleep(mAssetDelay + (int)(mAssetDelay * (Math.random())));
-        } catch (InterruptedException ignored) {
-        }
-
-        String file_path = uri.getPath();
-        if (TextUtils.isEmpty(file_path)) throw new FileNotFoundException();
-        try {
-            if (file_path.startsWith("/")) {
-                file_path = file_path.substring(1);
-            }
-            return getContext().getAssets().openFd(file_path);
-        } catch (IOException e) {
-            Log.e(TAG, "openAssetFile failed: " + e);
-            return null;
-        }
-    }
-
-    @Override
-    public boolean onCreate() {
-        TmaPrefs.getInstance(getContext()).mAssetReplyDelay.registerChangeListener(
-                (oldValue, newValue) -> mAssetDelay = newValue.mReplyDelayMs);
-        return true;
-    }
-
-    @Override
-    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
-            String sortOrder) {
-        return null;
-    }
-
-    @Override
-    public String getType(Uri uri) {
-        return null;
-    }
-
-    @Override
-    public Uri insert(Uri uri, ContentValues values) {
-        return null;
-    }
-
-    @Override
-    public int delete(Uri uri, String selection, String[] selectionArgs) {
-        return 0;
-    }
-
-    @Override
-    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
-        return 0;
-    }
-}
diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPublicProvider.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPublicProvider.java
new file mode 100644
index 0000000..e7eb31b
--- /dev/null
+++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPublicProvider.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.car.media.testmediaapp;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.car.media.testmediaapp.prefs.TmaPrefs;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class TmaPublicProvider extends ContentProvider {
+
+    private static final String TAG = "TmaAssetProvider";
+
+    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
+    private static final String AUTHORITY = "com.android.car.media.testmediaapp.public";
+
+    private static final String FILES = "/files/";
+    private static final String ASSETS = "/assets/";
+
+    private static final String CONTENT_URI_PREFIX =
+            ContentResolver.SCHEME_CONTENT + "://" + AUTHORITY + "/";
+
+    private static final String RESOURCE_URI_PREFIX =
+            ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + AUTHORITY + "/";
+
+
+    public static String buildUriString(String localArt) {
+        String prefix = localArt.startsWith("drawable") ? RESOURCE_URI_PREFIX : CONTENT_URI_PREFIX;
+        return prefix + localArt;
+    }
+
+    private int mAssetDelay = 0;
+
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
+        String path = uri.getPath();
+
+        if (TextUtils.isEmpty(path) || !path.startsWith(FILES)) {
+            throw new FileNotFoundException(path);
+        }
+
+        Log.i(TAG, "TmaAssetProvider#openFile uri: " + uri + " path: " + path);
+
+        File localFile = new File(getContext().getFilesDir(), path);
+        if (!localFile.exists()) {
+            downloadFile(localFile, path.substring(FILES.length()));
+        }
+
+        return ParcelFileDescriptor.open(localFile,ParcelFileDescriptor.MODE_READ_ONLY);
+    }
+
+    @Override
+    public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
+        String path = uri.getPath();
+        if (TextUtils.isEmpty(path) || !path.startsWith(ASSETS)) {
+            // The ImageDecoder and media center code always try to open as asset first, but
+            // super delegates to openFile...
+            return super.openAssetFile(uri, mode);
+        }
+
+        Log.i(TAG, "TmaAssetProvider#openAssetFile uri: " + uri + " path: " + path);
+
+        try {
+            Thread.sleep(mAssetDelay + (int)(mAssetDelay * (Math.random())));
+        } catch (InterruptedException ignored) {
+        }
+
+        try {
+            return getContext().getAssets().openFd(path.substring(ASSETS.length()));
+        } catch (IOException e) {
+            Log.e(TAG, "openAssetFile failed: " + e);
+            return null;
+        }
+    }
+
+    private void downloadFile(File localFile, String assetsPath) {
+        try {
+            localFile.getParentFile().mkdirs();
+
+            InputStream input = getContext().getAssets().open(assetsPath);
+            OutputStream output = new FileOutputStream(localFile);
+
+            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
+            int n;
+            while (-1 != (n = input.read(buffer))) {
+                output.write(buffer, 0, n);
+            }
+
+        } catch (IOException e) {
+            Log.e(TAG, "downloadFile failed: " + e);
+        }
+    }
+
+    @Override
+    public boolean onCreate() {
+        TmaPrefs.getInstance(getContext()).mAssetReplyDelay.registerChangeListener(
+                (oldValue, newValue) -> mAssetDelay = newValue.mReplyDelayMs);
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return null;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/loader/TmaMediaMetadataReader.java b/TestMediaApp/src/com/android/car/media/testmediaapp/loader/TmaMediaMetadataReader.java
index 5a4a217..8cc4843 100644
--- a/TestMediaApp/src/com/android/car/media/testmediaapp/loader/TmaMediaMetadataReader.java
+++ b/TestMediaApp/src/com/android/car/media/testmediaapp/loader/TmaMediaMetadataReader.java
@@ -53,7 +53,7 @@
 import android.support.v4.media.MediaMetadataCompat;
 import android.util.Log;
 
-import com.android.car.media.testmediaapp.TmaAssetProvider;
+import com.android.car.media.testmediaapp.TmaPublicProvider;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -153,7 +153,7 @@
                     case TEXT:
                         String value = object.getString(jsonKey);
                         if (mUriKeys.contains(key)) {
-                            value = TmaAssetProvider.buildUriString(value);
+                            value = TmaPublicProvider.buildUriString(value);
                         }
                         builder.putString(key.mLongName, value);
                         break;