Adds the Random Music Player sample.

This sample illustrates how to write an application that plays media
in the background, handles streaming media from the network and
reacts appropriately to system events like headphone disconnection and
audio focus changes, and also uses the notification system to
keep the user informed about what is happening.

This CL is a cherrypick of the old CL 104495 (originally in
honeycomb-mr1) into honeycomb-mr2. Original CL:
https://android-git.corp.google.com/g/#change,104495

Change-Id: Ib8b15ee920300adc093a8b52c17bd9c251ac74ca
diff --git a/build/sdk.atree b/build/sdk.atree
index e5da0a2..e616515 100644
--- a/build/sdk.atree
+++ b/build/sdk.atree
@@ -167,6 +167,7 @@
 development/samples/LunarLander                samples/${PLATFORM_NAME}/LunarLander
 development/samples/MultiResolution            samples/${PLATFORM_NAME}/MultiResolution
 development/samples/NotePad                    samples/${PLATFORM_NAME}/NotePad
+development/samples/RandomMusicPlayer          samples/${PLATFORM_NAME}/RandomMusicPlayer
 development/samples/SampleSyncAdapter          samples/${PLATFORM_NAME}/SampleSyncAdapter
 development/samples/SearchableDictionary       samples/${PLATFORM_NAME}/SearchableDictionary
 development/samples/SipDemo                    samples/${PLATFORM_NAME}/SipDemo
