diff options
author | Xin Li <delphij@google.com> | 2020-01-15 15:57:17 -0800 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2020-01-15 15:57:17 -0800 |
commit | 3557a778993e52bf09ecfd2a34bfbb0d0679434a (patch) | |
tree | 22100ba5cdb818c16176753d8d1a4e20c3bef2fd | |
parent | bce842520fac7251dc4304acdd1027a87f53435b (diff) | |
parent | 45c2c0739532323ae599711983757569521d01c4 (diff) | |
download | tests-3557a778993e52bf09ecfd2a34bfbb0d0679434a.tar.gz |
DO NOT MERGE - Merge qt-qpr1-dev-plus-aosp-without-vendor (6129114) into stage-aosp-master
Bug: 146167222
Change-Id: I4c6e148432af216977a7970c6f8771f52cd17265
23 files changed, 369 insertions, 84 deletions
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/advanced.json b/TestMediaApp/assets/media_items/advanced.json index a6befa3..45a18ef 100644 --- a/TestMediaApp/assets/media_items/advanced.json +++ b/TestMediaApp/assets/media_items/advanced.json @@ -39,7 +39,7 @@ }, { "FLAGS": "browsable", - "PLAYABLE_HINT": "GRID", + "BROWSABLE_HINT": "GRID_CATEGORY", "METADATA": { "MEDIA_ID": "advanced art nodes", "DISPLAY_TITLE": "Album Art" diff --git a/TestMediaApp/assets/media_items/album_art/art_nodes.json b/TestMediaApp/assets/media_items/album_art/art_nodes.json index 434ed23..692809f 100644 --- a/TestMediaApp/assets/media_items/album_art/art_nodes.json +++ b/TestMediaApp/assets/media_items/album_art/art_nodes.json @@ -1,6 +1,6 @@ { "FLAGS": "browsable", - "BROWSABLE_HINT": "LIST", + "BROWSABLE_HINT": "GRID_CATEGORY", "METADATA": { "MEDIA_ID": "album_art/art_nodes", @@ -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/assets/media_items/mixed.json b/TestMediaApp/assets/media_items/mixed.json index 7e04e85..34da9c9 100644 --- a/TestMediaApp/assets/media_items/mixed.json +++ b/TestMediaApp/assets/media_items/mixed.json @@ -1,7 +1,7 @@ { "FLAGS": "browsable", "PLAYABLE_HINT": "GRID", - "BROWSABLE_HINT": "LIST", + "BROWSABLE_HINT": "LIST_CATEGORY", "METADATA": { "MEDIA_ID": "mixed", diff --git a/TestMediaApp/assets/media_items/only_nodes.json b/TestMediaApp/assets/media_items/only_nodes.json index a020abd..26f998e 100644 --- a/TestMediaApp/assets/media_items/only_nodes.json +++ b/TestMediaApp/assets/media_items/only_nodes.json @@ -32,7 +32,7 @@ { "FLAGS": "browsable", "PLAYABLE_HINT": "GRID", - "BROWSABLE_HINT": "LIST", + "BROWSABLE_HINT": "LIST_CATEGORY", "METADATA": { "MEDIA_ID": "only_nodes rabbit hole", "DISPLAY_TITLE": "Rabbit hole 2" diff --git a/TestMediaApp/assets/media_items/simple_leaves.json b/TestMediaApp/assets/media_items/simple_leaves.json index e666c1b..dc6b0a3 100644 --- a/TestMediaApp/assets/media_items/simple_leaves.json +++ b/TestMediaApp/assets/media_items/simple_leaves.json @@ -11,7 +11,7 @@ "FLAGS": "playable", "METADATA": { "MEDIA_ID": "simple_leaves normal 10s song", - "DISPLAY_TITLE": "A normal 10s song", + "DISPLAY_TITLE": "A normal 10s song with a long title. A normal 10s song with a long title. A normal 10s song with a long title. ", "DURATION": 10000 } }, @@ -20,6 +20,8 @@ "METADATA": { "MEDIA_ID": "simple_leaves normal 1H song", "DISPLAY_TITLE": "A normal 1H song", + "ARTIST": "Artist", + "ALBUM":"Album", "DURATION": 3600000 } }, @@ -28,6 +30,9 @@ "METADATA": { "MEDIA_ID": "simple_leaves slow connection", "DISPLAY_TITLE": "Connects and buffers for 4s each", + "DISPLAY_SUBTITLE": "A very long subtitle. A very long subtitle. A very long subtitle. A very long subtitle. A very long subtitle. A very long subtitle. ", + "ARTIST": "This is a very long artist name. This is a very long artist name. This is a very long artist name.", + "ALBUM":"Album", "DURATION": 30000 }, "EVENTS": [ @@ -41,6 +46,7 @@ "METADATA": { "MEDIA_ID": "simple_leaves poor internet", "DISPLAY_TITLE": "Poor internet quality at 2s", + "ARTIST": "Artist", "DURATION": 30000 }, "EVENTS": [ @@ -58,6 +64,8 @@ "METADATA": { "MEDIA_ID": "simple_leaves cache failure", "DISPLAY_TITLE": "Caching failure at 2s", + "DISPLAY_SUBTITLE": "Show a toast", + "ALBUM":"This is a very long album title. This is a very long album title. This is a very long album title.", "DURATION": 30000 }, "EVENTS": [ @@ -75,6 +83,7 @@ "METADATA": { "MEDIA_ID": "simple_leaves error code", "DISPLAY_TITLE": "Parental Control error code at 1s", + "DISPLAY_SUBTITLE": "Show a toast", "DURATION": 10000 }, "EVENTS": [ @@ -91,6 +100,7 @@ "METADATA": { "MEDIA_ID": "simple_leaves premium required", "DISPLAY_TITLE": "Paid account required at 1s", + "DISPLAY_SUBTITLE": "Show a dialog", "DURATION": 50000 }, "EVENTS": [ diff --git a/TestMediaApp/assets/media_items/single_node.json b/TestMediaApp/assets/media_items/single_node.json new file mode 100644 index 0000000..cf93cee --- /dev/null +++ b/TestMediaApp/assets/media_items/single_node.json @@ -0,0 +1,22 @@ +{ + "FLAGS": "browsable", + "PLAYABLE_HINT": "LIST", + "BROWSABLE_HINT": "GRID", + + "METADATA": { + "MEDIA_ID": "single_node", + "DISPLAY_TITLE": "A lonely tab" + }, + + "CHILDREN": [ + { + "FLAGS": "browsable", + "METADATA": { + "MEDIA_ID": "single_node simple_leaves", + "DISPLAY_TITLE": "Basic songs", + "ART_URI": "drawable/ic_heart_plus_plus" + }, + "INCLUDE":"media_items/simple_leaves.json" + } + ] +}
\ No newline at end of file diff --git a/TestMediaApp/assets/media_items/untagged.json b/TestMediaApp/assets/media_items/untagged.json new file mode 100644 index 0000000..fd8f5f5 --- /dev/null +++ b/TestMediaApp/assets/media_items/untagged.json @@ -0,0 +1,27 @@ +{ + "FLAGS": "browsable", + + "METADATA": { + "MEDIA_ID": "untagged", + "DISPLAY_TITLE": "Untagged media items" + }, + + "CHILDREN": [ + { + "METADATA": { + "MEDIA_ID": "untagged normal 10s song", + "DISPLAY_TITLE": "A normal 10s song with a long title. A normal 10s song with a long title. A normal 10s song with a long title. ", + "DURATION": 10000 + } + }, + { + "METADATA": { + "MEDIA_ID": "untagged normal 1H song", + "DISPLAY_TITLE": "A normal 1H song", + "ARTIST": "Artist", + "ALBUM":"Album", + "DURATION": 3600000 + } + } + ] +} diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/MediaKeys.java b/TestMediaApp/src/com/android/car/media/testmediaapp/MediaKeys.java index 8506b6b..9fba1a8 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/MediaKeys.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/MediaKeys.java @@ -22,6 +22,10 @@ package com.android.car.media.testmediaapp; */ public class MediaKeys { + /** Integer extra indicating the recommended size (in pixels) for media art bitmaps. */ + public static final String EXTRA_MEDIA_ART_SIZE_HINT_PIXELS = + "android.media.extras.MEDIA_ART_SIZE_HINT_PIXELS"; + /** * Bundle extra holding the Pending Intent to launch to let users resolve the current error. * See {@link #ERROR_RESOLUTION_ACTION_LABEL} for more details. @@ -61,4 +65,18 @@ public class MediaKeys { * hints the corresponding items should be presented as grids. */ static final int CONTENT_STYLE_GRID_ITEM_HINT_VALUE = 2; + + /** + * Value for {@link #CONTENT_STYLE_BROWSABLE_HINT} that hints the corresponding items should be + * presented as a "category" list, where media items are browsable and represented by a + * meaningful icon. + */ + public static final int CONTENT_STYLE_CATEGORY_LIST_ITEM_HINT_VALUE = 3; + + /** + * Value for {@link #CONTENT_STYLE_BROWSABLE_HINT} that hints the corresponding items should be + * presented as a "category" grid, where media items are browsable and represented by a + * meaningful icon. + */ + public static final int CONTENT_STYLE_CATEGORY_GRID_ITEM_HINT_VALUE = 4; } diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaBrowser.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaBrowser.java index 02e8292..7a62137 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaBrowser.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaBrowser.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.support.v4.media.MediaBrowserCompat.MediaItem; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -38,6 +39,8 @@ import com.android.car.media.testmediaapp.prefs.TmaPrefs; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** @@ -49,10 +52,17 @@ import java.util.List; * {@link TmaPlayer}. */ public class TmaBrowser extends MediaBrowserServiceCompat { + private static final String TAG = "TmaBrowser"; + private static final int MAX_SEARCH_DEPTH = 4; private static final String MEDIA_SESSION_TAG = "TEST_MEDIA_SESSION"; private static final String ROOT_ID = "_ROOT_ID_"; private static final String SEARCH_SUPPORTED = "android.media.browse.SEARCH_SUPPORTED"; + /** + * Extras key to allow Android Auto to identify the browse service from the media session. + */ + private static final String BROWSE_SERVICE_FOR_SESSION_KEY = + "android.media.session.BROWSE_SERVICE"; private TmaPrefs mPrefs; private Handler mHandler; @@ -61,7 +71,6 @@ public class TmaBrowser extends MediaBrowserServiceCompat { private TmaPlayer mPlayer; private BrowserRoot mRoot; - private String mLastLoadedNodeId; @Override public void onCreate() { @@ -78,6 +87,9 @@ public class TmaBrowser extends MediaBrowserServiceCompat { mSession.setCallback(mPlayer); mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); + Bundle mediaSessionExtras = new Bundle(); + mediaSessionExtras.putString(BROWSE_SERVICE_FOR_SESSION_KEY, TmaBrowser.class.getName()); + mSession.setExtras(mediaSessionExtras); mPrefs.mAccountType.registerChangeListener( (oldValue, newValue) -> onAccountChanged(newValue)); @@ -88,9 +100,11 @@ public class TmaBrowser extends MediaBrowserServiceCompat { mPrefs.mRootReplyDelay.registerChangeListener( (oldValue, newValue) -> invalidateRoot()); - Bundle extras = new Bundle(); - extras.putBoolean(SEARCH_SUPPORTED, true); - mRoot = new BrowserRoot(ROOT_ID, extras); + Bundle browserRootExtras = new Bundle(); + browserRootExtras.putBoolean(SEARCH_SUPPORTED, true); + mRoot = new BrowserRoot(ROOT_ID, browserRootExtras); + + updatePlaybackState(mPrefs.mAccountType.getValue()); } @Override @@ -115,6 +129,8 @@ public class TmaBrowser extends MediaBrowserServiceCompat { private void updatePlaybackState(TmaAccountType accountType) { if (accountType == TmaAccountType.NONE) { + mSession.setMetadata(null); + mPlayer.onStop(); mPlayer.setPlaybackState( new TmaMediaEvent(TmaMediaEvent.EventState.ERROR, TmaMediaEvent.StateErrorCode.AUTHENTICATION_EXPIRED, @@ -126,6 +142,7 @@ public class TmaBrowser extends MediaBrowserServiceCompat { // TODO don't reset error in all cases... PlaybackStateCompat.Builder playbackState = new PlaybackStateCompat.Builder(); playbackState.setState(PlaybackStateCompat.STATE_PAUSED, 0, 0); + playbackState.setActions(PlaybackStateCompat.ACTION_PREPARE); mSession.setPlaybackState(playbackState.build()); } } @@ -137,12 +154,17 @@ public class TmaBrowser extends MediaBrowserServiceCompat { @Override public BrowserRoot onGetRoot( @NonNull String clientPackageName, int clientUid, Bundle rootHints) { + if (rootHints == null) { + Log.e(TAG, "Client " + clientPackageName + " didn't set rootHints."); + throw new NullPointerException("rootHints is null"); + } + Log.i(TAG, "onGetroot client: " + clientPackageName + " EXTRA_MEDIA_ART_SIZE_HINT_PIXELS: " + + rootHints.getInt(MediaKeys.EXTRA_MEDIA_ART_SIZE_HINT_PIXELS, 0)); return mRoot; } @Override public void onLoadChildren(@NonNull String parentId, @NonNull Result<List<MediaItem>> result) { - mLastLoadedNodeId = parentId; getMediaItemsWithDelay(parentId, result, null); if (QUEUE_ONLY.equals(mPrefs.mRootNodeType.getValue()) && ROOT_ID.equals(parentId)) { @@ -155,8 +177,9 @@ public class TmaBrowser extends MediaBrowserServiceCompat { } @Override - public void onSearch(final String query, final Bundle extras, Result<List<MediaItem>> result) { - getMediaItemsWithDelay(mLastLoadedNodeId, result, query); + public void onSearch(@NonNull String query, Bundle extras, + @NonNull Result<List<MediaItem>> result) { + getMediaItemsWithDelay(ROOT_ID, result, query); } private void getMediaItemsWithDelay(@NonNull String parentId, @@ -175,14 +198,15 @@ public class TmaBrowser extends MediaBrowserServiceCompat { if (node == null) { result.sendResult(null); + } else if (filter != null) { + List<MediaItem> hits = new ArrayList<>(50); + Pattern pat = Pattern.compile(Pattern.quote(filter), Pattern.CASE_INSENSITIVE); + addSearchResults(node, pat.matcher(""), hits, MAX_SEARCH_DEPTH); + result.sendResult(hits); } else { List<MediaItem> items = new ArrayList<>(node.mChildren.size()); for (TmaMediaItem child : node.mChildren) { - MediaItem item = child.toMediaItem(); - CharSequence title = item.getDescription().getTitle(); - if (filter == null || (title != null && title.toString().contains(filter))) { - items.add(item); - } + items.add(child.toMediaItem()); } result.sendResult(items); } @@ -194,4 +218,26 @@ public class TmaBrowser extends MediaBrowserServiceCompat { mHandler.postDelayed(task, delay.mReplyDelayMs); } } + + private void addSearchResults(@Nullable TmaMediaItem node, Matcher matcher, + List<MediaItem> hits, int currentDepth) { + if (node == null || currentDepth <= 0) { + return; + } + + for (TmaMediaItem child : node.mChildren) { + MediaItem item = child.toMediaItem(); + CharSequence title = item.getDescription().getTitle(); + if (title != null) { + matcher.reset(title); + if (matcher.find()) { + hits.add(item); + } + } + + // Ask the library to load the grand children + child = mLibrary.getMediaItemById(child.getMediaId()); + addSearchResults(child, matcher, hits, currentDepth - 1); + } + } } diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaLibrary.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaLibrary.java index 27b8a7a..327a2b6 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaLibrary.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaLibrary.java @@ -49,9 +49,11 @@ class TmaLibrary { mRootAssetPaths.put(TmaBrowseNodeType.NULL, null); mRootAssetPaths.put(TmaBrowseNodeType.EMPTY, "media_items/empty.json"); mRootAssetPaths.put(TmaBrowseNodeType.QUEUE_ONLY, "media_items/empty.json"); + mRootAssetPaths.put(TmaBrowseNodeType.SINGLE_TAB, "media_items/single_node.json"); mRootAssetPaths.put(TmaBrowseNodeType.NODE_CHILDREN, "media_items/only_nodes.json"); mRootAssetPaths.put(TmaBrowseNodeType.LEAF_CHILDREN, "media_items/simple_leaves.json"); mRootAssetPaths.put(TmaBrowseNodeType.MIXED_CHILDREN, "media_items/mixed.json"); + mRootAssetPaths.put(TmaBrowseNodeType.UNTAGGED, "media_items/untagged.json"); } @Nullable diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java index f79e273..af1b2e3 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaMediaItem.java @@ -42,7 +42,9 @@ public class TmaMediaItem { public enum ContentStyle { NONE (0), LIST (MediaKeys.CONTENT_STYLE_LIST_ITEM_HINT_VALUE), - GRID (MediaKeys.CONTENT_STYLE_GRID_ITEM_HINT_VALUE); + GRID (MediaKeys.CONTENT_STYLE_GRID_ITEM_HINT_VALUE), + LIST_CATEGORY(MediaKeys.CONTENT_STYLE_CATEGORY_LIST_ITEM_HINT_VALUE), + GRID_CATEGORY(MediaKeys.CONTENT_STYLE_CATEGORY_GRID_ITEM_HINT_VALUE); final int mBundleValue; ContentStyle(int value) { mBundleValue = value; diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java index 2938a37..d8fab6c 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPlayer.java @@ -21,6 +21,7 @@ import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED; import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PAUSE; import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY; import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID; +import static android.support.v4.media.session.PlaybackStateCompat.ACTION_PREPARE; import static android.support.v4.media.session.PlaybackStateCompat.ACTION_SEEK_TO; import static android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_NEXT; import static android.support.v4.media.session.PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; @@ -345,7 +346,8 @@ public class TmaPlayer extends MediaSessionCompat.Callback { } private long addActions(long actions) { - actions |= ACTION_PLAY_FROM_MEDIA_ID | ACTION_SKIP_TO_QUEUE_ITEM | ACTION_SEEK_TO; + actions |= ACTION_PLAY_FROM_MEDIA_ID | ACTION_SKIP_TO_QUEUE_ITEM | ACTION_SEEK_TO + | ACTION_PREPARE; if (mActiveItem != null) { if (mActiveItem.getNext() != null) { diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaAssetProvider.java b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPublicProvider.java index fc9fd49..e7eb31b 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/TmaAssetProvider.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/TmaPublicProvider.java @@ -21,56 +21,105 @@ 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 TmaAssetProvider extends ContentProvider { +public class TmaPublicProvider extends ContentProvider { private static final String TAG = "TmaAssetProvider"; - private static final String PACKAGE_NAME = "com.android.car.media.testmediaapp"; + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; - private static final String ASSET_URI_PREFIX = - ContentResolver.SCHEME_CONTENT + "://" + PACKAGE_NAME + ".assets/"; + 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 + "://" + PACKAGE_NAME + "/"; + ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + AUTHORITY + "/"; public static String buildUriString(String localArt) { - String prefix = localArt.startsWith("drawable") ? RESOURCE_URI_PREFIX : ASSET_URI_PREFIX; + 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 { - Log.i(TAG, "TmaAssetProvider#openAssetFile " + uri); + 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) { } - 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); + 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( 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 static com.android.car.media.testmediaapp.loader.TmaLoaderUtils.enumNames 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 @@ class TmaMediaMetadataReader { 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; diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/phone/TmaLauncherActivity.java b/TestMediaApp/src/com/android/car/media/testmediaapp/phone/TmaLauncherActivity.java index 9ae6a6d..84f481f 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/phone/TmaLauncherActivity.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/phone/TmaLauncherActivity.java @@ -10,6 +10,7 @@ import android.util.Log; import androidx.appcompat.app.AppCompatActivity; +import com.android.car.media.testmediaapp.MediaKeys; import com.android.car.media.testmediaapp.TmaBrowser; import com.android.car.media.testmediaapp.prefs.TmaPrefsActivity; import com.android.car.media.testmediaapp.R; @@ -37,9 +38,11 @@ public class TmaLauncherActivity extends AppCompatActivity { startActivity(prefsIntent); }); - + Bundle rootHints = new Bundle(); + // TODO: 256 is just a placeholder. We'd better find a proper value. + rootHints.putInt(MediaKeys.EXTRA_MEDIA_ART_SIZE_HINT_PIXELS, 256); mediaBrowser = new MediaBrowserCompat(this, new ComponentName(this, TmaBrowser.class), - mConnectionCallbacks, null); + mConnectionCallbacks, rootHints); } private final MediaBrowserCompat.ConnectionCallback mConnectionCallbacks = diff --git a/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaEnumPrefs.java b/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaEnumPrefs.java index 744ef01..3702929 100644 --- a/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaEnumPrefs.java +++ b/TestMediaApp/src/com/android/car/media/testmediaapp/prefs/TmaEnumPrefs.java @@ -84,9 +84,11 @@ public class TmaEnumPrefs { NULL("Null (error)", "null"), EMPTY("Empty", "empty"), QUEUE_ONLY("Queue only", "queue-only"), + SINGLE_TAB("Single browse-able tab", "single-tab"), NODE_CHILDREN("Only browse-able content", "nodes"), LEAF_CHILDREN("Only playable content (basic working and error cases)", "leaves"), - MIXED_CHILDREN("Mixed content (apps are not supposed to do that)", "mixed"); + MIXED_CHILDREN("Mixed content (apps are not supposed to do that)", "mixed"), + UNTAGGED("Untagged media items (not playable or browsable)", "untagged"); private final PrefValueImpl mPrefValue; |