Updated MusicDemo sample.

Use material icons and colors;
Removed dependence on support libraries;
Added album art cache;
Bug: 17755718

Change-Id: I3085aa3e154393c3b0287783600f7187f7e42c7a
diff --git a/MusicDemo/build.gradle b/MusicDemo/build.gradle
index a0d7e19..eba452e 100644
--- a/MusicDemo/build.gradle
+++ b/MusicDemo/build.gradle
@@ -11,8 +11,8 @@
 apply plugin: 'android'
 
 android {
-    compileSdkVersion "android-L"
-    buildToolsVersion "21.0.0 rc1"
+    compileSdkVersion 21
+    buildToolsVersion "21.0.0"
 
     compileOptions {
         sourceCompatibility JavaVersion.VERSION_1_7
@@ -22,6 +22,4 @@
 
 
 dependencies {
-    compile 'com.android.support:support-v4:18.0.+'
-    compile 'com.android.support:appcompat-v7:18.0.+'
 }
diff --git a/MusicDemo/src/main/java/com/example/android/musicservicedemo/MediaNotification.java b/MusicDemo/src/main/java/com/example/android/musicservicedemo/MediaNotification.java
index 33d14c1..59b526e 100644
--- a/MusicDemo/src/main/java/com/example/android/musicservicedemo/MediaNotification.java
+++ b/MusicDemo/src/main/java/com/example/android/musicservicedemo/MediaNotification.java
@@ -23,7 +23,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
@@ -36,6 +41,7 @@
 import com.example.android.musicservicedemo.utils.LogHelper;
 
 import java.io.IOException;
+import java.util.LinkedHashMap;
 
 /**
  * Keeps track of a notification and updates it automatically for a given
@@ -58,6 +64,7 @@
     private MediaController mController;
     private MediaController.TransportControls mTransportControls;
     private final SparseArray<PendingIntent> mIntents = new SparseArray<PendingIntent>();
+    private final LinkedHashMap<String, Bitmap> mAlbumArtCache;
 
     private PlaybackState mPlaybackState;
     private MediaMetadata mMetadata;
@@ -67,6 +74,7 @@
     private Notification.Action mPlayPauseAction;
 
     private String mCurrentAlbumArt;
+    private int mNotificationColor;
 
     private boolean mStarted = false;
 
@@ -74,20 +82,49 @@
         mService = service;
         updateSessionToken();
 
+        // simple album art cache with up to 10 last accessed elements:
+        mAlbumArtCache = new LinkedHashMap<String, Bitmap>(10, 1f, true) {
+            @Override
+            protected boolean removeEldestEntry(Entry eldest) {
+                return size() > 10;
+            }
+        };
+
+        mNotificationColor = getNotificationColor();
+
         mNotificationManager = (NotificationManager) mService
                 .getSystemService(Context.NOTIFICATION_SERVICE);
 
         String pkg = mService.getPackageName();
-        mIntents.put(android.R.drawable.ic_media_pause, PendingIntent.getBroadcast(mService, 100,
+        mIntents.put(R.drawable.ic_pause_white_24dp, PendingIntent.getBroadcast(mService, 100,
                 new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
-        mIntents.put(android.R.drawable.ic_media_play, PendingIntent.getBroadcast(mService, 100,
+        mIntents.put(R.drawable.ic_play_arrow_white_24dp, PendingIntent.getBroadcast(mService, 100,
                 new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
-        mIntents.put(android.R.drawable.ic_media_previous, PendingIntent.getBroadcast(mService, 100,
+        mIntents.put(R.drawable.ic_skip_previous_white_24dp, PendingIntent.getBroadcast(mService, 100,
                 new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
-        mIntents.put(android.R.drawable.ic_media_next, PendingIntent.getBroadcast(mService, 100,
+        mIntents.put(R.drawable.ic_skip_next_white_24dp, PendingIntent.getBroadcast(mService, 100,
                 new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT));
     }
 
+    protected int getNotificationColor() {
+        int notificationColor = 0;
+        String packageName = mService.getPackageName();
+        try {
+            Context packageContext = mService.createPackageContext(packageName, 0);
+            ApplicationInfo applicationInfo =
+                    mService.getPackageManager().getApplicationInfo(packageName, 0);
+            packageContext.setTheme(applicationInfo.theme);
+            Resources.Theme theme = packageContext.getTheme();
+            TypedArray ta = theme.obtainStyledAttributes(
+                    new int[] {android.R.attr.colorPrimary});
+            notificationColor = ta.getColor(0, Color.DKGRAY);
+            ta.recycle();
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+        }
+        return notificationColor;
+    }
+
     /**
      * Posts the notification and starts tracking the session to keep it
      * updated. The notification will automatically be removed if the session is
@@ -187,61 +224,64 @@
 
     private void updateNotificationMetadata() {
         LogHelper.d(TAG, "updateNotificationMetadata. mMetadata=" + mMetadata);
-        if (mMetadata == null) {
+        if (mMetadata == null || mPlaybackState == null) {
             return;
         }
 
         updatePlayPauseAction();
 
-        boolean firstRun = false;
+        mNotificationBuilder = new Notification.Builder(mService);
+        int playPauseActionIndex = 0;
 
-        if (mNotificationBuilder == null) {
-            firstRun = true;
-
-            mNotificationBuilder = new Notification.Builder(mService);
-
+        // If skip to previous action is enabled
+        if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
             mNotificationBuilder
-                    .addAction(android.R.drawable.ic_media_previous,
+                    .addAction(R.drawable.ic_skip_previous_white_24dp,
                             mService.getString(R.string.label_previous),
-                            mIntents.get(android.R.drawable.ic_media_previous))
-                    .addAction(mPlayPauseAction)
-                    .addAction(android.R.drawable.ic_media_next,
-                            mService.getString(R.string.label_next),
-                            mIntents.get(android.R.drawable.ic_media_next))
-                    .setStyle(new Notification.MediaStyle()
-                            .setShowActionsInCompactView(1)  // only show play/pause in compact view
-                            .setMediaSession(mSessionToken))
-                    .setColor(android.R.attr.colorPrimaryDark)
-                    .setSmallIcon(R.drawable.ic_notification)
-                    .setVisibility(Notification.VISIBILITY_PUBLIC)
-                    .setUsesChronometer(true);
+                            mIntents.get(R.drawable.ic_skip_previous_white_24dp));
+            playPauseActionIndex = 1;
+        }
+
+        mNotificationBuilder.addAction(mPlayPauseAction);
+
+        // If skip to next action is enabled
+        if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
+            mNotificationBuilder.addAction(R.drawable.ic_skip_next_white_24dp,
+                    mService.getString(R.string.label_next),
+                    mIntents.get(R.drawable.ic_skip_next_white_24dp));
         }
 
         MediaDescription description = mMetadata.getDescription();
         Bitmap art = description.getIconBitmap();
+        if (art == null && description.getIconUri() != null) {
+            // This sample assumes the iconUri will be a valid URL formatted String, but
+            // it can actually be any valid Android Uri formatted String.
+            // async fetch the album art icon
+            String artUrl = description.getIconUri().toString();
+            art = mAlbumArtCache.get(artUrl);
+            if (art == null) {
+                fetchBitmapFromURLAsync(artUrl);
+            } else {
+                mNotificationBuilder.setLargeIcon(art);
+            }
+        }
+
         mNotificationBuilder
+                .setStyle(new Notification.MediaStyle()
+                        .setShowActionsInCompactView(playPauseActionIndex)  // only show play/pause in compact view
+                        .setMediaSession(mSessionToken))
+                .setColor(mNotificationColor)
+                .setSmallIcon(R.drawable.ic_notification)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setOngoing(true)
+                .setUsesChronometer(true)
                 .setContentTitle(description.getTitle())
                 .setContentText(description.getSubtitle())
                 .setLargeIcon(art);
 
         updateNotificationPlaybackState();
 
-        if (firstRun) {
-            mService.startForeground(NOTIFICATION_ID, mNotificationBuilder.build());
-        } else {
-            mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
-        }
-
-        if (art == null && description.getIconUri() != null) {
-            // This sample assumes the iconUri will be a valid URL formatted String, but
-            // it can actually be any valid Android Uri formatted String.
-            String albumUrl = description.getIconUri().toString();
-            if (mCurrentAlbumArt == null || !mCurrentAlbumArt.equals(albumUrl)) {
-                mCurrentAlbumArt = albumUrl;
-                // async fetch the album art icon
-                getBitmapFromURLAsync(albumUrl);
-            }
-        }
+        mService.startForeground(NOTIFICATION_ID, mNotificationBuilder.build());
     }
 
     private void updatePlayPauseAction() {
@@ -250,10 +290,10 @@
         int playPauseIcon;
         if (mPlaybackState.getState() == PlaybackState.STATE_PLAYING) {
             playPauseLabel = mService.getString(R.string.label_pause);
-            playPauseIcon = android.R.drawable.ic_media_pause;
+            playPauseIcon = R.drawable.ic_pause_white_24dp;
         } else {
             playPauseLabel = mService.getString(R.string.label_play);
-            playPauseIcon = android.R.drawable.ic_media_play;
+            playPauseIcon = R.drawable.ic_play_arrow_white_24dp;
         }
         if (mPlayPauseAction == null) {
             mPlayPauseAction = new Notification.Action(playPauseIcon, playPauseLabel,
@@ -297,7 +337,7 @@
         mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
     }
 
-    public void getBitmapFromURLAsync(final String source) {
+    public void fetchBitmapFromURLAsync(final String source) {
         LogHelper.d(TAG, "getBitmapFromURLAsync: starting asynctask to fetch ", source);
         new AsyncTask() {
             @Override
@@ -305,13 +345,12 @@
                 try {
                     Bitmap bitmap = BitmapHelper.fetchAndRescaleBitmap(source,
                             BitmapHelper.MEDIA_ART_BIG_WIDTH, BitmapHelper.MEDIA_ART_BIG_HEIGHT);
+                    mAlbumArtCache.put(source, bitmap);
                     if (mMetadata != null) {
-                        MediaDescription currentDescription = mMetadata.getDescription();
+                        String currentSource = mMetadata.getDescription().getIconUri().toString();
                         // If the media is still the same, update the notification:
-                        if (mNotificationBuilder != null &&
-                                currentDescription.getIconUri().toString().equals(source)) {
+                        if (mNotificationBuilder != null && currentSource.equals(source)) {
                             LogHelper.d(TAG, "getBitmapFromURLAsync: set bitmap to ", source);
-                            mCurrentAlbumArt = source;
                             mNotificationBuilder.setLargeIcon(bitmap);
                             mNotificationManager.notify(NOTIFICATION_ID,
                                     mNotificationBuilder.build());
diff --git a/MusicDemo/src/main/java/com/example/android/musicservicedemo/utils/BitmapHelper.java b/MusicDemo/src/main/java/com/example/android/musicservicedemo/utils/BitmapHelper.java
index c743262..984de49 100644
--- a/MusicDemo/src/main/java/com/example/android/musicservicedemo/utils/BitmapHelper.java
+++ b/MusicDemo/src/main/java/com/example/android/musicservicedemo/utils/BitmapHelper.java
@@ -33,25 +33,6 @@
     public static final int MEDIA_ART_BIG_WIDTH=128;
     public static final int MEDIA_ART_BIG_HEIGHT=128;
 
-    public static final Bitmap scaleBitmap(int targetW, int targetH, InputStream is) {
-        // Get the dimensions of the bitmap
-        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
-        bmOptions.inJustDecodeBounds = true;
-        BitmapFactory.decodeStream(is, null, bmOptions);
-        int actualW = bmOptions.outWidth;
-        int actualH = bmOptions.outHeight;
-
-        // Determine how much to scale down the image
-        int scaleFactor = Math.min(actualW/targetW, actualH/targetH);
-
-        // Decode the image file into a Bitmap sized to fill the View
-        bmOptions.inJustDecodeBounds = false;
-        bmOptions.inSampleSize = scaleFactor;
-
-        Bitmap bitmap = BitmapFactory.decodeStream(is, null, bmOptions);
-        return bitmap;
-    }
-
     public static final Bitmap scaleBitmap(int scaleFactor, InputStream is) {
         // Get the dimensions of the bitmap
         BitmapFactory.Options bmOptions = new BitmapFactory.Options();
diff --git a/MusicDemo/src/main/res/drawable-hdpi/ic_pause_white_24dp.png b/MusicDemo/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..b4bdbb5
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-hdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/MusicDemo/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..164385d
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png b/MusicDemo/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 0000000..3eeb0ef
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-hdpi/ic_shuffle_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png b/MusicDemo/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..4eaf7ca
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-hdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png b/MusicDemo/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..e59dedb
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-hdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png b/MusicDemo/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..14b6d17
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xhdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/MusicDemo/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..a55d199
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png b/MusicDemo/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 0000000..8ce3a60
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xhdpi/ic_shuffle_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png b/MusicDemo/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..f282b92
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xhdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png b/MusicDemo/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..2522877
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xhdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png b/MusicDemo/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
new file mode 100644
index 0000000..72dfa9f
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xxhdpi/ic_pause_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/MusicDemo/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 0000000..043acd8
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png b/MusicDemo/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
new file mode 100644
index 0000000..718b6b5
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xxhdpi/ic_shuffle_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png b/MusicDemo/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
new file mode 100644
index 0000000..4fe6088
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xxhdpi/ic_skip_next_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png b/MusicDemo/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
new file mode 100644
index 0000000..2c9310a
--- /dev/null
+++ b/MusicDemo/src/main/res/drawable-xxhdpi/ic_skip_previous_white_24dp.png
Binary files differ
diff --git a/MusicDemo/src/main/res/values-v21/styles.xml b/MusicDemo/src/main/res/values-v21/styles.xml
index 6169d24..602ce1c 100644
--- a/MusicDemo/src/main/res/values-v21/styles.xml
+++ b/MusicDemo/src/main/res/values-v21/styles.xml
@@ -16,17 +16,17 @@
 -->
 <resources>
 
-    <style name="AppBaseTheme" parent="Theme.AppCompat.Light">
+    <style name="AppBaseTheme" parent="android:Theme.Light">
         <!-- colorPrimary is used for Notification icon and bottom facet bar icons
         and overflow actions -->
-        <item name="android:colorPrimary">@color/red</item>
+        <item name="android:colorPrimary">#ffff5722</item>
 
         <!-- colorPrimaryDark is used for background -->
-        <item name="android:colorPrimaryDark">#990000</item>
+        <item name="android:colorPrimaryDark">#ffbf360c</item>
 
         <!-- colorAccent is sparingly used for accents, like floating action button highlight,
         progress on playbar-->
-        <item name="android:colorAccent">#0000FF</item>
+        <item name="android:colorAccent">#ffff5722</item>
 
     </style>
 
diff --git a/MusicDemo/src/main/res/values/colors.xml b/MusicDemo/src/main/res/values/colors.xml
deleted file mode 100644
index 6a5277e..0000000
--- a/MusicDemo/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<resources>
-    <color name="red">#ffff0000</color>
-</resources>
diff --git a/MusicDemo/src/main/res/values/styles.xml b/MusicDemo/src/main/res/values/styles.xml
index 507dc7b..3be59c1 100644
--- a/MusicDemo/src/main/res/values/styles.xml
+++ b/MusicDemo/src/main/res/values/styles.xml
@@ -16,8 +16,11 @@
 -->
 <resources>
 
-    <style name="AppBaseTheme" parent="Theme.AppCompat.Light"></style>
 
-    <style name="AppTheme" parent="AppBaseTheme"></style>
+    <style name="AppTheme" parent="AppBaseTheme">
+    </style>
+
+    <style name="AppBaseTheme" parent="android:Theme.Light">
+    </style>
 
 </resources>
\ No newline at end of file