am f6a28267: AI 149721: Import Portuguese translations.

Merge commit 'f6a28267503f50548169666009ff3605d82c9e67' into donut

* commit 'f6a28267503f50548169666009ff3605d82c9e67':
  AI 149721: Import Portuguese translations.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 533eb05..7659377 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -21,6 +21,7 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <application android:icon="@drawable/app_music"
         android:label="@string/musicbrowserlabel"
diff --git a/res/layout-land-finger/music_library.xml b/res/layout-land-finger/music_library.xml
index 2f3019f..8d912e8 100644
--- a/res/layout-land-finger/music_library.xml
+++ b/res/layout-land-finger/music_library.xml
@@ -31,8 +31,9 @@
 
         <Button
             android:id="@+id/browse_button"
-            android:layout_width="wrap_content"
+            android:layout_width="0dip"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:background="@drawable/main_menu_button"
             android:drawableTop="@drawable/ic_mp_screen_artists"
             android:text="@string/browse_menu"
@@ -46,8 +47,9 @@
 
         <Button
             android:id="@+id/albums_button"
-            android:layout_width="wrap_content"
+            android:layout_width="0dip"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:background="@drawable/main_menu_button"
             android:drawableTop="@drawable/ic_mp_screen_albums"
             android:text="@string/albums_menu"
@@ -61,8 +63,9 @@
 
         <Button
             android:id="@+id/tracks_button"
-            android:layout_width="wrap_content"
+            android:layout_width="0dip"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:background="@drawable/main_menu_button"
             android:drawableTop="@drawable/ic_mp_screen_tracks"
             android:text="@string/tracks_menu"
@@ -76,8 +79,9 @@
 
         <Button
             android:id="@+id/playlists_button"
-            android:layout_width="wrap_content"
+            android:layout_width="0dip"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:background="@drawable/main_menu_button"
             android:drawableTop="@drawable/ic_mp_screen_playlists"
             android:text="@string/playlists_menu"
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 23f76c0..8ca4408 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -26,10 +26,10 @@
     <item quantity="one">"1 Album"</item>
     <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> Alben"</item>
   </plurals>
-    <string name="goto_start">"Bibliothek"</string>
+    <string name="goto_start">"Startübersicht"</string>
     <string name="goto_playback">"Wiedergeben"</string>
-    <string name="party_shuffle">"Party-Shuffle"</string>
-    <string name="party_shuffle_off">"Party-Shuffle deaktivieren"</string>
+    <string name="party_shuffle">"Zufallswiedergabe (Party)"</string>
+    <string name="party_shuffle_off">"Zufallswiedergabe (Party) deaktivieren"</string>
     <string name="delete_item">"Löschen"</string>
     <string name="shuffle_all">"Alle zufällig wiedergeben"</string>
     <string name="play_all">"Alle wiedergeben"</string>
@@ -43,7 +43,7 @@
   </plurals>
     <string name="scanning">"SD-Karte wird gelesenen..."</string>
     <string name="nowplaying_title">"Aktuelle Wiedergabe"</string>
-    <string name="partyshuffle_title">"Party-Shuffle"</string>
+    <string name="partyshuffle_title">"Zufallswiedergabe (Party)"</string>
     <string name="artists_title">"Interpreten"</string>
     <string name="albums_menu">"Alben"</string>
     <string name="albums_title">"Alben"</string>
@@ -92,7 +92,7 @@
     <item quantity="one">"1 Titel zur Playlist hinzugefügt"</item>
     <item quantity="other">"%d Titel zur Playlist hinzugefügt."</item>
   </plurals>
-    <string name="emptyplaylist">"Playlist ist leer"</string>
+    <string name="emptyplaylist">"Ausgewählte Playlist ist leer"</string>
     <string name="create_playlist_create_text">"Speichern"</string>
     <string name="create_playlist_overwrite_text">"Überschreiben"</string>
     <string name="service_start_error_title">"Problem bei der Wiedergabe"</string>
@@ -126,14 +126,14 @@
     <string name="remove_from_playlist">"Von Playlist entfernen"</string>
     <string name="streamloadingtext">"Verbindung mit <xliff:g id="HOST">%s</xliff:g> wird hergestellt"</string>
     <string name="mediasearch">"Nach %s suchen mithilfe von:"</string>
-    <string name="working_artists">"Interpreten..."</string>
+    <string name="working_artists">"Künstler…"</string>
     <string name="working_albums">"Alben…"</string>
     <string name="working_songs">"Lieder…"</string>
     <string name="working_playlists">"Playlists…"</string>
     <string name="loading">"Wird geladen"</string>
-    <string name="sort_by_track">"Tracks"</string>
+    <string name="sort_by_track">"Titel"</string>
     <string name="sort_by_album">"Alben"</string>
-    <string name="sort_by_artist">"Interpreten"</string>
-    <string name="music_picker_title">"Musiktrack auswählen"</string>
+    <string name="sort_by_artist">"Künstler"</string>
+    <string name="music_picker_title">"Musiktitel auswählen"</string>
     <string name="gadget_track">"Track <xliff:g id="TRACK_NUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/res/values-es-rUS-finger/strings2.xml b/res/values-es-rUS-finger/strings2.xml