diff --git a/samples/RandomMusicPlayer/AndroidManifest.xml b/samples/RandomMusicPlayer/AndroidManifest.xml
new file mode 100644
index 0000000..5a0fc28
--- /dev/null
+++ b/samples/RandomMusicPlayer/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.example.android.musicplayer"
+      android:versionCode="1"
+      android:versionName="1.0">
+
+    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="8" />
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+
+    <application android:icon="@drawable/ic_launcher" android:label="Random Music Player">
+        <activity android:name=".MainActivity"
+                  android:label="Random Music Player"
+                  android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <service android:exported="false" android:name=".MusicService">
+            <intent-filter>
+                <action android:name="com.example.android.musicplayer.action.PLAY" />
+                <action android:name="com.example.android.musicplayer.action.PAUSE" />
+                <action android:name="com.example.android.musicplayer.action.SKIP" />
+                <action android:name="com.example.android.musicplayer.action.REWIND" />
+                <action android:name="com.example.android.musicplayer.action.STOP" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="com.example.android.musicplayer.action.URL" />
+                <data android:scheme="http" />
+            </intent-filter>
+        </service>
+
+        <receiver android:name=".MusicIntentReceiver">
+            <intent-filter>
+                <action android:name="android.media.AUDIO_BECOMING_NOISY" />
+            </intent-filter>
+        </receiver>
+    </application>
+</manifest>
diff --git a/samples/RandomMusicPlayer/_index.html b/samples/RandomMusicPlayer/_index.html
new file mode 100644
index 0000000..657e6c4
--- /dev/null
+++ b/samples/RandomMusicPlayer/_index.html
@@ -0,0 +1,8 @@
+<p>A simple music player that illustrates how to make a multimedia application
+that manages media playback from a service. It allows the user to play music
+available on the device or specify a URL from which the media should be
+streamed.  It also illustrates how to use the notification system to indicate
+an ongoing task and how to deal with audio focus changes.</p>
+
+<img alt="" src="../images/randommusicplayer.png" />
+
diff --git a/samples/RandomMusicPlayer/default.properties b/samples/RandomMusicPlayer/default.properties
new file mode 100644
index 0000000..e2e8061
--- /dev/null
+++ b/samples/RandomMusicPlayer/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-8
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png
new file mode 100644
index 0000000..d111aab
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi-v9/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/eject.png b/samples/RandomMusicPlayer/res/drawable-hdpi/eject.png
new file mode 100644
index 0000000..650b38a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/eject.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/eject_pressed.png b/samples/RandomMusicPlayer/res/drawable-hdpi/eject_pressed.png
new file mode 100644
index 0000000..065b30d
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/eject_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/ff.png b/samples/RandomMusicPlayer/res/drawable-hdpi/ff.png
new file mode 100644
index 0000000..508f741
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/ff.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/ff_pressed.png b/samples/RandomMusicPlayer/res/drawable-hdpi/ff_pressed.png
new file mode 100644
index 0000000..468ae8e
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/ff_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..abd9055
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png
new file mode 100644
index 0000000..c1dd9da
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/pause.png b/samples/RandomMusicPlayer/res/drawable-hdpi/pause.png
new file mode 100644
index 0000000..13581de
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/pause.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/pause_pressed.png b/samples/RandomMusicPlayer/res/drawable-hdpi/pause_pressed.png
new file mode 100644
index 0000000..9ddd07d
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/pause_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/play.png b/samples/RandomMusicPlayer/res/drawable-hdpi/play.png
new file mode 100644
index 0000000..e34b48e
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/play.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/play_pressed.png b/samples/RandomMusicPlayer/res/drawable-hdpi/play_pressed.png
new file mode 100644
index 0000000..790cd29
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/play_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/rew.png b/samples/RandomMusicPlayer/res/drawable-hdpi/rew.png
new file mode 100644
index 0000000..26864b7
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/rew.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/rew_pressed.png b/samples/RandomMusicPlayer/res/drawable-hdpi/rew_pressed.png
new file mode 100644
index 0000000..54c38a7
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/rew_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_eject.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_eject.xml
new file mode 100644
index 0000000..300e75a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_eject.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/eject_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/eject_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/eject" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_ff.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_ff.xml
new file mode 100644
index 0000000..2d399b4
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_ff.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/ff_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/ff_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/ff" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_pause.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_pause.xml
new file mode 100644
index 0000000..2d6c4be
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_pause.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/pause_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/pause_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/pause" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_play.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_play.xml
new file mode 100644
index 0000000..d2eea02
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_play.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/play_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/play_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/play" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_rew.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_rew.xml
new file mode 100644
index 0000000..5f5f88a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_rew.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/rew_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/rew_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/rew" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/selector_stop.xml b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_stop.xml
new file mode 100644
index 0000000..5778417
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/selector_stop.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/stop_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/stop_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/stop" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/stop.png b/samples/RandomMusicPlayer/res/drawable-hdpi/stop.png
new file mode 100644
index 0000000..45eff23
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/stop.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-hdpi/stop_pressed.png b/samples/RandomMusicPlayer/res/drawable-hdpi/stop_pressed.png
new file mode 100644
index 0000000..c7bda81
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-hdpi/stop_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-ldpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-ldpi-v9/ic_stat_playing.png
new file mode 100644
index 0000000..6a40823
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-ldpi-v9/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-ldpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..6f1277a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-ldpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-ldpi/ic_stat_playing.png
new file mode 100644
index 0000000..fb21884
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-ldpi/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png
new file mode 100644
index 0000000..b5a66df
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi-v9/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/eject.png b/samples/RandomMusicPlayer/res/drawable-mdpi/eject.png
new file mode 100644
index 0000000..650b38a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/eject.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/eject_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/eject_pressed.png
new file mode 100644
index 0000000..065b30d
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/eject_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ff.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ff.png
new file mode 100644
index 0000000..508f741
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/ff.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ff_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ff_pressed.png
new file mode 100644
index 0000000..468ae8e
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/ff_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..abd9055
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png
new file mode 100644
index 0000000..c1dd9da
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/ic_stat_playing.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/pause.png b/samples/RandomMusicPlayer/res/drawable-mdpi/pause.png
new file mode 100644
index 0000000..13581de
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/pause.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/pause_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/pause_pressed.png
new file mode 100644
index 0000000..9ddd07d
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/pause_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/play.png b/samples/RandomMusicPlayer/res/drawable-mdpi/play.png
new file mode 100644
index 0000000..e34b48e
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/play.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/play_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/play_pressed.png
new file mode 100644
index 0000000..790cd29
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/play_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/rew.png b/samples/RandomMusicPlayer/res/drawable-mdpi/rew.png
new file mode 100644
index 0000000..26864b7
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/rew.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/rew_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/rew_pressed.png
new file mode 100644
index 0000000..54c38a7
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/rew_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_eject.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_eject.xml
new file mode 100644
index 0000000..300e75a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_eject.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/eject_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/eject_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/eject" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_ff.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_ff.xml
new file mode 100644
index 0000000..2d399b4
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_ff.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/ff_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/ff_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/ff" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_pause.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_pause.xml
new file mode 100644
index 0000000..2d6c4be
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_pause.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/pause_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/pause_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/pause" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_play.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_play.xml
new file mode 100644
index 0000000..d2eea02
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_play.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/play_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/play_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/play" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_rew.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_rew.xml
new file mode 100644
index 0000000..5f5f88a
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_rew.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/rew_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/rew_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/rew" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/selector_stop.xml b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_stop.xml
new file mode 100644
index 0000000..5778417
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/selector_stop.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+ <selector xmlns:android="http://schemas.android.com/apk/res/android">
+     <item android:state_pressed="true"
+           android:drawable="@drawable/stop_pressed" /> <!-- pressed -->
+     <item android:state_focused="true"
+           android:drawable="@drawable/stop_pressed" /> <!-- focused -->
+     <item android:drawable="@drawable/stop" /> <!-- default -->
+ </selector>
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/stop.png b/samples/RandomMusicPlayer/res/drawable-mdpi/stop.png
new file mode 100644
index 0000000..45eff23
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/stop.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/drawable-mdpi/stop_pressed.png b/samples/RandomMusicPlayer/res/drawable-mdpi/stop_pressed.png
new file mode 100644
index 0000000..c7bda81
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/drawable-mdpi/stop_pressed.png
Binary files differ
diff --git a/samples/RandomMusicPlayer/res/layout-land/main.xml b/samples/RandomMusicPlayer/res/layout-land/main.xml
new file mode 100644
index 0000000..c9072bf
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/layout-land/main.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center"
+    android:background="#000040"
+    >
+
+<TextView android:text="Random Music Player"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:padding="20dp"
+          android:textColor="#ffffff"
+          android:textSize="20sp"
+          android:textStyle="bold"
+          />
+
+<LinearLayout
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    >
+<Button
+    android:id="@+id/rewindbutton"
+    android:background="@drawable/selector_rew"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/playbutton"
+    android:background="@drawable/selector_play"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/pausebutton"
+    android:background="@drawable/selector_pause"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/skipbutton"
+    android:background="@drawable/selector_ff"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/stopbutton"
+    android:background="@drawable/selector_stop"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/ejectbutton"
+    android:background="@drawable/selector_eject"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+
+</LinearLayout>
+</LinearLayout>
diff --git a/samples/RandomMusicPlayer/res/layout-port/main.xml b/samples/RandomMusicPlayer/res/layout-port/main.xml
new file mode 100644
index 0000000..ab86ae5
--- /dev/null
+++ b/samples/RandomMusicPlayer/res/layout-port/main.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:gravity="center"
+    android:background="#000040"
+    >
+
+<TextView android:text="Random Music Player"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:padding="20dp"
+          android:textColor="#ffffff"
+          android:textSize="20sp"
+          android:textStyle="bold"
+          />
+
+<LinearLayout
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:layout_margin="10dp"
+    >
+<Button
+    android:id="@+id/rewindbutton"
+    android:background="@drawable/selector_rew"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/playbutton"
+    android:background="@drawable/selector_play"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/pausebutton"
+    android:background="@drawable/selector_pause"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/skipbutton"
+    android:background="@drawable/selector_ff"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+</LinearLayout>
+
+<LinearLayout
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:gravity="center"
+    android:layout_margin="10dp"
+    >
+<Button
+    android:id="@+id/stopbutton"
+    android:background="@drawable/selector_stop"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+<Button
+    android:id="@+id/ejectbutton"
+    android:background="@drawable/selector_eject"
+    android:layout_width="64dp"
+    android:layout_height="64dp"
+    android:layout_margin="5dp"
+    />
+
+</LinearLayout>
+</LinearLayout>
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java
new file mode 100644
index 0000000..4b8b54a
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/AudioFocusHelper.java
@@ -0,0 +1,71 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+import android.content.Context;
+import android.media.AudioManager;
+
+/** 
+ * Convenience class to deal with audio focus. This class deals with everything related to audio
+ * focus: it can request and abandon focus, and will intercept focus change events and deliver
+ * them to a MusicFocusable interface (which, in our case, is implemented by {@link MusicService}).
+ *
+ * This class can only be used on SDK level 8 and above, since it uses API features that are not
+ * available on previous SDK's.
+ */
+public class AudioFocusHelper implements AudioManager.OnAudioFocusChangeListener {
+    AudioManager mAM;
+    MusicFocusable mFocusable;
+
+    public AudioFocusHelper(Context ctx, MusicFocusable focusable) {
+        mAM = (AudioManager) ctx.getSystemService(Context.AUDIO_SERVICE);
+        mFocusable = focusable;
+    }
+
+    /** Requests audio focus. Returns whether request was successful or not. */
+    public boolean requestFocus() {
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED ==
+            mAM.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+    }
+
+    /** Abandons audio focus. Returns whether request was successful or not. */
+    public boolean abandonFocus() {
+        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED == mAM.abandonAudioFocus(this);
+    }
+
+    /** 
+     * Called by AudioManager on audio focus changes. We implement this by calling our
+     * MusicFocusable appropriately to relay the message.
+     */
+    @Override
+    public void onAudioFocusChange(int focusChange) {
+        if (mFocusable == null) return;
+        switch (focusChange) {
+            case AudioManager.AUDIOFOCUS_GAIN:
+                mFocusable.onGainedAudioFocus();
+                break;
+            case AudioManager.AUDIOFOCUS_LOSS:
+            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+                mFocusable.onLostAudioFocus(false);
+                break;
+            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+                mFocusable.onLostAudioFocus(true);
+                break;
+             default:
+        }
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java
new file mode 100644
index 0000000..4974a21
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MainActivity.java
@@ -0,0 +1,122 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+
+/** 
+ * Main activity: shows media player buttons. This activity shows the media player buttons and
+ * lets the user click them. No media handling is done here -- everything is done by passing
+ * Intents to our {@link MusicService}.
+ * */
+public class MainActivity extends Activity implements OnClickListener {
+    /**
+     * The URL we suggest as default when adding by URL. This is just so that the user doesn't
+     * have to find an URL to test this sample.
+     */
+    final String SUGGESTED_URL = "http://www.vorbis.com/music/Epoq-Lepidoptera.ogg";
+
+    Button mPlayButton;
+    Button mPauseButton;
+    Button mSkipButton;
+    Button mRewindButton;
+    Button mStopButton;
+    Button mEjectButton;
+
+    /**
+     * Called when the activity is first created. Here, we simply set the event listeners and
+     * start the background service ({@link MusicService}) that will handle the actual media
+     * playback.
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+
+        mPlayButton = (Button) findViewById(R.id.playbutton);
+        mPauseButton = (Button) findViewById(R.id.pausebutton);
+        mSkipButton = (Button) findViewById(R.id.skipbutton);
+        mRewindButton = (Button) findViewById(R.id.rewindbutton);
+        mStopButton = (Button) findViewById(R.id.stopbutton);
+        mEjectButton = (Button) findViewById(R.id.ejectbutton);
+
+        mPlayButton.setOnClickListener(this);
+        mPauseButton.setOnClickListener(this);
+        mSkipButton.setOnClickListener(this);
+        mRewindButton.setOnClickListener(this);
+        mStopButton.setOnClickListener(this);
+        mEjectButton.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View target) {
+        // Send the correct intent to the MusicService, according to the button that was clicked
+        if (target == mPlayButton)
+            startService(new Intent(MusicService.ACTION_PLAY));
+        else if (target == mPauseButton)
+            startService(new Intent(MusicService.ACTION_PAUSE));
+        else if (target == mSkipButton)
+            startService(new Intent(MusicService.ACTION_SKIP));
+        else if (target == mRewindButton)
+            startService(new Intent(MusicService.ACTION_REWIND));
+        else if (target == mStopButton)
+            startService(new Intent(MusicService.ACTION_STOP));
+        else if (target == mEjectButton) {
+            showUrlDialog();
+        }
+    }
+
+    /** 
+     * Shows an alert dialog where the user can input a URL. After showing the dialog, if the user
+     * confirms, sends the appropriate intent to the {@link MusicService} to cause that URL to be
+     * played.
+     */
+    void showUrlDialog() {
+        AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
+        alertBuilder.setTitle("Manual Input");
+        alertBuilder.setMessage("Enter a URL (must be http://)");
+        final EditText input = new EditText(this);
+        alertBuilder.setView(input);
+
+        input.setText(SUGGESTED_URL);
+
+        alertBuilder.setPositiveButton("Play!", new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dlg, int whichButton) {
+                // Send an intent with the URL of the song to play. This is expected by
+                // MusicService.
+                Intent i = new Intent(MusicService.ACTION_URL);
+                Uri uri = Uri.parse(input.getText().toString());
+                i.setData(uri);
+                startService(i);
+            }
+        });
+        alertBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+            public void onClick(DialogInterface dlg, int whichButton) {}
+        });
+
+        alertBuilder.show();
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicFocusable.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicFocusable.java
new file mode 100644
index 0000000..aea8b49
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicFocusable.java
@@ -0,0 +1,35 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+/**
+ * Represents something that can react to audio focus events. We implement this instead of just
+ * using AudioManager.OnAudioFocusChangeListener because that interface is only available in SDK
+ * level 8 and above, and we want our application to work on previous SDKs.
+ */
+public interface MusicFocusable {
+    /** Signals that audio focus was gained. */
+    public void onGainedAudioFocus();
+
+    /**
+     * Signals that audio focus was lost.
+     *
+     * @param canDuck If true, audio can continue in "ducked" mode (low volume). Otherwise, all
+     * audio must stop.
+     */
+    public void onLostAudioFocus(boolean canDuck);
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java
new file mode 100644
index 0000000..cc03d5e
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicIntentReceiver.java
@@ -0,0 +1,40 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.widget.Toast;
+
+/**
+ * Receives broadcasted intents. In particular, we are interested in the
+ * android.media.AUDIO_BECOMING_NOISY intent, which is broadcast, for example, when the user
+ * disconnects the headphones. This class works because we are declaring it in a &lt;receiver&gt;
+ * tag in AndroidManifest.xml.
+ */
+public class MusicIntentReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context ctx, Intent intent) {
+        if (intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
+            Toast.makeText(ctx, "Headphones disconnected.", Toast.LENGTH_SHORT).show();
+
+            // send an intent to our MusicService to telling it to pause the audio
+            ctx.startService(new Intent(MusicService.ACTION_PAUSE));
+        }
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java
new file mode 100644
index 0000000..44d6447
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicRetriever.java
@@ -0,0 +1,118 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.database.Cursor;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * Retrieves and organizes media to play. Before being used, you must call {@link #prepare()},
+ * which will retrieve all of the music on the user's device (by performing a query on a content
+ * resolver). After that, it's ready to retrieve a random song, with its title and URI, upon
+ * request.
+ */
+public class MusicRetriever {
+    final String TAG = "MusicRetriever";
+
+    ContentResolver mContentResolver;
+
+    // the items (songs) we have queried
+    List<Item> mItems = new ArrayList<Item>();
+
+    Random mRandom = new Random();
+
+    public MusicRetriever(ContentResolver cr) {
+        mContentResolver = cr;
+    }
+
+    /**
+     * Loads music data. This method may take long, so be sure to call it asynchronously without
+     * blocking the main thread.
+     */
+    public void prepare() {
+        Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+        Log.i(TAG, "Querying media...");
+        Log.i(TAG, "URI: " + uri.toString());
+
+        // Perform a query on the content resolver. The URI we're passing specifies that we
+        // want to query for all audio media on external storage (e.g. SD card)
+        Cursor cur = mContentResolver.query(uri, null, null, null, null);
+        Log.i(TAG, "Query finished. " + (cur == null ? "Returned NULL." : "Returned a cursor."));
+
+        if (cur == null) {
+            // Query failed...
+            Log.e(TAG, "Failed to retrieve music: cursor is null :-(");
+            return;
+        }
+        if (!cur.moveToFirst()) {
+            // Nothing to query. There is no music on the device. How boring.
+            Log.e(TAG, "Failed to move cursor to first row (no query results).");
+            return;
+        }
+
+        Log.i(TAG, "Listing...");
+
+        // retrieve the indices of the columns where the ID and title of the song are
+        int titleColumn = cur.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
+        int idColumn = cur.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
+
+        Log.i(TAG, "Title column index: " + String.valueOf(titleColumn));
+        Log.i(TAG, "ID column index: " + String.valueOf(titleColumn));
+
+        // add each song to mItems
+        do {
+            Log.i(TAG, "ID: " + cur.getString(idColumn) + " Title: " + cur.getString(titleColumn));
+            mItems.add(new Item(cur.getLong(idColumn), cur.getString(titleColumn)));
+        } while (cur.moveToNext());
+
+        Log.i(TAG, "Done querying media. MusicRetriever is ready.");
+    }
+
+    public ContentResolver getContentResolver() {
+        return mContentResolver;
+    }
+
+    /** Returns a random Item. If there are no items available, returns null. */
+    public Item getRandomItem() {
+        if (mItems.size() <= 0) return null;
+        return mItems.get(mRandom.nextInt(mItems.size()));
+    }
+
+    public class Item {
+        long id;
+        String title;
+
+        public Item(long id, String title) {
+            this.id = id;
+            this.title = title;
+        }
+
+        public long getId() { return id; }
+        public String getTitle() { return title; }
+        public Uri getURI() {
+            return ContentUris.withAppendedId(
+                    android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id);
+        }
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java
new file mode 100644
index 0000000..9bd1251
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/MusicService.java
@@ -0,0 +1,511 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+import java.io.IOException;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiManager.WifiLock;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.util.Log;
+import android.widget.Toast;
+
+/**
+ * Service that handles media playback. This is the Service through which we perform all the media
+ * handling in our application. Upon initialization, it starts a {@link MediaRetriever} to scan
+ * the user's media. Then, it waits for Intents (which come from our main activity,
+ * {@link MainActivity}, which signal the service to perform specific operations: Play, Pause,
+ * Rewind, Skip, etc.
+ */
+public class MusicService extends Service implements OnCompletionListener, OnPreparedListener,
+                OnErrorListener, MusicFocusable,
+                PrepareMusicRetrieverTask.MusicRetrieverPreparedListener {
+
+    NotificationManager mNotificationManager;
+
+    // our media player
+    MediaPlayer mPlayer = null;
+
+    // our AudioFocusHelper object, if it's available (it's available on SDK level >= 8)
+    // If not available, this will be null. Always check for null before using!
+    AudioFocusHelper mAudioFocusHelper = null;
+
+    // indicates the state our service:
+    enum State {
+        Retrieving, // the MediaRetriever is retrieving music
+        Stopped,    // media player is stopped and not prepared to play
+        Preparing,  // media player is preparing...
+        Playing,    // playback active (media player ready!). (but the media player may actually be
+                    // paused in this state if we don't have audio focus. But we stay in this state
+                    // so that we know we have to resume playback once we get focus back)
+        Paused      // playback paused (media player ready!)
+    };
+
+    State mState = State.Retrieving;
+
+    // if in Retrieving mode, this flag indicates whether we should start playing immediately
+    // when we are ready or not.
+    boolean mStartPlayingAfterRetrieve = false;
+
+    // if mStartPlayingAfterRetrieve is true, this variable indicates the URL that we should
+    // start playing when we are ready. If null, we should play a random song from the device
+    Uri mWhatToPlayAfterRetrieve = null;
+
+    enum PauseReason {
+        UserRequest,  // paused by user request
+        FocusLoss,    // paused because of audio focus loss
+    };
+
+    // why did we pause? (only relevant if mState == State.Paused)
+    PauseReason mPauseReason = PauseReason.UserRequest;
+
+    // do we have audio focus?
+    enum AudioFocus {
+        NoFocusNoDuck,    // we don't have audio focus, and can't duck
+        NoFocusCanDuck,   // we don't have focus, but can play at a low volume ("ducking")
+        Focused           // we have full audio focus
+    }
+    AudioFocus mAudioFocus = AudioFocus.NoFocusNoDuck;
+
+    // title of the song we are currently playing
+    String mSongTitle = "";
+
+    // whether the song we are playing is streaming from the network
+    boolean mIsStreaming = false;
+
+    // Wifi lock that we hold when streaming files from the internet, in order to prevent the
+    // device from shutting off the Wifi radio
+    WifiLock mWifiLock;
+
+    // The tag we put on debug messages
+    final static String TAG = "RandomMusicPlayer";
+
+    // These are the Intent actions that we are prepared to handle. Notice that the fact these
+    // constants exist in our class is a mere convenience: what really defines the actions our
+    // service can handle are the <action> tags in the <intent-filters> tag for our service in
+    // AndroidManifest.xml.
+    public static final String ACTION_PLAY = "com.example.android.musicplayer.action.PLAY";
+    public static final String ACTION_PAUSE = "com.example.android.musicplayer.action.PAUSE";
+    public static final String ACTION_STOP = "com.example.android.musicplayer.action.STOP";
+    public static final String ACTION_SKIP = "com.example.android.musicplayer.action.SKIP";
+    public static final String ACTION_REWIND = "com.example.android.musicplayer.action.REWIND";
+    public static final String ACTION_URL = "com.example.android.musicplayer.action.URL";
+
+    // The volume we set the media player to when we lose audio focus, but are allowed to reduce
+    // the volume instead of stopping playback.
+    public final float DUCK_VOLUME = 0.1f;
+
+    // The ID we use for the notification (the onscreen alert that appears at the notification
+    // area at the top of the screen as an icon -- and as text as well if the user expands the
+    // notification area).
+    final int NOTIFICATION_ID = 1;
+
+    // Our instance of our MusicRetriever, which handles scanning for media and
+    // providing titles and URIs as we need.
+    MusicRetriever mRetriever;
+
+    Notification mNotification = null;
+
+    /**
+     * Makes sure the media player exists and has been reset. This will create the media player
+     * if needed, or reset the existing media player if one already exists.
+     */
+    void createMediaPlayerIfNeeded() {
+        if (mPlayer == null) {
+            mPlayer = new MediaPlayer();
+
+            // Make sure the media player will acquire a wake-lock while playing. If we don't do
+            // that, the CPU might go to sleep while the song is playing, causing playback to stop.
+            //
+            // Remember that to use this, we have to declare the android.permission.WAKE_LOCK
+            // permission in AndroidManifest.xml.
+            mPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
+
+            // we want the media player to notify us when it's ready preparing, and when it's done
+            // playing:
+            mPlayer.setOnPreparedListener(this);
+            mPlayer.setOnCompletionListener(this);
+            mPlayer.setOnErrorListener(this);
+        }
+        else
+            mPlayer.reset();
+    }
+
+    @Override
+    public void onCreate() {
+        Log.i(TAG, "debug: Creating service");
+
+        // Create the Wifi lock (this does not acquire the lock, this just creates it)
+        mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
+                        .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");
+
+        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+        // Create the retriever and start an asynchronous task that will prepare it.
+        mRetriever = new MusicRetriever(getContentResolver());
+        (new PrepareMusicRetrieverTask(mRetriever,this)).execute();
+
+        // create the Audio Focus Helper, if the Audio Focus feature is available (SDK 8 or above)
+        if (android.os.Build.VERSION.SDK_INT >= 8)
+            mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);
+        else
+            mAudioFocus = AudioFocus.Focused; // no focus feature, so we always "have" audio focus
+    }
+
+    /**
+     * Called when we receive an Intent. When we receive an intent sent to us via startService(),
+     * this is the method that gets called. So here we react appropriately depending on the
+     * Intent's action, which specifies what is being requested of us.
+     */
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        String action = intent.getAction();
+        if (action.equals(ACTION_PLAY)) processPlayRequest();
+        else if (action.equals(ACTION_PAUSE)) processPauseRequest();
+        else if (action.equals(ACTION_SKIP)) processSkipRequest();
+        else if (action.equals(ACTION_STOP)) processStopRequest();
+        else if (action.equals(ACTION_REWIND)) processRewindRequest();
+        else if (action.equals(ACTION_URL)) processAddRequest(intent);
+
+        return START_NOT_STICKY; // Means we started the service, but don't want it to
+                                 // restart in case it's killed.
+    }
+
+    void processPlayRequest() {
+        if (mState == State.Retrieving) {
+            // If we are still retrieving media, just set the flag to start playing when we're
+            // ready
+            mWhatToPlayAfterRetrieve = null; // play a random song
+            mStartPlayingAfterRetrieve = true;
+            return;
+        }
+
+        tryToGetAudioFocus();
+
+        if (mState == State.Stopped) {
+            // If we're stopped, just go ahead to the next song and start playing
+            playNextSong(null);
+        }
+        else if (mState == State.Paused) {
+            // If we're paused, just continue playback and restore the 'foreground service' state.
+            mState = State.Playing;
+            setUpAsForeground(mSongTitle + " (playing)");
+            configAndStartMediaPlayer();
+        }
+    }
+
+    void processPauseRequest() {
+        if (mState == State.Retrieving) {
+            // If we are still retrieving media, clear the flag that indicates we should start
+            // playing when we're ready
+            mStartPlayingAfterRetrieve = false;
+            return;
+        }
+
+        if (mState == State.Playing) {
+            // Pause media player and cancel the 'foreground service' state.
+            mState = State.Paused;
+            mPlayer.pause();
+            relaxResources(false); // while paused, we always retain the MediaPlayer
+            giveUpAudioFocus();
+        }
+    }
+
+    void processRewindRequest() {
+        if (mState == State.Playing || mState == State.Paused)
+            mPlayer.seekTo(0);
+    }
+
+    void processSkipRequest() {
+        if (mState == State.Playing || mState == State.Paused) {
+            tryToGetAudioFocus();
+            playNextSong(null);
+        }
+    }
+
+    void processStopRequest() {
+        if (mState == State.Playing || mState == State.Paused) {
+            mState = State.Stopped;
+
+            // let go of all resources...
+            relaxResources(true);
+            giveUpAudioFocus();
+
+            // service is no longer necessary. Will be started again if needed.
+            stopSelf();
+        }
+    }
+
+    /**
+     * Releases resources used by the service for playback. This includes the "foreground service"
+     * status and notification, the wake locks and possibly the MediaPlayer.
+     *
+     * @param releaseMediaPlayer Indicates whether the Media Player should also be released or not
+     */
+    void relaxResources(boolean releaseMediaPlayer) {
+        // stop being a foreground service
+        stopForeground(true);
+
+        // stop and release the Media Player, if it's available
+        if (releaseMediaPlayer && mPlayer != null) {
+            mPlayer.reset();
+            mPlayer.release();
+            mPlayer = null;
+        }
+
+        // we can also release the Wifi lock, if we're holding it
+        if (mWifiLock.isHeld()) mWifiLock.release();
+    }
+
+    void giveUpAudioFocus() {
+        if (mAudioFocus == AudioFocus.Focused && mAudioFocusHelper != null
+                                && mAudioFocusHelper.abandonFocus())
+            mAudioFocus = AudioFocus.NoFocusNoDuck;
+    }
+
+    /**
+     * Reconfigures MediaPlayer according to audio focus settings and starts/restarts it. This
+     * method starts/restarts the MediaPlayer respecting the current audio focus state. So if
+     * we have focus, it will play normally; if we don't have focus, it will either leave the
+     * MediaPlayer paused or set it to a low volume, depending on what is allowed by the
+     * current focus settings. This method assumes mPlayer != null, so if you are calling it,
+     * you have to do so from a context where you are sure this is the case.
+     */
+    void configAndStartMediaPlayer() {
+        if (mAudioFocus == AudioFocus.NoFocusNoDuck) {
+            // If we don't have audio focus and can't duck, we have to pause, even if mState
+            // is State.Playing. But we stay in the Playing state so that we know we have to resume
+            // playback once we get the focus back.
+            if (mPlayer.isPlaying()) mPlayer.pause();
+            return;
+        }
+        else if (mAudioFocus == AudioFocus.NoFocusCanDuck)
+            mPlayer.setVolume(DUCK_VOLUME, DUCK_VOLUME);  // we'll be relatively quiet
+        else
+            mPlayer.setVolume(1.0f, 1.0f); // we can be loud
+
+        if (!mPlayer.isPlaying()) mPlayer.start();
+    }
+
+    void processAddRequest(Intent intent) {
+        // user wants to play a song directly by URL or path. The URL or path comes in the "data"
+        // part of the Intent. This Intent is sent by {@link MainActivity} after the user
+        // specifies the URL/path via an alert box.
+        if (mState == State.Retrieving) {
+            // we'll play the requested URL right after we finish retrieving
+            mWhatToPlayAfterRetrieve = intent.getData();
+            mStartPlayingAfterRetrieve = true;
+        }
+        else if (mState == State.Playing || mState == State.Paused || mState == State.Stopped) {
+            Log.i(TAG, "Playing from URL/path: " + intent.getData().toString());
+            tryToGetAudioFocus();
+            playNextSong(intent.getData().toString());
+        }
+    }
+
+    /**
+     * Shortcut to making and displaying a toast. Seemed cleaner than repeating
+     * this code everywhere, at least for this sample.
+     */
+    void say(String message) {
+        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
+    }
+
+    void tryToGetAudioFocus() {
+        if (mAudioFocus != AudioFocus.Focused && mAudioFocusHelper != null
+                        && mAudioFocusHelper.requestFocus())
+            mAudioFocus = AudioFocus.Focused;
+    }
+
+    /**
+     * Starts playing the next song. If manualUrl is null, the next song will be randomly selected
+     * from our Media Retriever (that is, it will be a random song in the user's device). If
+     * manualUrl is non-null, then it specifies the URL or path to the song that will be played
+     * next.
+     */
+    void playNextSong(String manualUrl) {
+        mState = State.Stopped;
+        relaxResources(false); // release everything except MediaPlayer
+
+        try {
+            if (manualUrl != null) {
+                // set the source of the media player to a manual URL or path
+                createMediaPlayerIfNeeded();
+                mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+                mPlayer.setDataSource(manualUrl);
+                mSongTitle = manualUrl;
+                mIsStreaming = manualUrl.startsWith("http:") || manualUrl.startsWith("https:");
+            }
+            else {
+                mIsStreaming = false; // playing a locally available song
+
+                MusicRetriever.Item item = mRetriever.getRandomItem();
+                if (item == null) {
+                    say("No song to play :-(");
+                    return;
+                }
+
+                // set the source of the media player a a content URI
+                createMediaPlayerIfNeeded();
+                mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+                mPlayer.setDataSource(getApplicationContext(), item.getURI());
+                mSongTitle = item.getTitle();
+            }
+
+
+            mState = State.Preparing;
+            setUpAsForeground(mSongTitle + " (loading)");
+
+            // starts preparing the media player in the background. When it's done, it will call
+            // our OnPreparedListener (that is, the onPrepared() method on this class, since we set
+            // the listener to 'this').
+            //
+            // Until the media player is prepared, we *cannot* call start() on it!
+            mPlayer.prepareAsync();
+
+            // If we are streaming from the internet, we want to hold a Wifi lock, which prevents
+            // the Wifi radio from going to sleep while the song is playing. If, on the other hand,
+            // we are *not* streaming, we want to release the lock if we were holding it before.
+            if (mIsStreaming) mWifiLock.acquire();
+            else if (mWifiLock.isHeld()) mWifiLock.release();
+        }
+        catch (IOException ex) {
+            Log.e("MusicService", "IOException playing next song: " + ex.getMessage());
+            ex.printStackTrace();
+        }
+    }
+
+    /** Called when media player is done playing current song. */
+    @Override
+    public void onCompletion(MediaPlayer player) {
+        // The media player finished playing the current song, so we go ahead and start the next.
+        playNextSong(null);
+    }
+
+    /** Called when media player is done preparing. */
+    @Override
+    public void onPrepared(MediaPlayer player) {
+        // The media player is done preparing. That means we can start playing!
+        mState = State.Playing;
+        updateNotification(mSongTitle + " (playing)");
+        configAndStartMediaPlayer();
+    }
+
+    /** Updates the notification. */
+    void updateNotification(String text) {
+        PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
+                new Intent(getApplicationContext(), MainActivity.class),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        mNotification.setLatestEventInfo(getApplicationContext(), "RandomMusicPlayer", text, pi);
+        mNotificationManager.notify(NOTIFICATION_ID, mNotification);
+    }
+
+    /**
+     * Configures service as a foreground service. A foreground service is a service that's doing
+     * something the user is actively aware of (such as playing music), and must appear to the
+     * user as a notification. That's why we create the notification here.
+     */
+    void setUpAsForeground(String text) {
+        PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0,
+                new Intent(getApplicationContext(), MainActivity.class),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        mNotification = new Notification();
+        mNotification.tickerText = text;
+        mNotification.icon = R.drawable.ic_stat_playing;
+        mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
+        mNotification.setLatestEventInfo(getApplicationContext(), "RandomMusicPlayer",
+                text, pi);
+        startForeground(NOTIFICATION_ID, mNotification);
+    }
+
+    /**
+     * Called when there's an error playing media. When this happens, the media player goes to
+     * the Error state. We warn the user about the error and reset the media player.
+     */
+    @Override
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        Toast.makeText(getApplicationContext(), "Media player error! Resetting.",
+            Toast.LENGTH_SHORT).show();
+        Log.e(TAG, "Error: what=" + String.valueOf(what) + ", extra=" + String.valueOf(extra));
+
+        mState = State.Stopped;
+        relaxResources(true);
+        giveUpAudioFocus();
+        return true; // true indicates we handled the error
+    }
+
+    @Override
+    public void onGainedAudioFocus() {
+        Toast.makeText(getApplicationContext(), "gained audio focus.", Toast.LENGTH_SHORT).show();
+        mAudioFocus = AudioFocus.Focused;
+
+        // restart media player with new focus settings
+        if (mState == State.Playing)
+            configAndStartMediaPlayer();
+    }
+
+    @Override
+    public void onLostAudioFocus(boolean canDuck) {
+        Toast.makeText(getApplicationContext(), "lost audio focus." + (canDuck ? "can duck" :
+            "no duck"), Toast.LENGTH_SHORT).show();
+        mAudioFocus = canDuck ? AudioFocus.NoFocusCanDuck : AudioFocus.NoFocusNoDuck;
+
+        // start/restart/pause media player with new focus settings
+        if (mPlayer != null && mPlayer.isPlaying())
+            configAndStartMediaPlayer();
+    }
+
+    @Override
+    public void onMusicRetrieverPrepared() {
+        // Done retrieving!
+        mState = State.Stopped;
+
+        // If the flag indicates we should start playing after retrieving, let's do that now.
+        if (mStartPlayingAfterRetrieve) {
+            tryToGetAudioFocus();
+            playNextSong(mWhatToPlayAfterRetrieve == null ?
+                    null : mWhatToPlayAfterRetrieve.toString());
+        }
+    }
+
+
+    @Override
+    public void onDestroy() {
+        // Service is being killed, so make sure we release our resources
+        mState = State.Stopped;
+        relaxResources(true);
+        giveUpAudioFocus();
+    }
+
+    @Override
+    public IBinder onBind(Intent arg0) {
+        return null;
+    }
+}
diff --git a/samples/RandomMusicPlayer/src/com/example/android/musicplayer/PrepareMusicRetrieverTask.java b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/PrepareMusicRetrieverTask.java
new file mode 100644
index 0000000..fd114c8
--- /dev/null
+++ b/samples/RandomMusicPlayer/src/com/example/android/musicplayer/PrepareMusicRetrieverTask.java
@@ -0,0 +1,50 @@
+/*   
+ * Copyright (C) 2011 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.example.android.musicplayer;
+
+import android.os.AsyncTask;
+
+/**
+ * Asynchronous task that prepares a MusicRetriever. This asynchronous task essentially calls
+ * {@link MusicRetriever#prepare()} on a {@link MusicRetriever}, which may take some time to
+ * run. Upon finishing, it notifies the indicated {@MusicRetrieverPreparedListener}.
+ */
+public class PrepareMusicRetrieverTask extends AsyncTask<Void, Void, Void> {
+    MusicRetriever mRetriever;
+    MusicRetrieverPreparedListener mListener;
+
+    public PrepareMusicRetrieverTask(MusicRetriever retriever,
+            MusicRetrieverPreparedListener listener) {
+        mRetriever = retriever;
+        mListener = listener;
+    }
+
+    @Override
+    protected Void doInBackground(Void... arg0) {
+        mRetriever.prepare();
+        return null;
+    }
+
+    @Override
+    protected void onPostExecute(Void result) {
+        mListener.onMusicRetrieverPrepared();
+    }
+
+    public interface MusicRetrieverPreparedListener {
+        public void onMusicRetrieverPrepared();
+    }
+}