new file mode 100644
index 0000000..120ac61
--- /dev/null
+++ b/res/values-es-rUS-finger/strings2.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="notification_artist_album">"Segmento <xliff:g id="ALBUM">%2$s</xliff:g>"\n"<xliff:g id="ARTIST">%1$s</xliff:g>"</string>
+</resources>
diff --git a/res/values-es-rUS-keysexposed/strings.xml b/res/values-es-rUS-keysexposed/strings.xml
new file mode 100644
index 0000000..279e05a
--- /dev/null
+++ b/res/values-es-rUS-keysexposed/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="create_playlist_create_text_prompt">"Nombre de lista de reproducción"</string>
+    <string name="rename_playlist_same_prompt">"Cambiar nombre \"<xliff:g id="PLAYLIST">%s</xliff:g>\" por"</string>
+    <string name="rename_playlist_diff_prompt">"Cambiar nombre \"<xliff:g id="PLAYLIST">%s</xliff:g>\" por"</string>
+</resources>
diff --git a/res/values-es-rUS-keyshidden/strings.xml b/res/values-es-rUS-keyshidden/strings.xml
new file mode 100644
index 0000000..0b3c3a1
--- /dev/null
+++ b/res/values-es-rUS-keyshidden/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="create_playlist_create_text_prompt">"Abre el teclado para asignar un nombre a tu lista de reproducción nueva o selecciona Guardar para nombrarla \"%s\"."</string>
+    <string name="rename_playlist_same_prompt">"Abrir el teclado para asignar un nombre nuevo a la lista de reproducción \"<xliff:g id="PLAYLIST">%s</xliff:g>\"."</string>
+    <string name="rename_playlist_diff_prompt">"Abre el teclado para asignar un nombre nuevo a la lista de reproducción \"<xliff:g id="PLAYLIST">%s</xliff:g>\" o selecciona Guardar para nombrarla \"%s\"."</string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..c90fc7b
--- /dev/null
+++ b/res/values-es-rUS/strings.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 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 xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="onesong">"1 canción"</string>
+  <plurals name="Nsongs">
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> canciones"</item>
+  </plurals>
+  <plurals name="Nsongscomp">
+    <item quantity="other">"<xliff:g id="COUNT_FOR_ARTIST">%2$d</xliff:g> de <xliff:g id="TOTAL_COUNT">%1$d</xliff:g> canciones"</item>
+  </plurals>
+  <plurals name="Nalbums">
+    <item quantity="one">"1 álbum"</item>
+    <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> álbumes"</item>
+  </plurals>
+    <string name="goto_start">"Biblioteca"</string>
+    <string name="goto_playback">"Reproducir"</string>
+    <string name="party_shuffle">"Party shuffle"</string>
+    <string name="party_shuffle_off">"Party shuffle desactivado"</string>
+    <string name="delete_item">"Eliminar"</string>
+    <string name="shuffle_all">"Arrastrar todo"</string>
+    <string name="play_all">"Reproducir todo"</string>
+    <string name="delete_artist_desc">"Todas las canciones de <xliff:g id="ARTIST">%s</xliff:g> se eliminarán definitivamente de la tarjeta SD."</string>
+    <string name="delete_album_desc">"El álbum \"<xliff:g id="ALBUM">%s</xliff:g>\" se eliminará definitivamente de la tarjeta SD.\n."</string>
+    <string name="delete_song_desc">"\"<xliff:g id="SONG">%s</xliff:g>\" se eliminará definitivamente de la tarjeta SD."</string>
+    <string name="delete_confirm_button_text">"Aceptar"</string>
+  <plurals name="NNNtracksdeleted">
+    <item quantity="one">"Se eliminó 1 canción."</item>
+    <item quantity="other">"Se eliminaron <xliff:g id="SONGS_TO_DELETE">%d</xliff:g> canciones."</item>
+  </plurals>
+    <string name="scanning">"Escaneando tarjeta SD..."</string>
+    <string name="nowplaying_title">"Reproduciendo ahora"</string>
+    <string name="partyshuffle_title">"Party shuffle"</string>
+    <string name="artists_title">"Artistas"</string>
+    <string name="albums_menu">"Álbumes"</string>
+    <string name="albums_title">"Álbumes"</string>
+    <string name="tracks_menu">"Canciones"</string>
+    <string name="tracks_title">"Canciones"</string>
+    <string name="playlists_menu">"Listas de reproducción"</string>
+    <string name="playlists_title">"Listas de reproducción"</string>
+    <string name="videos_title">"Videos"</string>
+    <string name="all_title">"Todos los medios"</string>
+    <string name="browse_menu">"Artistas"</string>
+    <string name="search_title">"Buscar"</string>
+    <string name="no_tracks_title">"No hay canciones"</string>
+    <string name="no_videos_title">"No hay videos"</string>
+    <string name="no_playlists_title">"No hay listas de reproducción"</string>
+    <string name="delete_playlist_menu">"Eliminar"</string>
+    <string name="edit_playlist_menu">"Editar"</string>
+    <string name="rename_playlist_menu">"Cambiar nombre"</string>
+    <string name="playlist_deleted_message">"Lista de reproducción eliminada."</string>
+    <string name="playlist_renamed_message">"Se cambió el nombre de la lista de reproducción."</string>
+    <string name="recentlyadded">"Últimos agregados"</string>
+    <string name="recentlyadded_title">"Últimos agregados"</string>
+    <string name="podcasts_listitem">"Podcasts"</string>
+    <string name="podcasts_title">"Podcasts"</string>
+    <string name="sdcard_missing_title">"No hay tarjeta SD"</string>
+    <string name="sdcard_missing_message">"Tu teléfono no tiene una tarjeta SD."</string>
+    <string name="sdcard_busy_title">"Tarjeta SD no disponible"</string>
+    <string name="sdcard_busy_message">"Lo sentimos, pero tu tarjeta SD está ocupada."</string>
+    <string name="sdcard_error_title">"Error de tarjeta SD"</string>
+    <string name="sdcard_error_message">"Se encontró un error en tu tarjeta SD."</string>
+    <string name="unknown_artist_name">"Artista desconocido"</string>
+    <string name="unknown_album_name">"Álbum desconocido"</string>
+    <string name="shuffle_on_notif">"El shuffle está activado."</string>
+    <string name="shuffle_off_notif">"El shuffle está desactivado."</string>
+    <string name="repeat_off_notif">"Repetir está desactivado."</string>
+    <string name="repeat_current_notif">"Repitiendo canción actual."</string>
+    <string name="repeat_all_notif">"Repitiendo todas las canciones."</string>
+    <string name="ringtone_menu">"Usar como tono de timbre del teléfono"</string>
+    <string name="ringtone_menu_short">"Usar como tono de timbre"</string>
+    <string name="ringtone_set">"\"%s\" definidos como tono de timbre del teléfono."</string>
+    <string name="play_selection">"Reproducir"</string>
+    <string name="add_to_playlist">"Agregar a lista de reproducción"</string>
+    <string name="queue">"Lista de reproducción actual"</string>
+    <string name="new_playlist">"Nuevos"</string>
+    <string name="new_playlist_name_template">"Lista de reproducción nueva <xliff:g id="NUMBER">%d</xliff:g>"</string>
+  <plurals name="NNNtrackstoplaylist">
+    <item quantity="one">"Se agregó una canción a la lista de reproducción."</item>
+    <item quantity="other">"%d canciones agregadas a la lista de reproducción."</item>
+  </plurals>
+    <string name="emptyplaylist">"La lista de reproducción seleccionada está vacía."</string>
+    <string name="create_playlist_create_text">"Guardar"</string>
+    <string name="create_playlist_overwrite_text">"Sobreescribir"</string>
+    <string name="service_start_error_title">"Problema de reproducción"</string>
+    <string name="service_start_error_msg">"Lo sentimos, pero la canción no se pudo reproducir."</string>
+    <string name="service_start_error_button">"Aceptar"</string>
+  <string-array name="weeklist">
+    <item>"1 semana"</item>
+    <item>"2 semanas"</item>
+    <item>"3 semanas"</item>
+    <item>"4 semanas"</item>
+    <item>"5 semanas"</item>
+    <item>"6 semanas"</item>
+    <item>"7 semanas"</item>
+    <item>"8 semanas"</item>
+    <item>"9 semanas"</item>
+    <item>"10 semanas"</item>
+    <item>"11 semanas"</item>
+    <item>"12 semanas"</item>
+  </string-array>
+    <string name="weekpicker_set">"Finalizado"</string>
+    <string name="weekpicker_title">"Fijar hora"</string>
+    <string name="save_as_playlist">"Guardar como lista de reproducción"</string>
+    <string name="clear_playlist">"Borrar lista de reproducción"</string>
+    <string name="musicbrowserlabel">"Música"</string>
+    <string name="musicshortcutlabel">"Lista de reproducción de música"</string>
+    <string name="mediaplaybacklabel">"Música"</string>
+    <string name="videobrowserlabel">"Videos"</string>
+    <string name="mediapickerlabel">"Música"</string>
+    <string name="playback_failed">"Lo sentimos, pero el reproductor no admite este tipo de archivo de audio."</string>
+    <string name="cancel">"Cancelar"</string>
+    <string name="remove_from_playlist">"Suprimir de la lista de reproducción"</string>
+    <string name="streamloadingtext">"Conectándose a <xliff:g id="HOST">%s</xliff:g>"</string>
+    <string name="mediasearch">"Buscar %s usando:"</string>
+    <string name="working_artists">"Artistas..."</string>
+    <string name="working_albums">"Álbumes..."</string>
+    <string name="working_songs">"Canciones..."</string>
+    <string name="working_playlists">"Listas de reproducción..."</string>
+    <string name="loading">"Cargando"</string>
+    <string name="sort_by_track">"Pista"</string>
+    <string name="sort_by_album">"Álbumes"</string>
+    <string name="sort_by_artist">"Artistas"</string>
+    <string name="music_picker_title">"Seleccionar pista de música"</string>
+    <string name="gadget_track">"Pista <xliff:g id="TRACK_NUMBER">%d</xliff:g>"</string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index e45f2c0..00c743f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -49,8 +49,8 @@
     <string name="albums_title">"Álbumes"</string>
     <string name="tracks_menu">"Canciones"</string>
     <string name="tracks_title">"Canciones"</string>
-    <string name="playlists_menu">"Listas reprod."</string>
-    <string name="playlists_title">"Listas reprod."</string>
+    <string name="playlists_menu">"Listas de reproducción"</string>
+    <string name="playlists_title">"Listas de reproducción"</string>
     <string name="videos_title">"Vídeos"</string>
     <string name="all_title">"Todos los medios"</string>
     <string name="browse_menu">"Artistas"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 6a24ff5..b434be0 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -26,7 +26,7 @@
     <item quantity="one">"1 album"</item>
     <item quantity="other">"<xliff:g id="COUNT">%d</xliff:g> albums"</item>
   </plurals>
-    <string name="goto_start">"Bibliothèque"</string>
+    <string name="goto_start">"Médiathèque"</string>
     <string name="goto_playback">"Lecture"</string>
     <string name="party_shuffle">"Lecture aléatoire"</string>
     <string name="party_shuffle_off">"La lecture aléatoire est désactivée."</string>
@@ -76,7 +76,7 @@
     <string name="unknown_artist_name">"Artiste inconnu"</string>
     <string name="unknown_album_name">"Album inconnu"</string>
     <string name="shuffle_on_notif">"La lecture aléatoire est activée."</string>
-    <string name="shuffle_off_notif">"La lecture aléatoire est désactivée."</string>
+    <string name="shuffle_off_notif">"Le mode aléatoire est désactivé."</string>
     <string name="repeat_off_notif">"La lecture en boucle est désactivée."</string>
     <string name="repeat_current_notif">"Lecture en boucle de la chanson en écoute."</string>
     <string name="repeat_all_notif">"Lecture en boucle de toutes les chansons"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 9029805..6b0bc1a 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -64,7 +64,7 @@
     <string name="playlist_deleted_message">"プレイリストを削除しました。"</string>
     <string name="playlist_renamed_message">"プレイリストの名前を変更しました。"</string>
     <string name="recentlyadded">"最近追加したアイテム"</string>
-    <string name="recentlyadded_title">"最近追加したアイテム"</string>
+    <string name="recentlyadded_title">"最近追加した項目"</string>
     <string name="podcasts_listitem">"ポッドキャスト"</string>
     <string name="podcasts_title">"ポッドキャスト"</string>
     <string name="sdcard_missing_title">"SDカードがありません"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index ca75826..1b5a390 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -28,8 +28,8 @@
   </plurals>
     <string name="goto_start">"Biblioteka"</string>
     <string name="goto_playback">"Odtwórz"</string>
-    <string name="party_shuffle">"Losowo – tryb imprezy"</string>
-    <string name="party_shuffle_off">"Wyłącz tryb imprezy"</string>
+    <string name="party_shuffle">"Losowo w trybie imprezy"</string>
+    <string name="party_shuffle_off">"Wyłączono losowe odtwarzanie w trybie imprezy"</string>
     <string name="delete_item">"Usuń"</string>
     <string name="shuffle_all">"Wszystkie losowo"</string>
     <string name="play_all">"Odtwórz wszystko"</string>
@@ -90,7 +90,7 @@
     <string name="new_playlist_name_template">"Nowa playlista <xliff:g id="NUMBER">%d</xliff:g>"</string>
   <plurals name="NNNtrackstoplaylist">
     <item quantity="one">"Dodano 1 utwór do playlisty."</item>
-    <item quantity="other">"Utworów dodanych do playlisty: %d."</item>
+    <item quantity="other">"%d utworów dodano do listy odtwarzania."</item>
   </plurals>
     <string name="emptyplaylist">"Wybrana playlista jest pusta."</string>
     <string name="create_playlist_create_text">"Zapisz"</string>
@@ -129,11 +129,11 @@
     <string name="working_artists">"Wykonawcy…"</string>
     <string name="working_albums">"Albumy…"</string>
     <string name="working_songs">"Utwory…"</string>
-    <string name="working_playlists">"Playlisty…"</string>
+    <string name="working_playlists">"Listy odtwarzania..."</string>
     <string name="loading">"Ładowanie"</string>
     <string name="sort_by_track">"Utwory"</string>
     <string name="sort_by_album">"Albumy"</string>
     <string name="sort_by_artist">"Wykonawcy"</string>
     <string name="music_picker_title">"Wybierz utwór muzyczny"</string>
-    <string name="gadget_track">"Utwór <xliff:g id="TRACK_NUMBER">%d</xliff:g>"</string>
+    <string name="gadget_track">"Ścieżka <xliff:g id="TRACK_NUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a6f51c6..4d631d8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -279,5 +279,8 @@
 
     <!-- Title for track number in music gadget -->
     <string name="gadget_track">Track <xliff:g id="track_number">%d</xliff:g></string>
+
+    <!-- Toast after streamStarter activity receives PLAYBACK_COMPLETE in case of an error -->
+    <string name="fail_to_start_stream">Failed to play the requested stream.</string>
 </resources>
 
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
index 1bff884..e1ac60b 100644
--- a/res/xml/searchable.xml
+++ b/res/xml/searchable.xml
@@ -18,6 +18,6 @@
     android:label="@string/search_title"
 
     android:searchSuggestAuthority="media"
-    android:searchSuggestPath="external/audio"
+    android:searchSuggestPath="external/audio/search"
     android:searchSuggestIntentAction="android.intent.action.VIEW"
 />
diff --git a/src/com/android/music/AlbumBrowserActivity.java b/src/com/android/music/AlbumBrowserActivity.java
index 020c0a6..5488504 100644
--- a/src/com/android/music/AlbumBrowserActivity.java
+++ b/src/com/android/music/AlbumBrowserActivity.java
@@ -300,6 +300,7 @@
         
         Intent i = new Intent();
         i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
+        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         
         title = mCurrentAlbumName;
         query = mCurrentArtistNameForAlbum + " " + mCurrentAlbumName;
@@ -416,10 +417,8 @@
             
         String[] cols = new String[] {
                 MediaStore.Audio.Albums._ID,
-                MediaStore.Audio.Albums.ALBUM,
-                MediaStore.Audio.Albums.ALBUM_KEY,
                 MediaStore.Audio.Albums.ARTIST,
-                MediaStore.Audio.Albums.NUMBER_OF_SONGS,
+                MediaStore.Audio.Albums.ALBUM,
                 MediaStore.Audio.Albums.ALBUM_ART
         };
         Cursor ret = null;
@@ -454,7 +453,6 @@
         private final BitmapDrawable mDefaultAlbumIcon;
         private int mAlbumIdx;
         private int mArtistIdx;
-        private int mNumSongsIdx;
         private int mAlbumArtIndex;
         private final Resources mResources;
         private final StringBuilder mStringBuilder = new StringBuilder();
@@ -468,10 +466,9 @@
         private String mConstraint = null;
         private boolean mConstraintIsValid = false;
         
-        class ViewHolder {
+        static class ViewHolder {
             TextView line1;
             TextView line2;
-            TextView duration;
             ImageView play_indicator;
             ImageView icon;
         }
@@ -515,7 +512,6 @@
             if (cursor != null) {
                 mAlbumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM);
                 mArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ARTIST);
-                mNumSongsIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS);
                 mAlbumArtIndex = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM_ART);
                 
                 if (mIndexer != null) {
@@ -541,7 +537,6 @@
            ViewHolder vh = new ViewHolder();
            vh.line1 = (TextView) v.findViewById(R.id.line1);
            vh.line2 = (TextView) v.findViewById(R.id.line2);
-           vh.duration = (TextView) v.findViewById(R.id.duration);
            vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
            vh.icon = (ImageView) v.findViewById(R.id.icon);
            vh.icon.setBackgroundDrawable(mDefaultAlbumIcon);
diff --git a/src/com/android/music/ArtistAlbumBrowserActivity.java b/src/com/android/music/ArtistAlbumBrowserActivity.java
index 8486672..c005d04 100644
--- a/src/com/android/music/ArtistAlbumBrowserActivity.java
+++ b/src/com/android/music/ArtistAlbumBrowserActivity.java
@@ -410,6 +410,7 @@
         
         Intent i = new Intent();
         i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
+        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         
         if (mCurrentArtistId != null) {
             title = mCurrentArtistName;
@@ -518,7 +519,7 @@
         private String mConstraint = null;
         private boolean mConstraintIsValid = false;
         
-        class ViewHolder {
+        static class ViewHolder {
             TextView line1;
             TextView line2;
             ImageView play_indicator;
@@ -659,12 +660,6 @@
 
             int numsongs = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS));
             int numartistsongs = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST));
-            int first = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.FIRST_YEAR));
-            int last = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.LAST_YEAR));
-
-            if (first == 0) {
-                first = last;
-            }
 
             final StringBuilder builder = mBuffer;
             builder.delete(0, builder.length());
@@ -724,8 +719,6 @@
                     MediaStore.Audio.Albums.ALBUM,
                     MediaStore.Audio.Albums.NUMBER_OF_SONGS,
                     MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST,
-                    MediaStore.Audio.Albums.FIRST_YEAR,
-                    MediaStore.Audio.Albums.LAST_YEAR,
                     MediaStore.Audio.Albums.ALBUM_ART
             };
             Cursor c = MusicUtils.query(mActivity,
diff --git a/src/com/android/music/IMediaPlaybackService.aidl b/src/com/android/music/IMediaPlaybackService.aidl
index 5698cc5..1d27057 100644
--- a/src/com/android/music/IMediaPlaybackService.aidl
+++ b/src/com/android/music/IMediaPlaybackService.aidl
@@ -21,8 +21,8 @@
 
 interface IMediaPlaybackService
 {
-    void openfile(String path);
-    void openfileAsync(String path);
+    void openFile(String path, boolean oneShot);
+    void openFileAsync(String path);
     void open(in int [] list, int position);
     int getQueuePosition();
     boolean isPlaying();
diff --git a/src/com/android/music/MediaAppWidgetProvider.java b/src/com/android/music/MediaAppWidgetProvider.java
index f20e91a..1c39466 100644
--- a/src/com/android/music/MediaAppWidgetProvider.java
+++ b/src/com/android/music/MediaAppWidgetProvider.java
@@ -117,7 +117,6 @@
         final Resources res = service.getResources();
         final RemoteViews views = new RemoteViews(service.getPackageName(), R.layout.album_appwidget);
         
-        final int track = service.getQueuePosition() + 1;
         CharSequence titleName = service.getTrackName();
         CharSequence artistName = service.getArtistName();
         CharSequence errorState = null;
diff --git a/src/com/android/music/MediaButtonIntentReceiver.java b/src/com/android/music/MediaButtonIntentReceiver.java
index 44d76db..5840721 100644
--- a/src/com/android/music/MediaButtonIntentReceiver.java
+++ b/src/com/android/music/MediaButtonIntentReceiver.java
@@ -102,23 +102,16 @@
 
             if (command != null) {
                 if (action == KeyEvent.ACTION_DOWN) {
-                    if (!mDown) {
-                        // only if this isn't a repeat event
-                        
-                        if (MediaPlaybackService.CMDTOGGLEPAUSE.equals(command)) {
-                            // We're not using the original time of the event as the
-                            // base here, because in some cases it can take more than
-                            // one second for us to receive the event, in which case
-                            // we would go immediately to auto shuffle mode, even if
-                            // the user didn't long press.
-                            mHandler.sendMessageDelayed(
-                                    mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context),
-                                    LONG_PRESS_DELAY);
+                    if (mDown) {
+                        if (MediaPlaybackService.CMDTOGGLEPAUSE.equals(command)
+                                && mLastClickTime != 0 
+                                && eventtime - mLastClickTime > LONG_PRESS_DELAY) {
+                            mHandler.sendMessage(
+                                    mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context));
                         }
-                        
-                        SharedPreferences pref = context.getSharedPreferences("Music", 
-                                Context.MODE_WORLD_READABLE | Context.MODE_WORLD_WRITEABLE);
-                        String q = pref.getString("queue", "");
+                    } else {
+                        // if this isn't a repeat event
+
                         // The service may or may not be running, but we need to send it
                         // a command.
                         Intent i = new Intent(context, MediaPlaybackService.class);
diff --git a/src/com/android/music/MediaPickerActivity.java b/src/com/android/music/MediaPickerActivity.java
index 9ef6375..220642e 100644
--- a/src/com/android/music/MediaPickerActivity.java
+++ b/src/com/android/music/MediaPickerActivity.java
@@ -223,7 +223,7 @@
     private String mLastYear;
     private String mWhereClause;
 
-    class PickListAdapter extends SimpleCursorAdapter {
+    static class PickListAdapter extends SimpleCursorAdapter {
         int mTitleIdx;
         int mArtistIdx;
         int mAlbumIdx;
diff --git a/src/com/android/music/MediaPlaybackActivity.java b/src/com/android/music/MediaPlaybackActivity.java
index e04b73e..8f47a40 100644
--- a/src/com/android/music/MediaPlaybackActivity.java
+++ b/src/com/android/music/MediaPlaybackActivity.java
@@ -21,11 +21,14 @@
 import android.app.SearchManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.media.MediaFile;
@@ -65,7 +68,7 @@
     
     private boolean mOneShot = false;
     private boolean mSeeking = false;
-    private boolean mTrackball;
+    private boolean mDeviceHasNoDpad;
     private long mStartSeekPos = 0;
     private long mLastSeekEventTime;
     private IMediaPlaybackService mService = null;
@@ -78,7 +81,6 @@
     private Worker mAlbumArtWorker;
     private AlbumArtHandler mAlbumArtHandler;
     private Toast mToast;
-    private boolean mRelaunchAfterConfigChange;
     private int mTouchSlop;
 
     public MediaPlaybackActivity()
@@ -129,8 +131,8 @@
         mNextButton.setRepeatListener(mFfwdListener, 260);
         seekmethod = 1;
 
-        mTrackball = true; /* (See bug 1044348) (getResources().getConfiguration().navigation == 
-            Resources.Configuration.NAVIGATION_TRACKBALL);*/
+        mDeviceHasNoDpad = (getResources().getConfiguration().navigation != 
+            Configuration.NAVIGATION_DPAD);
         
         mQueueButton = (ImageButton) findViewById(R.id.curplaylist);
         mQueueButton.setOnClickListener(mQueueListener);
@@ -146,7 +148,6 @@
         mProgress.setMax(1000);
         
         if (icicle != null) {
-            mRelaunchAfterConfigChange = icicle.getBoolean("configchange");
             mOneShot = icicle.getBoolean("oneshot");
         } else {
             mOneShot = getIntent().getBooleanExtra("oneshot", false);
@@ -277,12 +278,15 @@
             return true;
         }
         
-        boolean knownartist = !MediaFile.UNKNOWN_STRING.equals(artist);
-        boolean knownalbum = !MediaFile.UNKNOWN_STRING.equals(album);
+        boolean knownartist =
+            (artist != null) && !MediaFile.UNKNOWN_STRING.equals(artist);
+
+        boolean knownalbum =
+            (album != null) && !MediaFile.UNKNOWN_STRING.equals(album);
         
         if (knownartist && view.equals(mArtistName.getParent())) {
             title = artist;
-            query = artist.toString();
+            query = artist;
             mime = MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE;
         } else if (knownalbum && view.equals(mAlbumName.getParent())) {
             title = album;
@@ -293,6 +297,12 @@
             }
             mime = MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE;
         } else if (view.equals(mTrackName.getParent()) || !knownartist || !knownalbum) {
+            if ((song == null) || MediaFile.UNKNOWN_STRING.equals(song)) {
+                // A popup of the form "Search for null/'' using ..." is pretty
+                // unhelpful, plus, we won't find any way to buy it anyway.
+                return true;
+            }
+
             title = song;
             if (knownartist) {
                 query = artist + " " + song;
@@ -430,12 +440,12 @@
         mHandler.removeMessages(REFRESH);
         unregisterReceiver(mStatusListener);
         MusicUtils.unbindFromService(this);
+        mService = null;
         super.onStop();
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        outState.putBoolean("configchange", getChangingConfigurations() != 0);
         outState.putBoolean("oneshot", mOneShot);
         super.onSaveInstanceState(outState);
     }
@@ -484,20 +494,21 @@
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         super.onCreateOptionsMenu(menu);
-        // Don't show the menu items if we got launched by path/filedescriptor, since
-        // those tend to not be in the media database.
-        if (MusicUtils.getCurrentAudioId() >= 0) {
-            if (!mOneShot) {
-                menu.add(0, GOTO_START, 0, R.string.goto_start).setIcon(R.drawable.ic_menu_music_library);
-                menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle); // icon will be set in onPrepareOptionsMenu()
-            }
+        // Don't show the menu items if we got launched by path/filedescriptor, or
+        // if we're in one shot mode. In most cases, these menu items are not
+        // useful in those modes, so for consistency we never show them in these
+        // modes, instead of tailoring them to the specific file being played.
+        if (MusicUtils.getCurrentAudioId() >= 0 && !mOneShot) {
+            menu.add(0, GOTO_START, 0, R.string.goto_start).setIcon(R.drawable.ic_menu_music_library);
+            menu.add(0, PARTY_SHUFFLE, 0, R.string.party_shuffle); // icon will be set in onPrepareOptionsMenu()
             SubMenu sub = menu.addSubMenu(0, ADD_TO_PLAYLIST, 0,
                     R.string.add_to_playlist).setIcon(android.R.drawable.ic_menu_add);
             MusicUtils.makePlaylistMenu(this, sub);
             menu.add(0, USE_AS_RINGTONE, 0, R.string.ringtone_menu_short).setIcon(R.drawable.ic_menu_set_as_ringtone);
             menu.add(0, DELETE_ITEM, 0, R.string.delete_item).setIcon(R.drawable.ic_menu_delete);
+            return true;
         }
-        return true;
+        return false;
     }
 
     @Override
@@ -701,7 +712,7 @@
             switch(keyCode)
             {
                 case KeyEvent.KEYCODE_DPAD_LEFT:
-                    if (mTrackball) {
+                    if (mDeviceHasNoDpad) {
                         break;
                     }
                     if (mService != null) {
@@ -722,7 +733,7 @@
                     mPosOverride = -1;
                     return true;
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
-                    if (mTrackball) {
+                    if (mDeviceHasNoDpad) {
                         break;
                     }
                     if (mService != null) {
@@ -780,7 +791,7 @@
                 return true;
 
             case KeyEvent.KEYCODE_DPAD_LEFT:
-                if (mTrackball) {
+                if (mDeviceHasNoDpad) {
                     break;
                 }
                 if (!mPrevButton.hasFocus()) {
@@ -789,7 +800,7 @@
                 scanBackward(repcnt, event.getEventTime() - event.getDownTime());
                 return true;
             case KeyEvent.KEYCODE_DPAD_RIGHT:
-                if (mTrackball) {
+                if (mDeviceHasNoDpad) {
                     break;
                 }
                 if (!mNextButton.hasFocus()) {
@@ -979,12 +990,14 @@
                 filename = uri.toString();
             }
             try {
-                mOneShot = true;
-                if (! mRelaunchAfterConfigChange) {
-                    mService.stop();
-                    mService.openfile(filename);
-                    mService.play();
+                if (! ContentResolver.SCHEME_CONTENT.equals(scheme) ||
+                        ! MediaStore.AUTHORITY.equals(uri.getAuthority())) {
+                    mOneShot = true;
                 }
+                mService.stop();
+                mService.openFile(filename, mOneShot);
+                mService.play();
+                setIntent(new Intent());
             } catch (Exception ex) {
                 Log.d("MediaPlaybackActivity", "couldn't start playback: " + ex);
             }
@@ -998,9 +1011,6 @@
     private ServiceConnection osc = new ServiceConnection() {
             public void onServiceConnected(ComponentName classname, IBinder obj) {
                 mService = IMediaPlaybackService.Stub.asInterface(obj);
-                if (MusicUtils.sService == null) {
-                    MusicUtils.sService = mService;
-                }
                 startPlayback();
                 try {
                     // Assume something is playing when the service says it is,
@@ -1273,7 +1283,7 @@
         }
     }
     
-    private class Worker implements Runnable {
+    private static class Worker implements Runnable {
         private final Object mLock = new Object();
         private Looper mLooper;
         
diff --git a/src/com/android/music/MediaPlaybackService.java b/src/com/android/music/MediaPlaybackService.java
index deedf27..995a050 100644
--- a/src/com/android/music/MediaPlaybackService.java
+++ b/src/com/android/music/MediaPlaybackService.java
@@ -45,13 +45,14 @@
 import android.os.SystemClock;
 import android.os.PowerManager.WakeLock;
 import android.provider.MediaStore;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.widget.RemoteViews;
 import android.widget.Toast;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneStateIntentReceiver;
 
 import java.io.IOException;
+import java.lang.ref.WeakReference;
 import java.util.Random;
 import java.util.Vector;
 
@@ -96,7 +97,6 @@
     public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous";
     public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next";
 
-    private static final int PHONE_CHANGED = 1;
     private static final int TRACK_ENDED = 1;
     private static final int RELEASE_WAKELOCK = 2;
     private static final int SERVER_DIED = 3;
@@ -105,7 +105,6 @@
     
     private MultiPlayer mPlayer;
     private String mFileToPlay;
-    private PhoneStateIntentReceiver mPsir;
     private int mShuffleMode = SHUFFLE_NONE;
     private int mRepeatMode = REPEAT_NONE;
     private int mMediaMountedCount = 0;
@@ -139,7 +138,7 @@
     private int mServiceStartId = -1;
     private boolean mServiceInUse = false;
     private boolean mResumeAfterCall = false;
-    private boolean mWasPlaying = false;
+    private boolean mIsSupposedToBePlaying = false;
     private boolean mQuietMode = false;
     
     private SharedPreferences mPreferences;
@@ -152,35 +151,28 @@
     // interval after which we stop the service when idle
     private static final int IDLE_DELAY = 60000; 
 
-    private Handler mPhoneHandler = new Handler() {
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
         @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case PHONE_CHANGED:
-                    Phone.State state = mPsir.getPhoneState();
-                    if (state == Phone.State.RINGING) {
-                        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
-                        int ringvolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
-                        if (ringvolume > 0) {
-                            mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
-                            pause();
-                        }
-                    } else if (state == Phone.State.OFFHOOK) {
-                        // pause the music while a conversation is in progress
-                        mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
-                        pause();
-                    } else if (state == Phone.State.IDLE) {
-                        // start playing again
-                        if (mResumeAfterCall) {
-                            // resume playback only if music was playing
-                            // when the call was answered
-                            startAndFadeIn();
-                            mResumeAfterCall = false;
-                        }
-                    }
-                    break;
-                default:
-                    break;
+        public void onCallStateChanged(int state, String incomingNumber) {
+            if (state == TelephonyManager.CALL_STATE_RINGING) {
+                AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+                int ringvolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
+                if (ringvolume > 0) {
+                    mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
+                    pause();
+                }
+            } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
+                // pause the music while a conversation is in progress
+                mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
+                pause();
+            } else if (state == TelephonyManager.CALL_STATE_IDLE) {
+                // start playing again
+                if (mResumeAfterCall) {
+                    // resume playback only if music was playing
+                    // when the call was answered
+                    startAndFadeIn();
+                    mResumeAfterCall = false;
+                }
             }
         }
     };
@@ -211,7 +203,7 @@
                     }
                     break;
                 case SERVER_DIED:
-                    if (mWasPlaying) {
+                    if (mIsSupposedToBePlaying) {
                         next(true);
                     } else {
                         // the server died when we were idle, so just
@@ -229,6 +221,7 @@
                         next(false);
                     } else {
                         notifyChange(PLAYBACK_COMPLETE);
+                        mIsSupposedToBePlaying = false;
                     }
                     break;
                 case RELEASE_WAKELOCK:
@@ -270,8 +263,6 @@
     };
 
     public MediaPlaybackService() {
-        mPsir = new PhoneStateIntentReceiver(this, mPhoneHandler);
-        mPsir.notifyPhoneCallState(PHONE_CHANGED);
     }
 
     @Override
@@ -301,7 +292,8 @@
         commandFilter.addAction(PREVIOUS_ACTION);
         registerReceiver(mIntentReceiver, commandFilter);
         
-        mPsir.registerIntent();
+        TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
         PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
         mWakeLock.setReferenceCounted(false);
@@ -318,21 +310,27 @@
         if (isPlaying()) {
             Log.e("MediaPlaybackService", "Service being destroyed while still playing.");
         }
-        // and for good measure, call mPlayer.stop(), which calls MediaPlayer.reset(), which
-        // releases the MediaPlayer's wake lock, if any.
-        mPlayer.stop();
+        // release all MediaPlayer resources, including the native player and wakelocks
+        mPlayer.release();
+        mPlayer = null;
         
+        // make sure there aren't any other messages coming
+        mDelayedStopHandler.removeCallbacksAndMessages(null);
+        mMediaplayerHandler.removeCallbacksAndMessages(null);
+
         if (mCursor != null) {
             mCursor.close();
             mCursor = null;
         }
 
+        TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+        tmgr.listen(mPhoneStateListener, 0);
+
         unregisterReceiver(mIntentReceiver);
         if (mUnmountReceiver != null) {
             unregisterReceiver(mUnmountReceiver);
             mUnmountReceiver = null;
         }
-        mPsir.unregisterIntent();
         mWakeLock.release();
         super.onDestroy();
     }
@@ -402,37 +400,37 @@
             // the same one as when the playlist was saved
             q = mPreferences.getString("queue", "");
         }
-        if (q != null && q.length() > 1) {
+        int qlen = q.length();
+        if (q != null && qlen > 1) {
             //Log.i("@@@@ service", "loaded queue: " + q);
-            String [] entries = q.split(";");
-            int len = entries.length;
-            ensurePlayListCapacity(len);
-            for (int i = 0; i < len; i++) {
-                if (newstyle) {
-                    String revhex = entries[i];
-                    int n = 0;
-                    for (int j = revhex.length() - 1; j >= 0 ; j--) {
-                        n <<= 4;
-                        char c = revhex.charAt(j);
-                        if (c >= '0' && c <= '9') {
-                            n += (c - '0');
-                        } else if (c >= 'a' && c <= 'f') {
-                            n += (10 + c - 'a');
-                        } else {
-                            // bogus playlist data
-                            len = 0;
-                            break;
-                        }
-                    }
-                    mPlayList[i] = n;
+            int plen = 0;
+            int n = 0;
+            int shift = 0;
+            for (int i = 0; i < qlen; i++) {
+                char c = q.charAt(i);
+                if (c == ';') {
+                    ensurePlayListCapacity(plen + 1);
+                    mPlayList[plen] = n;
+                    plen++;
+                    n = 0;
+                    shift = 0;
                 } else {
-                    mPlayList[i] = Integer.parseInt(entries[i]);
+                    if (c >= '0' && c <= '9') {
+                        n += ((c - '0') << shift);
+                    } else if (c >= 'a' && c <= 'f') {
+                        n += ((10 + c - 'a') << shift);
+                    } else {
+                        // bogus playlist data
+                        plen = 0;
+                        break;
+                    }
+                    shift += 4;
                 }
             }
-            mPlayListLen = len;
+            mPlayListLen = plen;
 
             int pos = mPreferences.getInt("curpos", 0);
-            if (pos < 0 || pos >= len) {
+            if (pos < 0 || pos >= mPlayListLen) {
                 // The saved playlist is bogus, discard it
                 mPlayListLen = 0;
                 return;
@@ -678,7 +676,7 @@
             // need to grow and copy the array for every
             // insert
             int [] newlist = new int[size * 2];
-            int len = mPlayListLen;
+            int len = mPlayList != null ? mPlayList.length : mPlayListLen;
             for (int i = 0; i < len; i++) {
                 newlist[i] = mPlayList[i];
             }
@@ -977,6 +975,12 @@
      */
     public void play() {
         if (mPlayer.isInitialized()) {
+            // if we are at the end of the song, go to the next song first
+            if (mRepeatMode != REPEAT_CURRENT &&
+                mPlayer.position() >= mPlayer.duration() - 2000) {
+                next(true);
+            }
+
             mPlayer.start();
             setForeground(true);
 
@@ -1005,8 +1009,6 @@
                         );
             }
             
-            Intent statusintent = new Intent("com.android.music.PLAYBACK_VIEWER");
-            statusintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
             Notification status = new Notification();
             status.contentView = views;
             status.flags |= Notification.FLAG_ONGOING_EVENT;
@@ -1014,10 +1016,10 @@
             status.contentIntent = PendingIntent.getActivity(this, 0,
                     new Intent("com.android.music.PLAYBACK_VIEWER"), 0);
             nm.notify(PLAYBACKSERVICE_STATUS, status);
-            if (!mWasPlaying) {
+            if (!mIsSupposedToBePlaying) {
                 notifyChange(PLAYSTATE_CHANGED);
             }
-            mWasPlaying = true;
+            mIsSupposedToBePlaying = true;
         } else if (mPlayListLen <= 0) {
             // This is mostly so that if you press 'play' on a bluetooth headset
             // without every having played anything before, it will still play
@@ -1040,7 +1042,7 @@
         }
         setForeground(false);
         if (remove_status_icon) {
-            mWasPlaying = false;
+            mIsSupposedToBePlaying = false;
         }
     }
 
@@ -1055,25 +1057,25 @@
      * Pauses playback (call play() to resume)
      */
     public void pause() {
-        if (isPlaying()) {
-            mPlayer.pause();
-            gotoIdleState();
-            setForeground(false);
-            mWasPlaying = false;
-            notifyChange(PLAYSTATE_CHANGED);
-            saveBookmarkIfNeeded();
+        synchronized(this) {
+            if (isPlaying()) {
+                mPlayer.pause();
+                gotoIdleState();
+                setForeground(false);
+                mIsSupposedToBePlaying = false;
+                notifyChange(PLAYSTATE_CHANGED);
+                saveBookmarkIfNeeded();
+            }
         }
     }
 
-    /** Returns whether playback is currently paused
+    /** Returns whether something is currently playing
      *
-     * @return true if playback is paused, false if not
+     * @return true if something is playing (or will be playing shortly, in case
+     * we're currently transitioning between tracks), false if not.
      */
     public boolean isPlaying() {
-        if (mPlayer.isInitialized()) {
-            return mPlayer.isPlaying();
-        }
-        return false;
+        return mIsSupposedToBePlaying;
     }
 
     /*
@@ -1208,6 +1210,7 @@
                         // all done
                         gotoIdleState();
                         notifyChange(PLAYBACK_COMPLETE);
+                        mIsSupposedToBePlaying = false;
                         return;
                     } else if (mRepeatMode == REPEAT_ALL || force) {
                         mPlayPos = 0;
@@ -1288,7 +1291,7 @@
     // A simple variation of Random that makes sure that the
     // value it returns is not equal to the value it returned
     // previously, unless the interval is 1.
-    private class Shuffler {
+    private static class Shuffler {
         private int mPrevious;
         private Random mRandom = new Random();
         public int nextInt(int interval) {
@@ -1663,14 +1666,18 @@
             mIsInitialized = false;
         }
 
+        /**
+         * You CANNOT use this player anymore after calling release()
+         */
+        public void release() {
+            stop();
+            mMediaPlayer.release();
+        }
+        
         public void pause() {
             mMediaPlayer.pause();
         }
         
-        public boolean isPlaying() {
-            return mMediaPlayer.isPlaying();
-        }
-
         public void setHandler(Handler handler) {
             mHandler = handler;
         }
@@ -1732,102 +1739,115 @@
         }
     }
 
-    private final IMediaPlaybackService.Stub mBinder = new IMediaPlaybackService.Stub()
-    {
-        public void openfileAsync(String path)
-        {
-            MediaPlaybackService.this.openAsync(path);
+    /*
+     * By making this a static class with a WeakReference to the Service, we
+     * ensure that the Service can be GCd even when the system process still
+     * has a remote reference to the stub.
+     */
+    static class ServiceStub extends IMediaPlaybackService.Stub {
+        WeakReference<MediaPlaybackService> mService;
+        
+        ServiceStub(MediaPlaybackService service) {
+            mService = new WeakReference<MediaPlaybackService>(service);
         }
-        public void openfile(String path)
+
+        public void openFileAsync(String path)
         {
-            MediaPlaybackService.this.open(path, true);
+            mService.get().openAsync(path);
+        }
+        public void openFile(String path, boolean oneShot)
+        {
+            mService.get().open(path, oneShot);
         }
         public void open(int [] list, int position) {
-            MediaPlaybackService.this.open(list, position);
+            mService.get().open(list, position);
         }
         public int getQueuePosition() {
-            return MediaPlaybackService.this.getQueuePosition();
+            return mService.get().getQueuePosition();
         }
         public void setQueuePosition(int index) {
-            MediaPlaybackService.this.setQueuePosition(index);
+            mService.get().setQueuePosition(index);
         }
         public boolean isPlaying() {
-            return MediaPlaybackService.this.isPlaying();
+            return mService.get().isPlaying();
         }
         public void stop() {
-            MediaPlaybackService.this.stop();
+            mService.get().stop();
         }
         public void pause() {
-            MediaPlaybackService.this.pause();
+            mService.get().pause();
         }
         public void play() {
-            MediaPlaybackService.this.play();
+            mService.get().play();
         }
         public void prev() {
-            MediaPlaybackService.this.prev();
+            mService.get().prev();
         }
         public void next() {
-            MediaPlaybackService.this.next(true);
+            mService.get().next(true);
         }
         public String getTrackName() {
-            return MediaPlaybackService.this.getTrackName();
+            return mService.get().getTrackName();
         }
         public String getAlbumName() {
-            return MediaPlaybackService.this.getAlbumName();
+            return mService.get().getAlbumName();
         }
         public int getAlbumId() {
-            return MediaPlaybackService.this.getAlbumId();
+            return mService.get().getAlbumId();
         }
         public String getArtistName() {
-            return MediaPlaybackService.this.getArtistName();
+            return mService.get().getArtistName();
         }
         public int getArtistId() {
-            return MediaPlaybackService.this.getArtistId();
+            return mService.get().getArtistId();
         }
         public void enqueue(int [] list , int action) {
-            MediaPlaybackService.this.enqueue(list, action);
+            mService.get().enqueue(list, action);
         }
         public int [] getQueue() {
-            return MediaPlaybackService.this.getQueue();
+            return mService.get().getQueue();
         }
         public void moveQueueItem(int from, int to) {
-            MediaPlaybackService.this.moveQueueItem(from, to);
+            mService.get().moveQueueItem(from, to);
         }
         public String getPath() {
-            return MediaPlaybackService.this.getPath();
+            return mService.get().getPath();
         }
         public int getAudioId() {
-            return MediaPlaybackService.this.getAudioId();
+            return mService.get().getAudioId();
         }
         public long position() {
-            return MediaPlaybackService.this.position();
+            return mService.get().position();
         }
         public long duration() {
-            return MediaPlaybackService.this.duration();
+            return mService.get().duration();
         }
         public long seek(long pos) {
-            return MediaPlaybackService.this.seek(pos);
+            return mService.get().seek(pos);
         }
         public void setShuffleMode(int shufflemode) {
-            MediaPlaybackService.this.setShuffleMode(shufflemode);
+            mService.get().setShuffleMode(shufflemode);
         }
         public int getShuffleMode() {
-            return MediaPlaybackService.this.getShuffleMode();
+            return mService.get().getShuffleMode();
         }
         public int removeTracks(int first, int last) {
-            return MediaPlaybackService.this.removeTracks(first, last);
+            return mService.get().removeTracks(first, last);
         }
         public int removeTrack(int id) {
-            return MediaPlaybackService.this.removeTrack(id);
+            return mService.get().removeTrack(id);
         }
         public void setRepeatMode(int repeatmode) {
-            MediaPlaybackService.this.setRepeatMode(repeatmode);
+            mService.get().setRepeatMode(repeatmode);
         }
         public int getRepeatMode() {
-            return MediaPlaybackService.this.getRepeatMode();
+            return mService.get().getRepeatMode();
         }
         public int getMediaMountedCount() {
-            return MediaPlaybackService.this.getMediaMountedCount();
+            return mService.get().getMediaMountedCount();
         }
-    };
+
+    }
+    
+    private final IBinder mBinder = new ServiceStub(this);
 }
diff --git a/src/com/android/music/MusicPicker.java b/src/com/android/music/MusicPicker.java
index c5be26d..9eed155 100644
--- a/src/com/android/music/MusicPicker.java
+++ b/src/com/android/music/MusicPicker.java
@@ -76,7 +76,7 @@
     static final String SORT_MODE_KEY = "sortMode";
     
     /** Arbitrary number, doesn't matter since we only do one query type. */
-    final int MY_QUERY_TOKEN = 42;
+    static final int MY_QUERY_TOKEN = 42;
     
     /** Menu item to sort the music list by track title. */
     static final int TRACK_MENU = Menu.FIRST;
@@ -169,12 +169,9 @@
         private int mArtistIdx;
         private int mAlbumIdx;
         private int mDurationIdx;
-        private int mAudioIdIdx;
-        private int mTrackIdx;
 
         private boolean mLoading = true;
         private int mIndexerSortMode;
-        private boolean mIndexerOutOfDate;
         private MusicAlphabetIndexer mIndexer;
         
         class ViewHolder {
@@ -306,18 +303,32 @@
                 mArtistIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
                 mAlbumIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
                 mDurationIdx = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
-                int audioIdIdx = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID);
-                if (audioIdIdx < 0) {
-                    audioIdIdx = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
+
+                // If the sort mode has changed, or we haven't yet created an
+                // indexer one, then create a new one that is indexing the
+                // appropriate column based on the sort mode.
+                if (mIndexerSortMode != mSortMode || mIndexer == null) {
+                    mIndexerSortMode = mSortMode;
+                    int idx = mTitleIdx;
+                    switch (mIndexerSortMode) {
+                        case ARTIST_MENU:
+                            idx = mArtistIdx;
+                            break;
+                        case ALBUM_MENU:
+                            idx = mAlbumIdx;
+                            break;
+                    }
+                    mIndexer = new MusicAlphabetIndexer(cursor, idx,
+                            getResources().getString(
+                                    com.android.internal.R.string.fast_scroll_alphabet));
+                    
+                // If we have a valid indexer, but the cursor has changed since
+                // its last use, then point it to the current cursor.
+                } else {
+                    mIndexer.setCursor(cursor);
                 }
-                mAudioIdIdx = audioIdIdx;
-                mTrackIdx = cursor.getColumnIndex(MediaStore.Audio.Media.TRACK);
             }
             
-            // The next time the indexer is needed, we will need to rebind it
-            // to this cursor.
-            mIndexerOutOfDate = true;
-            
             // Ensure that the list is shown (and initial progress indicator
             // hidden) in case this is the first cursor we have gotten.
             makeListShown();
@@ -342,32 +353,6 @@
                 return 0;
             }
             
-            // If the sort mode has changed, or we haven't yet created an
-            // indexer one, then create a new one that is indexing the
-            // appropriate column based on the sort mode.
-            if (mIndexerSortMode != mSortMode || mIndexer == null) {
-                mIndexerSortMode = mSortMode;
-                int idx = mTitleIdx;
-                switch (mIndexerSortMode) {
-                    case ARTIST_MENU:
-                        idx = mArtistIdx;
-                        break;
-                    case ALBUM_MENU:
-                        idx = mAlbumIdx;
-                        break;
-                }
-                mIndexer = new MusicAlphabetIndexer(cursor, idx,
-                        getResources().getString(
-                                com.android.internal.R.string.fast_scroll_alphabet));
-                
-            // If we have a valid indexer, but the cursor has changed since
-            // its last use, then point it to the current cursor.
-            } else if (mIndexerOutOfDate) {
-                mIndexer.setCursor(cursor);
-            }
-            
-            mIndexerOutOfDate = false;
-            
             return mIndexer.getPositionForSection(section);
         }
 
@@ -376,7 +361,10 @@
         }
 
         public Object[] getSections() {
-            return mIndexer.getSections();
+            if (mIndexer != null) {
+                return mIndexer.getSections();
+            }
+            return null;
         }
     }
 
diff --git a/src/com/android/music/MusicUtils.java b/src/com/android/music/MusicUtils.java
index 2f5aeca..49bb7fe 100644
--- a/src/com/android/music/MusicUtils.java
+++ b/src/com/android/music/MusicUtils.java
@@ -900,6 +900,16 @@
                 // maybe it never existed to begin with.
                 Bitmap bm = getArtworkFromFile(context, null, album_id);
                 if (bm != null) {
+                    if (bm.getConfig() == null) {
+                        bm = bm.copy(Bitmap.Config.RGB_565, false);
+                        if (bm == null) {
+                            if (allowDefault) {
+                                return getDefaultArtwork(context);
+                            } else {
+                                return null;
+                            }
+                        }
+                    }
                     // Put the newly found artwork in the database.
                     // Note that this shouldn't be done for the "unknown" album,
                     // but if this method is called correctly, that won't happen.
@@ -910,16 +920,6 @@
                     if (ensureFileExists(file)) {
                         try {
                             OutputStream outstream = new FileOutputStream(file);
-                            if (bm.getConfig() == null) {
-                                bm = bm.copy(Bitmap.Config.RGB_565, false);
-                                if (bm == null) {
-                                    if (allowDefault) {
-                                        return getDefaultArtwork(context);
-                                    } else {
-                                        return null;
-                                    }
-                                }
-                            }
                             boolean success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream);
                             outstream.close();
                             if (success) {
diff --git a/src/com/android/music/QueryBrowserActivity.java b/src/com/android/music/QueryBrowserActivity.java
index 9e91ba6..a67790a 100644
--- a/src/com/android/music/QueryBrowserActivity.java
+++ b/src/com/android/music/QueryBrowserActivity.java
@@ -20,10 +20,12 @@
 import android.app.SearchManager;
 import android.content.AsyncQueryHandler;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
 
 import android.database.Cursor;
 import android.database.DatabaseUtils;
@@ -32,7 +34,9 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Message;
+import android.provider.BaseColumns;
 import android.provider.MediaStore;
 import android.text.TextUtils;
 import android.util.Log;
@@ -49,7 +53,8 @@
 
 import java.util.ArrayList;
 
-public class QueryBrowserActivity extends ListActivity implements MusicUtils.Defs
+public class QueryBrowserActivity extends ListActivity
+implements MusicUtils.Defs, ServiceConnection
 {
     private final static int PLAY_NOW = 0;
     private final static int ADD_TO_QUEUE = 1;
@@ -73,52 +78,55 @@
     {
         super.onCreate(icicle);
         setVolumeControlStream(AudioManager.STREAM_MUSIC);
-        MusicUtils.bindToService(this);
+        mAdapter = (QueryListAdapter) getLastNonConfigurationInstance();
+        MusicUtils.bindToService(this, this);
+        // defer the real work until we're bound to the service
+    }
+
+
+    public void onServiceConnected(ComponentName name, IBinder service) {
         IntentFilter f = new IntentFilter();
         f.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
         f.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
         f.addDataScheme("file");
         registerReceiver(mScanListener, f);
         
-        if (icicle == null) {
-            Intent intent = getIntent();
-            
-            if (intent.getAction().equals(Intent.ACTION_VIEW)) {
-                // this is something we got from the search bar
-                Uri uri = intent.getData();
-                String path = uri.toString();
-                if (path.startsWith("content://media/external/audio/media/")) {
-                    // This is a specific file
-                    String id = uri.getLastPathSegment();
-                    int [] list = new int[] { Integer.valueOf(id) };
-                    MusicUtils.playAll(this, list, 0);
-                    finish();
-                    return;
-                } else if (path.startsWith("content://media/external/audio/albums/")) {
-                    // This is an album, show the songs on it
-                    Intent i = new Intent(Intent.ACTION_PICK);
-                    i.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
-                    i.putExtra("album", uri.getLastPathSegment());
-                    startActivity(i);
-                    finish();
-                    return;
-                } else if (path.startsWith("content://media/external/audio/artists/")) {
-                    // This is an artist, show the albums for that artist
-                    Intent i = new Intent(Intent.ACTION_PICK);
-                    i.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
-                    i.putExtra("artist", uri.getLastPathSegment());
-                    startActivity(i);
-                    finish();
-                    return;
-                }
+        Intent intent = getIntent();
+        
+        if (intent.getAction().equals(Intent.ACTION_VIEW)) {
+            // this is something we got from the search bar
+            Uri uri = intent.getData();
+            String path = uri.toString();
+            if (path.startsWith("content://media/external/audio/media/")) {
+                // This is a specific file
+                String id = uri.getLastPathSegment();
+                int [] list = new int[] { Integer.valueOf(id) };
+                MusicUtils.playAll(this, list, 0);
+                finish();
+                return;
+            } else if (path.startsWith("content://media/external/audio/albums/")) {
+                // This is an album, show the songs on it
+                Intent i = new Intent(Intent.ACTION_PICK);
+                i.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
+                i.putExtra("album", uri.getLastPathSegment());
+                startActivity(i);
+                finish();
+                return;
+            } else if (path.startsWith("content://media/external/audio/artists/")) {
+                // This is an artist, show the albums for that artist
+                Intent i = new Intent(Intent.ACTION_PICK);
+                i.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
+                i.putExtra("artist", uri.getLastPathSegment());
+                startActivity(i);
+                finish();
+                return;
             }
-            mFilterString = intent.getStringExtra(SearchManager.QUERY);
         }
+        mFilterString = intent.getStringExtra(SearchManager.QUERY);
 
         setContentView(R.layout.query_activity);
         mTrackList = getListView();
         mTrackList.setTextFilterEnabled(true);
-        mAdapter = (QueryListAdapter) getLastNonConfigurationInstance();
         if (mAdapter == null) {
             mAdapter = new QueryListAdapter(
                     getApplication(),
@@ -145,7 +153,11 @@
             }
         }
     }
-    
+
+    public void onServiceDisconnected(ComponentName name) {
+        
+    }
+
     @Override
     public Object onRetainNonConfigurationInstance() {
         mAdapterSent = true;
@@ -267,15 +279,17 @@
             filter = "";
         }
         String[] ccols = new String[] {
-                "_id",   // this will be the artist, album or track ID
+                BaseColumns._ID,   // this will be the artist, album or track ID
                 MediaStore.Audio.Media.MIME_TYPE, // mimetype of audio file, or "artist" or "album"
-                SearchManager.SUGGEST_COLUMN_TEXT_1,
+                MediaStore.Audio.Artists.ARTIST,
+                MediaStore.Audio.Albums.ALBUM,
+                MediaStore.Audio.Media.TITLE,
                 "data1",
                 "data2"
         };
 
-        Uri search = Uri.parse("content://media/external/audio/" + 
-                SearchManager.SUGGEST_URI_PATH_QUERY + "/" + Uri.encode(filter));
+        Uri search = Uri.parse("content://media/external/audio/search/fancy/" +
+                Uri.encode(filter));
         
         Cursor ret = null;
         if (async != null) {
@@ -342,7 +356,7 @@
             if (mimetype.equals("artist")) {
                 iv.setImageResource(R.drawable.ic_mp_artist_list);
                 String name = cursor.getString(cursor.getColumnIndexOrThrow(
-                        SearchManager.SUGGEST_COLUMN_TEXT_1));
+                        MediaStore.Audio.Artists.ARTIST));
                 String displayname = name;
                 boolean isunknown = false;
                 if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
@@ -362,14 +376,15 @@
             } else if (mimetype.equals("album")) {
                 iv.setImageResource(R.drawable.albumart_mp_unknown_list);
                 String name = cursor.getString(cursor.getColumnIndexOrThrow(
-                        SearchManager.SUGGEST_COLUMN_TEXT_1));
+                        MediaStore.Audio.Albums.ALBUM));
                 String displayname = name;
                 if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
                     displayname = context.getString(R.string.unknown_album_name);
                 }
                 tv1.setText(displayname);
                 
-                name = cursor.getString(cursor.getColumnIndexOrThrow("data1"));
+                name = cursor.getString(cursor.getColumnIndexOrThrow(
+                        MediaStore.Audio.Artists.ARTIST));
                 displayname = name;
                 if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
                     displayname = context.getString(R.string.unknown_artist_name);
@@ -381,16 +396,18 @@
                     mimetype.equals("application/x-ogg")) {
                 iv.setImageResource(R.drawable.ic_mp_song_list);
                 String name = cursor.getString(cursor.getColumnIndexOrThrow(
-                        SearchManager.SUGGEST_COLUMN_TEXT_1));
+                        MediaStore.Audio.Media.TITLE));
                 tv1.setText(name);
 
-                String displayname = cursor.getString(cursor.getColumnIndexOrThrow("data1"));
-                if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
+                String displayname = cursor.getString(cursor.getColumnIndexOrThrow(
+                        MediaStore.Audio.Artists.ARTIST));
+                if (displayname == null || displayname.equals(MediaFile.UNKNOWN_STRING)) {
                     displayname = context.getString(R.string.unknown_artist_name);
                 }
-                name = cursor.getString(cursor.getColumnIndexOrThrow("data2"));
+                name = cursor.getString(cursor.getColumnIndexOrThrow(
+                        MediaStore.Audio.Albums.ALBUM));
                 if (name == null || name.equals(MediaFile.UNKNOWN_STRING)) {
-                    name = context.getString(R.string.unknown_artist_name);
+                    name = context.getString(R.string.unknown_album_name);
                 }
                 tv2.setText(displayname + " - " + name);
             }
diff --git a/src/com/android/music/StreamStarter.java b/src/com/android/music/StreamStarter.java
index 0537bad..a43dbf5 100644
--- a/src/com/android/music/StreamStarter.java
+++ b/src/com/android/music/StreamStarter.java
@@ -30,6 +30,7 @@
 import android.os.RemoteException;
 import android.view.Window;
 import android.widget.TextView;
+import android.widget.Toast;
 
 public class StreamStarter extends Activity
 {
@@ -57,8 +58,9 @@
                 try {
                     IntentFilter f = new IntentFilter();
                     f.addAction(MediaPlaybackService.ASYNC_OPEN_COMPLETE);
+                    f.addAction(MediaPlaybackService.PLAYBACK_COMPLETE);
                     registerReceiver(mStatusListener, new IntentFilter(f));
-                    MusicUtils.sService.openfileAsync(getIntent().getData().toString());
+                    MusicUtils.sService.openFileAsync(getIntent().getData().toString());
                 } catch (RemoteException ex) {
                 }
             }
@@ -71,6 +73,16 @@
     private BroadcastReceiver mStatusListener = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(MediaPlaybackService.PLAYBACK_COMPLETE)) {
+                // You would come here only in case of a failure in the
+                // MediaPlayerService before PrepareAsync completes
+                String msg = getString(R.string.fail_to_start_stream);
+                Toast mt = Toast.makeText(StreamStarter.this, msg, Toast.LENGTH_SHORT);
+                mt.show();
+                finish();
+                return;
+            }
             try {
                 MusicUtils.sService.play();
                 intent = new Intent("com.android.music.PLAYBACK_VIEWER");
diff --git a/src/com/android/music/TrackBrowserActivity.java b/src/com/android/music/TrackBrowserActivity.java
index dd3da3e..1f1adf6 100644
--- a/src/com/android/music/TrackBrowserActivity.java
+++ b/src/com/android/music/TrackBrowserActivity.java
@@ -65,13 +65,13 @@
 public class TrackBrowserActivity extends ListActivity
         implements View.OnCreateContextMenuListener, MusicUtils.Defs, ServiceConnection
 {
-    private final int Q_SELECTED = CHILD_MENU_BASE;
-    private final int Q_ALL = CHILD_MENU_BASE + 1;
-    private final int SAVE_AS_PLAYLIST = CHILD_MENU_BASE + 2;
-    private final int PLAY_ALL = CHILD_MENU_BASE + 3;
-    private final int CLEAR_PLAYLIST = CHILD_MENU_BASE + 4;
-    private final int REMOVE = CHILD_MENU_BASE + 5;
-    private final int SEARCH = CHILD_MENU_BASE + 6;
+    private static final int Q_SELECTED = CHILD_MENU_BASE;
+    private static final int Q_ALL = CHILD_MENU_BASE + 1;
+    private static final int SAVE_AS_PLAYLIST = CHILD_MENU_BASE + 2;
+    private static final int PLAY_ALL = CHILD_MENU_BASE + 3;
+    private static final int CLEAR_PLAYLIST = CHILD_MENU_BASE + 4;
+    private static final int REMOVE = CHILD_MENU_BASE + 5;
+    private static final int SEARCH = CHILD_MENU_BASE + 6;
 
 
     private static final String LOGTAG = "TrackBrowser";
@@ -151,7 +151,6 @@
         mTrackList = getListView();
         mTrackList.setOnCreateContextMenuListener(this);
         if (mEditMode) {
-            //((TouchInterceptor) mTrackList).setDragListener(mDragListener);
             ((TouchInterceptor) mTrackList).setDropListener(mDropListener);
             ((TouchInterceptor) mTrackList).setRemoveListener(mRemoveListener);
             mTrackList.setCacheColorHint(0);
@@ -439,18 +438,6 @@
         }
     }
     
-    private TouchInterceptor.DragListener mDragListener =
-        new TouchInterceptor.DragListener() {
-        public void drag(int from, int to) {
-            if (mTrackCursor instanceof NowPlayingCursor) {
-                NowPlayingCursor c = (NowPlayingCursor) mTrackCursor;
-                c.moveItem(from, to);
-                ((TrackListAdapter)getListAdapter()).notifyDataSetChanged();
-                getListView().invalidateViews();
-                mDeletedOneRow = true;
-            }
-        }
-    };
     private TouchInterceptor.DropListener mDropListener =
         new TouchInterceptor.DropListener() {
         public void drop(int from, int to) {
@@ -668,6 +655,7 @@
         
         Intent i = new Intent();
         i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
+        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         
         title = mCurrentAlbumName;
         query = mCurrentArtistNameForAlbum + " " + mCurrentAlbumName;
@@ -927,7 +915,6 @@
             for (int i = 0; i < searchWords.length; i++) {
                 where.append(" AND ");
                 where.append(MediaStore.Audio.Media.ARTIST_KEY + "||");
-                where.append(MediaStore.Audio.Media.ALBUM_KEY + "||");
                 where.append(MediaStore.Audio.Media.TITLE_KEY + " LIKE ?");
             }
         }
@@ -1260,7 +1247,6 @@
 
         int mTitleIdx;
         int mArtistIdx;
-        int mAlbumIdx;
         int mDurationIdx;
         int mAudioIdIdx;
 
@@ -1275,7 +1261,7 @@
         private String mConstraint = null;
         private boolean mConstraintIsValid = false;
         
-        class ViewHolder {
+        static class ViewHolder {
             TextView line1;
             TextView line2;
             TextView duration;
@@ -1322,7 +1308,6 @@
             if (cursor != null) {
                 mTitleIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE);
                 mArtistIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST);
-                mAlbumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM);
                 mDurationIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION);
                 try {
                     mAudioIdIdx = cursor.getColumnIndexOrThrow(