summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaman Tenneti <rtenneti@google.com>2018-09-20 17:33:28 -0700
committerRaman Tenneti <rtenneti@google.com>2018-10-10 04:37:31 +0000
commit026dd07c005844475e6d74f7112831fb0aeb10c3 (patch)
tree560e57860e90caf7f621629b9c17bd2fa7d08525
parentb5ac8a91b4c72557f7637c8b136145ef0ee14f54 (diff)
downloadMusic-026dd07c005844475e6d74f7112831fb0aeb10c3.tar.gz
A simple music app that passes CTS tests.
Deleted most of the code from the previous app. There is Music icon for this app because CTS tests that tests MediaBrowserService and Playback callbacks. It pops up a dialog when an audio file is clicked on and when it is playing (same as before). The following test is the only test that tests Music app. cts/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java Test: manual - Ran the following CTS tests on Pixel phone. ./development/testrunner/runtest.py --path cts/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java ./development/testrunner/runtest.py --path cts/tests/tests/media/src/android/media/cts/MediaRouterTest.java ./development/testrunner/runtest.py --path cts/tests/tests/media/src/android/media/cts/AudioManagerTest.java ./development/testrunner/runtest.py --path cts/tests/tests/media/src/android/media/cts/MediaSessionTest.java ./development/testrunner/runtest.py --path cts/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java Bug: 112925066 Change-Id: I81080f138774c52ea636ddfca3eff26306f2f051
-rw-r--r--AndroidManifest.xml144
-rw-r--r--res/color/tab_indicator_text.xml21
-rw-r--r--res/drawable/appwidget_button_center.xml28
-rw-r--r--res/drawable/appwidget_button_left.xml28
-rw-r--r--res/drawable/appwidget_button_right.xml28
-rw-r--r--res/drawable/buttonbarbackground.xml30
-rw-r--r--res/drawable/ic_tab_albums.xml21
-rw-r--r--res/drawable/ic_tab_artists.xml21
-rw-r--r--res/drawable/ic_tab_playback.xml21
-rw-r--r--res/drawable/ic_tab_playlists.xml21
-rw-r--r--res/drawable/ic_tab_songs.xml21
-rw-r--r--res/drawable/list_selector.xml24
-rw-r--r--res/drawable/list_selector_background.xml39
-rw-r--r--res/drawable/list_selector_background_transition.xml20
-rw-r--r--res/drawable/playlist_tile.xml28
-rw-r--r--res/layout-keysexposed/create_playlist.xml60
-rw-r--r--res/layout-keyshidden/create_playlist.xml71
-rw-r--r--res/layout-land/audio_player.xml159
-rw-r--r--res/layout-land/buttonbar.xml111
-rw-r--r--res/layout-land/media_picker_activity.xml36
-rw-r--r--res/layout-land/media_picker_activity_expanding.xml38
-rw-r--r--res/layout-port-finger-854x480/audio_player.xml137
-rw-r--r--res/layout/album_appwidget.xml95
-rw-r--r--res/layout/audio_player.xml148
-rw-r--r--res/layout/audio_player_common.xml89
-rw-r--r--res/layout/buttonbar.xml94
-rw-r--r--res/layout/confirm_delete.xml51
-rw-r--r--res/layout/edit_track_list_item.xml39
-rw-r--r--res/layout/media_picker_activity.xml38
-rw-r--r--res/layout/media_picker_activity_expanding.xml40
-rw-r--r--res/layout/music_picker.xml89
-rw-r--r--res/layout/music_picker_item.xml79
-rw-r--r--res/layout/nowplaying.xml71
-rw-r--r--res/layout/query_activity.xml31
-rw-r--r--res/layout/scanning.xml38
-rw-r--r--res/layout/scanning_nosdcard.xml38
-rw-r--r--res/layout/sd_error.xml36
-rw-r--r--res/layout/statusbar.xml54
-rw-r--r--res/layout/track_list_item.xml27
-rw-r--r--res/layout/track_list_item_child.xml28
-rw-r--r--res/layout/track_list_item_common.xml75
-rw-r--r--res/layout/track_list_item_group.xml28
-rw-r--r--res/layout/weekpicker.xml68
-rw-r--r--res/values/strings.xml1
-rw-r--r--res/xml/appwidget_info.xml23
-rw-r--r--res/xml/automotive_app_desc.xml4
-rw-r--r--res/xml/searchable.xml27
-rw-r--r--src/com/android/music/AlbumBrowserActivity.java298
-rw-r--r--src/com/android/music/ArtistAlbumBrowserActivity.java406
-rw-r--r--src/com/android/music/MediaPlaybackActivity.java773
-rw-r--r--src/com/android/music/MediaPlaybackService.java798
-rw-r--r--src/com/android/music/MusicAlphabetIndexer.java43
-rw-r--r--src/com/android/music/MusicBrowserActivity.java53
-rw-r--r--src/com/android/music/MusicPicker.java688
-rw-r--r--src/com/android/music/MusicUtils.java320
-rw-r--r--src/com/android/music/PlaylistBrowserActivity.java257
-rw-r--r--src/com/android/music/RepeatingImageButton.java140
-rw-r--r--src/com/android/music/SharedPreferencesCompat.java54
-rw-r--r--src/com/android/music/TouchInterceptor.java467
-rw-r--r--src/com/android/music/TrackBrowserActivity.java317
-rw-r--r--src/com/android/music/VerticalTextSpinner.java461
-rw-r--r--src/com/android/music/utils/AlbumArtCache.java128
-rw-r--r--src/com/android/music/utils/BitmapHelper.java83
-rw-r--r--src/com/android/music/utils/CheckableRelativeLayout.java61
-rw-r--r--src/com/android/music/utils/LogHelper.java93
-rw-r--r--src/com/android/music/utils/MediaIDHelper.java120
-rw-r--r--src/com/android/music/utils/MediaNotificationManager.java353
-rw-r--r--src/com/android/music/utils/MusicProvider.java491
-rw-r--r--src/com/android/music/utils/Playback.java486
-rw-r--r--src/com/android/music/utils/QueueHelper.java165
-rw-r--r--src/com/android/music/utils/ResourceHelper.java53
-rw-r--r--src/com/android/music/utils/Song.java101
-rw-r--r--tests/Android.mk18
-rw-r--r--tests/AndroidManifest.xml37
-rw-r--r--tests/src/com/android/music/MusicPlayerFunctionalTestRunner.java57
-rw-r--r--tests/src/com/android/music/MusicPlayerLaunchPerformance.java53
-rw-r--r--tests/src/com/android/music/MusicPlayerNames.java65
-rw-r--r--tests/src/com/android/music/MusicPlayerStability.java90
-rw-r--r--tests/src/com/android/music/MusicPlayerStressTestRunner.java51
-rw-r--r--tests/src/com/android/music/functional/TestPlaylist.java170
-rw-r--r--tests/src/com/android/music/functional/TestSongs.java214
-rw-r--r--tests/src/com/android/music/stress/AlbumsPlaybackStress.java92
-rw-r--r--tests/src/com/android/music/stress/MusicPlaybackStress.java87
83 files changed, 29 insertions, 10532 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 6adb4b3..5afe6e2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -14,51 +14,20 @@
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.android.music"
- android:versionCode="2"
- android:versionName="2.0">
-
- <!-- Package Name -->
- <original-package android:name="com.android.music"/>
-
- <!-- SDK Versions -->
- <uses-sdk android:minSdkVersion="19"
- android:targetSdkVersion="24"/>
+ xmlns:tools="http://schemas.android.com/tools">
<!-- Permissions -->
- <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <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.READ_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
- <uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<!-- App Declaration -->
<application
- android:icon="@drawable/app_music"
- android:label="@string/musicbrowserlabel"
- android:taskAffinity="android.task.music"
- android:allowTaskReparenting="true"
- android:usesCleartextTraffic="true">
-
- <!-- Meta Data -->
- <meta-data android:name="com.google.android.gms.car.application"
- android:resource="@xml/automotive_app_desc"/>
-
- <!-- Main Activity -->
- <activity android:name="com.android.music.MusicBrowserActivity"
- android:theme="@android:style/Theme.NoTitleBar"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.APP_MUSIC"/>
- </intent-filter>
- </activity>
+ android:allowBackup="true"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:launchMode="singleTop">
<activity android:name="AudioPreview" android:theme="@android:style/Theme.Dialog"
android:taskAffinity=""
@@ -95,108 +64,9 @@
</intent-filter>
</activity>
- <activity android:name="com.android.music.MusicPicker"
- android:label="@string/music_picker_title" android:exported="true" >
- <!-- First way to invoke us: someone asks to get content of
- any of the audio types we support. -->
- <intent-filter>
- <action android:name="android.intent.action.GET_CONTENT" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.OPENABLE" />
- <data android:mimeType="audio/*"/>
- <data android:mimeType="application/ogg"/>
- <data android:mimeType="application/x-ogg"/>
- </intent-filter>
- <!-- Second way to invoke us: someone asks to pick an item from
- some media Uri. -->
- <intent-filter>
- <action android:name="android.intent.action.PICK" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.OPENABLE" />
- <data android:mimeType="vnd.android.cursor.dir/audio"/>
- </intent-filter>
- </activity>
-
- <!--
- This is the "current music playing" panel, which has special
- launch behavior. We clear its task affinity, so it will not
- be associated with the main media task and if launched
- from a notification will not bring the rest of the media app
- to the foreground. We make it singleTask so that when others
- launch it (such as media) we will launch in to our own task.
- We set clearTaskOnLaunch because the user
- can go to a playlist from this activity, so if they later return
- to it we want it back in its initial state. We exclude from
- recents since this is accessible through a notification when
- appropriate.
- -->
- <activity android:name="com.android.music.MediaPlaybackActivity"
- android:theme="@android:style/Theme.NoTitleBar"
- android:label="@string/mediaplaybacklabel"
- android:taskAffinity=""
- android:launchMode="singleTask"
- android:clearTaskOnLaunch="true"
- android:excludeFromRecents="true"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:scheme="content"/>
- <data android:host="media"/>
- <data android:mimeType="audio/*"/>
- <data android:mimeType="application/ogg"/>
- <data android:mimeType="application/x-ogg"/>
- <data android:mimeType="application/itunes"/>
- </intent-filter>
- <intent-filter>
- <action android:name="com.android.music.PLAYBACK_VIEWER"/>
- <category android:name="android.intent.category.DEFAULT"/>
- </intent-filter>
- </activity>
-
- <activity android:name="com.android.music.ArtistAlbumBrowserActivity"
- android:exported="false">
- <intent-filter>
- <action android:name="android.intent.action.PICK"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="vnd.android.cursor.dir/artistalbum"/>
- </intent-filter>
- </activity>
-
- <activity android:name="com.android.music.AlbumBrowserActivity" android:exported="false">
- <intent-filter>
- <action android:name="android.intent.action.PICK"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="vnd.android.cursor.dir/album"/>
- </intent-filter>
- </activity>
-
- <activity android:name="com.android.music.TrackBrowserActivity" android:exported="false">
- <intent-filter>
- <action android:name="android.intent.action.PICK"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="vnd.android.cursor.dir/track"/>
- </intent-filter>
- </activity>
-
- <activity android:name="com.android.music.PlaylistBrowserActivity"
- android:label="@string/musicbrowserlabel"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.PICK"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="vnd.android.cursor.dir/playlist"/>
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.VIEW"/>
- <category android:name="android.intent.category.DEFAULT"/>
- <data android:mimeType="vnd.android.cursor.dir/playlist"/>
- </intent-filter>
- </activity>
-
<service android:name="com.android.music.MediaPlaybackService"
android:exported="true"
- android:label="Android Open Source Music Player">
+ android:label="Android Open Source Music Playback Service">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
diff --git a/res/color/tab_indicator_text.xml b/res/color/tab_indicator_text.xml
deleted file mode 100644
index 62f522b..0000000
--- a/res/color/tab_indicator_text.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true" android:color="#ffffff"/>
- <item android:state_focused="true" android:color="#ffffff"/>
- <item android:color="#808080"/> <!-- not selected -->
-</selector>
diff --git a/res/drawable/appwidget_button_center.xml b/res/drawable/appwidget_button_center.xml
deleted file mode 100644
index 194b357..0000000
--- a/res/drawable/appwidget_button_center.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:drawable="@drawable/appwidget_inner_press_c" />
-
- <item android:state_focused="true" android:state_enabled="true"
- android:state_window_focused="true"
- android:drawable="@drawable/appwidget_inner_focus_c" />
-
- <item
- android:drawable="@android:color/transparent" />
-</selector>
diff --git a/res/drawable/appwidget_button_left.xml b/res/drawable/appwidget_button_left.xml
deleted file mode 100644
index cbbce86..0000000
--- a/res/drawable/appwidget_button_left.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:drawable="@drawable/appwidget_inner_press_l" />
-
- <item android:state_focused="true" android:state_enabled="true"
- android:state_window_focused="true"
- android:drawable="@drawable/appwidget_inner_focus_l" />
-
- <item
- android:drawable="@android:color/transparent" />
-</selector>
diff --git a/res/drawable/appwidget_button_right.xml b/res/drawable/appwidget_button_right.xml
deleted file mode 100644
index 9623f54..0000000
--- a/res/drawable/appwidget_button_right.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_pressed="true"
- android:drawable="@drawable/appwidget_inner_press_r" />
-
- <item android:state_focused="true" android:state_enabled="true"
- android:state_window_focused="true"
- android:drawable="@drawable/appwidget_inner_focus_r" />
-
- <item
- android:drawable="@android:color/transparent" />
-</selector>
diff --git a/res/drawable/buttonbarbackground.xml b/res/drawable/buttonbarbackground.xml
deleted file mode 100644
index 54f4181..0000000
--- a/res/drawable/buttonbarbackground.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_focused="true"
- android:drawable="@drawable/buttonbar_focused" />
- <item
- android:state_pressed="true"
- android:drawable="@drawable/buttonbar_pressed" />
- <item
- android:state_selected="true"
- android:drawable="@drawable/buttonbar_active" />
- <item
- android:state_selected="false"
- android:drawable="@drawable/buttonbar_inactive" />
-</selector>
diff --git a/res/drawable/ic_tab_albums.xml b/res/drawable/ic_tab_albums.xml
deleted file mode 100644
index 72957df..0000000
--- a/res/drawable/ic_tab_albums.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_albums_selected" />
- <item android:drawable="@drawable/ic_tab_albums_unselected" />
-</selector>
-
diff --git a/res/drawable/ic_tab_artists.xml b/res/drawable/ic_tab_artists.xml
deleted file mode 100644
index e79766a..0000000
--- a/res/drawable/ic_tab_artists.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_artists_selected" />
- <item android:drawable="@drawable/ic_tab_artists_unselected" />
-</selector>
-
diff --git a/res/drawable/ic_tab_playback.xml b/res/drawable/ic_tab_playback.xml
deleted file mode 100644
index bcb8312..0000000
--- a/res/drawable/ic_tab_playback.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_playback_selected" />
- <item android:drawable="@drawable/ic_tab_playback_unselected" />
-</selector>
-
diff --git a/res/drawable/ic_tab_playlists.xml b/res/drawable/ic_tab_playlists.xml
deleted file mode 100644
index 64e6353..0000000
--- a/res/drawable/ic_tab_playlists.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_playlists_selected" />
- <item android:drawable="@drawable/ic_tab_playlists_unselected" />
-</selector>
-
diff --git a/res/drawable/ic_tab_songs.xml b/res/drawable/ic_tab_songs.xml
deleted file mode 100644
index 7642017..0000000
--- a/res/drawable/ic_tab_songs.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true" android:state_pressed="false" android:drawable="@drawable/ic_tab_songs_selected" />
- <item android:drawable="@drawable/ic_tab_songs_unselected" />
-</selector>
-
diff --git a/res/drawable/list_selector.xml b/res/drawable/list_selector.xml
deleted file mode 100644
index d8afcb6..0000000
--- a/res/drawable/list_selector.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_selected="true"
- android:drawable="@android:color/transparent" />
- <item android:state_pressed="true" android:state_selected="false"
- android:drawable="@android:color/transparent" />
- <item android:state_selected="false"
- android:drawable="@color/expanding_child_background" />
-</selector>
diff --git a/res/drawable/list_selector_background.xml b/res/drawable/list_selector_background.xml
deleted file mode 100644
index 5f52682..0000000
--- a/res/drawable/list_selector_background.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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_window_focused="false"
- android:drawable="@drawable/playlist_tile_normal" />
-
- <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
- <item android:state_focused="true" android:state_enabled="false"
- android:state_pressed="true"
- android:drawable="@drawable/playlist_tile_normal" />
- <item android:state_focused="true" android:state_enabled="false"
- android:drawable="@drawable/playlist_tile_normal" />
-
- <item android:state_focused="true" android:state_pressed="true"
- android:drawable="@drawable/list_selector_background_transition" />
- <item android:state_focused="false" android:state_pressed="true"
- android:drawable="@drawable/list_selector_background_transition" />
-
- <item android:state_focused="true"
- android:drawable="@drawable/playlist_tile_selected" />
-
- <item android:state_focused="false"
- android:drawable="@drawable/playlist_tile_normal" />
-</selector>
diff --git a/res/drawable/list_selector_background_transition.xml b/res/drawable/list_selector_background_transition.xml
deleted file mode 100644
index d92b392..0000000
--- a/res/drawable/list_selector_background_transition.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/playlist_tile_pressed" />
- <item android:drawable="@drawable/playlist_tile_longpress" />
-</transition>
diff --git a/res/drawable/playlist_tile.xml b/res/drawable/playlist_tile.xml
deleted file mode 100644
index 5e85f36..0000000
--- a/res/drawable/playlist_tile.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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_window_focused="false"
- android:drawable="@drawable/playlist_tile_normal" />
-
- <item android:state_focused="true" android:drawable="@color/transparent" />
- <item android:state_selected="true" android:drawable="@color/transparent" />
- <item android:state_pressed="true" android:drawable="@color/transparent" />
-
- <item android:state_focused="false" android:state_pressed="false"
- android:drawable="@drawable/playlist_tile_normal" />
-</selector>
diff --git a/res/layout-keysexposed/create_playlist.xml b/res/layout-keysexposed/create_playlist.xml
deleted file mode 100644
index 132210a..0000000
--- a/res/layout-keysexposed/create_playlist.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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="match_parent"
- android:layout_height="wrap_content">
-
- <TextView android:id="@+id/prompt"
- android:layout_width="match_parent" android:layout_height="wrap_content"
- android:text="@string/create_playlist_create_text_prompt"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip">
- </TextView>
-
- <EditText android:id="@+id/playlist"
- android:layout_width="match_parent" android:layout_height="wrap_content"
- android:singleLine="true"
- android:inputType="textCapSentences"
- android:layout_marginBottom="8dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip">
- <requestFocus />
- </EditText>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="6dip"
- android:background="#ffffff" >
-
- <Button android:id="@+id/create"
- android:layout_width="120dip" android:layout_height="wrap_content"
- android:text="@string/create_playlist_create_text"
- android:layout_alignParentLeft="true" />
-
- <Button android:id="@+id/cancel"
- android:layout_width="120dip" android:layout_height="wrap_content"
- android:text="@string/cancel"
- android:layout_alignParentRight="true" />
-
- </RelativeLayout>
-
-</LinearLayout>
-
diff --git a/res/layout-keyshidden/create_playlist.xml b/res/layout-keyshidden/create_playlist.xml
deleted file mode 100644
index 04aefc9..0000000
--- a/res/layout-keyshidden/create_playlist.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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="match_parent"
- android:layout_height="wrap_content">
-
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dip"
- android:layout_marginTop="8dip"
- android:layout_marginLeft="8dip"
- android:layout_marginRight="8dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/ic_slide_keyboard"/>
-
- <TextView android:id="@+id/prompt"
- android:layout_width="match_parent" android:layout_height="wrap_content"
- android:text="@string/create_playlist_create_text_prompt"
- android:layout_marginLeft="8dip">
- </TextView>
- </LinearLayout>
-
- <EditText android:id="@+id/playlist"
- android:layout_width="match_parent" android:layout_height="wrap_content"
- android:singleLine="true"
- android:inputType="textCapSentences"
- android:visibility="gone"
- android:layout_marginBottom="8dip">
- <requestFocus />
- </EditText>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="6dip"
- android:background="#ffffff" >
-
- <Button android:id="@+id/create"
- android:layout_width="120dip" android:layout_height="wrap_content"
- android:text="@string/create_playlist_create_text"
- android:layout_alignParentLeft="true" />
-
- <Button android:id="@+id/cancel"
- android:layout_width="120dip" android:layout_height="wrap_content"
- android:text="@string/cancel"
- android:layout_alignParentRight="true" />
-
- </RelativeLayout>
-
-</LinearLayout>
-
diff --git a/res/layout-land/audio_player.xml b/res/layout-land/audio_player.xml
deleted file mode 100644
index 982c2cc..0000000
--- a/res/layout-land/audio_player.xml
+++ /dev/null
@@ -1,159 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
-
- <!-- This is the LinearLayout that contains the album art, function buttons and album/artist/track info -->
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/album"
- android:background="@drawable/album_border_large"
- android:layout_width="183dip"
- android:layout_height="183dip"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="15dip"
- android:layout_marginTop="12dip" />
-
- <!-- This is the LinearLayout that contains function buttons and album/artist/track info -->
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingTop="20dip" >
-
- <ImageButton android:id="@+id/curplaylist"
- android:src="@drawable/ic_mp_current_playlist_btn"
- android:layout_width="82dip"
- android:layout_height="45dip"
- android:layout_marginRight="8dip"
- android:nextFocusLeft="@id/curplaylist" />
-
- <ImageButton android:id="@+id/shuffle"
- android:layout_width="82dip"
- android:layout_height="45dip"
- android:layout_marginRight="8dip" />
-
- <ImageButton android:id="@+id/repeat"
- android:layout_width="82dip"
- android:layout_height="45dip" />
-
- </LinearLayout>
-
- <!-- This is the LinearLayout that contains album/artist/track info -->
- <LinearLayout android:id="@+id/trackinfo"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingTop="8dip"
- android:paddingBottom="2dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_artist_playback" />
-
- <TextView android:id="@+id/artistname"
- android:textSize="18sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:textStyle="bold"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingTop="8dip"
- android:paddingBottom="2dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_album_playback" />
-
- <TextView android:id="@+id/albumname"
- android:textSize="14sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:textStyle="bold"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingTop="4dip"
- android:paddingBottom="2dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_song_playback" />
-
- <TextView android:id="@+id/trackname"
- android:textSize="14sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:textStyle="bold"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- </LinearLayout>
-
- </LinearLayout>
-
- </LinearLayout>
-
- <include layout="@layout/audio_player_common" />
-
-</LinearLayout>
diff --git a/res/layout-land/buttonbar.xml b/res/layout-land/buttonbar.xml
deleted file mode 100644
index f27907d..0000000
--- a/res/layout-land/buttonbar.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2008, 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.
-*/
--->
-
-<TabWidget xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/buttonbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/artisttab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_artists"
- android:text="@string/browse_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/albumtab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_albums"
- android:text="@string/albums_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/songtab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_songs"
- android:text="@string/tracks_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/playlisttab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_playlists"
- android:text="@string/playlists_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/nowplayingtab"
- android:focusable="false"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_playback"
- android:text="@string/nowplaying_title"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
-</TabWidget>
-
diff --git a/res/layout-land/media_picker_activity.xml b/res/layout-land/media_picker_activity.xml
deleted file mode 100644
index 77a9919..0000000
--- a/res/layout-land/media_picker_activity.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_vertical" >
-
- <include layout="@layout/sd_error" />
-
- <include layout="@layout/buttonbar" />
-
- <com.android.music.TouchInterceptor
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:textSize="18sp"
- android:drawSelectorOnTop="false"
- android:fastScrollEnabled="true" />
-
-</LinearLayout>
diff --git a/res/layout-land/media_picker_activity_expanding.xml b/res/layout-land/media_picker_activity_expanding.xml
deleted file mode 100644
index 9386eb8..0000000
--- a/res/layout-land/media_picker_activity_expanding.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_vertical" >
-
- <include layout="@layout/sd_error" />
-
- <include layout="@layout/buttonbar" />
-
- <ExpandableListView
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:textSize="18sp"
- android:drawSelectorOnTop="false"
- android:fastScrollEnabled="true"
- android:indicatorLeft="8dip"
- android:indicatorRight="52dip" />
-
-</LinearLayout>
diff --git a/res/layout-port-finger-854x480/audio_player.xml b/res/layout-port-finger-854x480/audio_player.xml
deleted file mode 100644
index 95f857c..0000000
--- a/res/layout-port-finger-854x480/audio_player.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-<?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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <ImageView
- android:id="@+id/album"
- android:background="@drawable/album_border_large"
- android:layout_width="270dip"
- android:layout_height="270dip"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="0dip" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:orientation="horizontal"
- android:layout_gravity="center_horizontal">
-
- <ImageButton android:id="@+id/curplaylist"
- android:src="@drawable/ic_mp_current_playlist_btn"
- android:layout_width="85dip"
- android:layout_height="54dip" />
-
- <ImageButton android:id="@+id/shuffle"
- android:layout_width="85dip"
- android:layout_height="54dip"
- android:layout_marginLeft="19dip" />
-
- <ImageButton android:id="@+id/repeat"
- android:layout_width="85dip"
- android:layout_height="54dip"
- android:layout_marginLeft="19dip" />
-
- </LinearLayout>
-
- <LinearLayout android:id="@+id/trackinfo"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingLeft="11dip"
- android:paddingTop="2dip"
- android:paddingBottom="4dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_artist_playback" />
-
- <TextView android:id="@+id/artistname"
- android:textSize="18sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:textStyle="bold"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingLeft="11dip"
- android:paddingTop="4dip"
- android:paddingBottom="8dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_album_playback" />
-
- <TextView android:id="@+id/albumname"
- android:textSize="14sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingLeft="11dip"
- android:paddingTop="0dip"
- android:paddingBottom="8dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_song_playback" />
-
- <TextView android:id="@+id/trackname"
- android:textSize="14sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
- </LinearLayout>
-
- <include layout="@layout/audio_player_common" />
-
-</LinearLayout>
diff --git a/res/layout/album_appwidget.xml b/res/layout/album_appwidget.xml
deleted file mode 100644
index b5d0908..0000000
--- a/res/layout/album_appwidget.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-<?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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:background="@drawable/appwidget_bg">
-
- <LinearLayout
- android:id="@+id/album_appwidget"
- android:layout_width="0dip"
- android:layout_weight="3"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_vertical"
- android:clickable="true"
- android:focusable="true"
- android:background="@drawable/appwidget_button_left"
- android:paddingLeft="18dip"
- android:paddingRight="8dip"
- >
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/appwidget_text"
- android:textStyle="bold"
- android:textSize="18sp"
- android:singleLine="true"
- android:fadingEdge="horizontal"
- android:fadingEdgeLength="10dip"
- android:ellipsize="none"
- />
-
- <TextView
- android:id="@+id/artist"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/appwidget_text"
- android:textSize="14sp"
- android:singleLine="true"
- android:fadingEdge="horizontal"
- android:fadingEdgeLength="10dip"
- android:ellipsize="none"
- />
- </LinearLayout>
-
- <ImageView
- android:layout_width="1dip"
- android:layout_height="match_parent"
- android:background="@drawable/appwidget_divider"
- />
-
- <ImageButton
- android:id="@+id/control_play"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:src="@drawable/ic_appwidget_music_play"
- android:background="@drawable/appwidget_button_center"
- android:scaleType="center"
- />
-
- <ImageView
- android:layout_width="1dip"
- android:layout_height="match_parent"
- android:background="@drawable/appwidget_divider"
- />
-
- <ImageButton
- android:id="@+id/control_next"
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="match_parent"
- android:src="@drawable/ic_appwidget_music_next"
- android:background="@drawable/appwidget_button_right"
- android:scaleType="center"
- />
-
-</LinearLayout>
diff --git a/res/layout/audio_player.xml b/res/layout/audio_player.xml
deleted file mode 100644
index a8a1921..0000000
--- a/res/layout/audio_player.xml
+++ /dev/null
@@ -1,148 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:orientation="horizontal"
- android:gravity="center">
-
- <ImageView
- android:id="@+id/album"
- android:background="@drawable/album_border_large"
- android:layout_width="220dip"
- android:layout_height="220dip"
- android:layout_marginLeft="4dip"
- android:layout_marginRight="2dip"
- android:layout_marginTop="8dip" />
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center_horizontal">
-
- <ImageButton android:id="@+id/curplaylist"
- android:src="@drawable/ic_mp_current_playlist_btn"
- android:layout_width="85dip"
- android:layout_height="54dip"
- android:layout_marginTop="14dip" />
-
- <ImageButton android:id="@+id/shuffle"
- android:layout_width="85dip"
- android:layout_height="54dip"
- android:layout_marginTop="20dip" />
-
- <ImageButton android:id="@+id/repeat"
- android:layout_width="85dip"
- android:layout_height="54dip"
- android:layout_marginTop="20dip" />
-
- </LinearLayout>
-
- </LinearLayout>
-
- <LinearLayout android:id="@+id/trackinfo"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingLeft="11dip"
- android:paddingTop="4dip"
- android:paddingBottom="8dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_artist_playback" />
-
- <TextView android:id="@+id/artistname"
- android:textSize="18sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:textStyle="bold"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingLeft="11dip"
- android:paddingTop="4dip"
- android:paddingBottom="8dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_album_playback" />
-
- <TextView android:id="@+id/albumname"
- android:textSize="14sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:baselineAligned="false"
- android:paddingLeft="11dip"
- android:paddingTop="0dip"
- android:paddingBottom="8dip">
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="4dip"
- android:src="@drawable/ic_mp_song_playback" />
-
- <TextView android:id="@+id/trackname"
- android:textSize="14sp"
- android:singleLine="true"
- android:ellipsize="end"
- android:layout_gravity="center_vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
- </LinearLayout>
-
- <include layout="@layout/audio_player_common" />
-
-</LinearLayout>
diff --git a/res/layout/audio_player_common.xml b/res/layout/audio_player_common.xml
deleted file mode 100644
index 4a7ceca..0000000
--- a/res/layout/audio_player_common.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1px"
- android:background="#ffffffff" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#ff5a5a5a"
- android:paddingTop="1dip"
- android:paddingBottom="4dip"
- android:orientation="horizontal">
-
- <TextView android:id="@+id/currenttime"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textSize="14sp"
- android:textStyle="bold"
- android:shadowColor="#ff000000"
- android:shadowDx="0"
- android:shadowDy="0"
- android:shadowRadius="3"
- android:layout_gravity="bottom"
- android:layout_weight="1"
- android:layout_width="0dip"
- android:paddingLeft="5dip"
- android:layout_height="wrap_content" />
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:layout_gravity="bottom"
- android:layout_marginTop="1dip"
- android:layout_marginBottom="2dip"
- android:gravity="center">
-
- <com.android.music.RepeatingImageButton android:id="@+id/prev" style="@android:style/MediaButton.Previous" />
-
- <ImageButton android:id="@+id/pause" style="@android:style/MediaButton.Play" />
-
- <com.android.music.RepeatingImageButton android:id="@+id/next" style="@android:style/MediaButton.Next" />
-
- </LinearLayout>
-
- <TextView android:id="@+id/totaltime"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textSize="14sp"
- android:textStyle="bold"
- android:shadowColor="#ff000000"
- android:shadowDx="0"
- android:shadowDy="0"
- android:shadowRadius="3"
- android:gravity="right"
- android:paddingRight="5dip"
- android:layout_gravity="bottom"
- android:layout_weight="1"
- android:layout_width="0dip"
- android:layout_height="wrap_content" />
-
- </LinearLayout>
-
- <SeekBar android:id="@android:id/progress"
- android:background="#ff5a5a5a"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="match_parent"
- android:layout_height="36dip"
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
- android:paddingBottom="4dip" />
-
-</merge>
diff --git a/res/layout/buttonbar.xml b/res/layout/buttonbar.xml
deleted file mode 100644
index 8c4e05a..0000000
--- a/res/layout/buttonbar.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2008, 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.
-*/
--->
-
-<TabWidget xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/buttonbar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content" >
-
- <TextView
- android:id="@+id/artisttab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_artists"
- android:text="@string/browse_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/albumtab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_albums"
- android:text="@string/albums_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/songtab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_songs"
- android:text="@string/tracks_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
- <TextView
- android:id="@+id/playlisttab"
- android:focusable="true"
- android:background="@drawable/buttonbarbackground"
- android:drawableTop="@drawable/ic_tab_playlists"
- android:text="@string/playlists_menu"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="@color/tab_indicator_text"
- android:paddingTop="7dip"
- android:paddingBottom="2dip"
- android:gravity="center"
- android:layout_weight="1"
- android:layout_marginLeft="-3dip"
- android:layout_marginRight="-3dip"
- android:layout_width="match_parent"
- android:layout_height="64dip" />
-
-</TabWidget>
-
diff --git a/res/layout/confirm_delete.xml b/res/layout/confirm_delete.xml
deleted file mode 100644
index 508fbdb..0000000
--- a/res/layout/confirm_delete.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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="match_parent"
- android:layout_height="wrap_content">
-
- <TextView android:id="@+id/prompt"
- android:layout_width="match_parent" android:layout_height="wrap_content"
- android:layout_marginLeft="8dip"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
- android:drawableLeft="@android:drawable/ic_dialog_alert"
- android:drawablePadding="8dip">
- </TextView>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="6dip"
- android:background="#ffffff" >
-
- <Button android:id="@+id/delete"
- android:layout_width="120dip" android:layout_height="wrap_content"
- android:text="@string/delete_confirm_button_text"
- android:layout_gravity="center_horizontal"
- android:layout_alignParentLeft="true" />
-
- <Button android:id="@+id/cancel"
- android:layout_width="120dip" android:layout_height="wrap_content"
- android:text="@string/cancel"
- android:layout_alignParentRight="true" />
-
- </RelativeLayout>
-
-</LinearLayout>
-
diff --git a/res/layout/edit_track_list_item.xml b/res/layout/edit_track_list_item.xml
deleted file mode 100644
index e8307bb..0000000
--- a/res/layout/edit_track_list_item.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2008, 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:layout_width="match_parent"
- android:layout_height="66dip"
- android:gravity="bottom"
- android:orientation="vertical"
- android:baselineAligned="false">
-
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="66dip"
- android:gravity="center_vertical"
- android:ignoreGravity="@+id/icon"
- android:background="@drawable/playlist_tile"
- android:paddingLeft="47dip"
- >
-
- <include layout="@layout/track_list_item_common" />
-
- </RelativeLayout>
-
-</LinearLayout>
diff --git a/res/layout/media_picker_activity.xml b/res/layout/media_picker_activity.xml
deleted file mode 100644
index af3d992..0000000
--- a/res/layout/media_picker_activity.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_vertical" >
-
- <include layout="@layout/sd_error" />
-
- <include layout="@layout/buttonbar" />
-
- <com.android.music.TouchInterceptor
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:textSize="18sp"
- android:drawSelectorOnTop="false"
- android:fastScrollEnabled="true" />
-
- <include layout="@layout/nowplaying" />
-
-</LinearLayout>
diff --git a/res/layout/media_picker_activity_expanding.xml b/res/layout/media_picker_activity_expanding.xml
deleted file mode 100644
index 4811f64..0000000
--- a/res/layout/media_picker_activity_expanding.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_vertical" >
-
- <include layout="@layout/sd_error" />
-
- <include layout="@layout/buttonbar" />
-
- <ExpandableListView
- android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:textSize="18sp"
- android:drawSelectorOnTop="false"
- android:fastScrollEnabled="true"
- android:indicatorLeft="8dip"
- android:indicatorRight="52dip" />
-
- <include layout="@layout/nowplaying" />
-
-</LinearLayout>
diff --git a/res/layout/music_picker.xml b/res/layout/music_picker.xml
deleted file mode 100644
index 0f97fcf..0000000
--- a/res/layout/music_picker.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (C) 2008 Google Inc.
- *
- * 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="match_parent"
- android:layout_height="match_parent">
-
- <FrameLayout
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1">
-
- <LinearLayout android:id="@+id/progressContainer"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center">
-
- <ProgressBar android:id="@+android:id/progress"
- style="?android:attr/progressBarStyleLarge"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <TextView android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:text="@string/loading"
- android:paddingTop="4dip"
- android:singleLine="true" />
-
- </LinearLayout>
-
- <FrameLayout android:id="@+id/listContainer"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <ListView android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:drawSelectorOnTop="false"
- android:fastScrollEnabled="true" />
- <TextView android:id="@android:id/empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/no_tracks_title"
- android:textAppearance="?android:attr/textAppearanceLarge" />
- </FrameLayout>
-
- </FrameLayout>
-
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="?android:attr/listPreferredItemHeight"
- android:layout_marginTop="1dip"
- android:background="@android:drawable/bottom_bar">
- <Button android:id="@+id/okayButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentLeft="true"
- android:text="@android:string/ok"
- android:minWidth="120dip"
- android:minHeight="48dip" />
- <Button android:id="@+id/cancelButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:text="@android:string/cancel"
- android:minWidth="120dip"
- android:minHeight="48dip" />
- </RelativeLayout>
-
-</LinearLayout>
diff --git a/res/layout/music_picker_item.xml b/res/layout/music_picker_item.xml
deleted file mode 100644
index cf0f637..0000000
--- a/res/layout/music_picker_item.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, Google Inc.
-**
-** 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.
-*/
--->
-<com.android.music.utils.CheckableRelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="64dip"
- android:gravity="center_vertical"
- android:ignoreGravity="@+id/radio">
-
- <RadioButton
- android:id="@+id/radio"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- android:layout_marginLeft="4dip"
- android:focusable="false"
- android:clickable="false" />
-
- <TextView android:id="@+id/duration"
- android:layout_alignParentRight="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/line1"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textColor="#ffe0d090"
- android:paddingLeft="4dip"
- android:paddingRight="5dip"
- android:singleLine="true" />
-
- <TextView android:id="@+id/line1"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="wrap_content"
- android:paddingLeft="4dip"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_alignWithParentIfMissing="true"
- android:layout_toRightOf="@id/radio"
- android:layout_toLeftOf="@id/duration"
- android:ellipsize="end"
- android:singleLine="true" />
-
- <TextView android:id="@+id/line2" android:visibility="visible"
- android:maxLines="2"
- android:ellipsize="end"
- android:paddingLeft="4dip"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:layout_below="@id/line1"
- android:layout_alignWithParentIfMissing="true"
- android:layout_toRightOf="@id/radio"
- android:layout_toLeftOf="@id/duration"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <ImageView android:id="@+id/play_indicator"
- android:layout_alignParentRight="true"
- android:layout_alignBottom="@id/line2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="6dip" />
-
-</com.android.music.utils.CheckableRelativeLayout>
diff --git a/res/layout/nowplaying.xml b/res/layout/nowplaying.xml
deleted file mode 100644
index 15ee78b..0000000
--- a/res/layout/nowplaying.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2008, 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:id="@+id/nowplaying"
- android:layout_width="match_parent"
- android:layout_height="64dip"
- android:focusable="true"
- android:visibility="gone"
- android:background="@drawable/music_bottom_playback_bg"
- android:orientation="vertical"
- android:paddingTop="3dip"
- android:paddingBottom="2dip">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/title"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:singleLine="true"
- android:ellipsize="end"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- <TextView
- android:id="@+id/artist"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:singleLine="true"
- android:ellipsize="end"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- />
- </LinearLayout>
-
- <ImageView android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginLeft="16dip"
- android:background="@drawable/indicator_ic_mp_playing_large"
- />
-
- </LinearLayout>
-</LinearLayout>
-
diff --git a/res/layout/query_activity.xml b/res/layout/query_activity.xml
deleted file mode 100644
index 7575364..0000000
--- a/res/layout/query_activity.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:gravity="center_vertical" >
-
- <include layout="@layout/sd_error" />
-
- <ListView android:id="@android:id/list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:drawSelectorOnTop="false">
- </ListView>
-</LinearLayout>
-
diff --git a/res/layout/scanning.xml b/res/layout/scanning.xml
deleted file mode 100644
index c4aa9ad..0000000
--- a/res/layout/scanning.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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="wrap_content"
- android:layout_height="wrap_content"
- android:padding="12dip">
-
- <ProgressBar android:id="@+id/spinner"
- style="?android:attr/progressBarStyleLarge"
- android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView android:id="@+id/message"
- android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/scanning">
- </TextView>
-
-</LinearLayout>
-
diff --git a/res/layout/scanning_nosdcard.xml b/res/layout/scanning_nosdcard.xml
deleted file mode 100644
index bb09fb8..0000000
--- a/res/layout/scanning_nosdcard.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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="wrap_content"
- android:layout_height="wrap_content"
- android:padding="12dip">
-
- <ProgressBar android:id="@+id/spinner"
- style="?android:attr/progressBarStyleLarge"
- android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView android:id="@+id/message"
- android:layout_gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:text="@string/scanning_nosdcard">
- </TextView>
-
-</LinearLayout>
-
diff --git a/res/layout/sd_error.xml b/res/layout/sd_error.xml
deleted file mode 100644
index 8a40305..0000000
--- a/res/layout/sd_error.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <ImageView
- android:id="@+id/sd_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:background="@drawable/ic_mp_sd_card"
- android:visibility="gone" />
-
- <TextView
- android:id="@+id/sd_message"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:padding="8dip"
- android:text="@string/sdcard_missing_message"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:visibility="gone" />
-
-</merge>
diff --git a/res/layout/statusbar.xml b/res/layout/statusbar.xml
deleted file mode 100644
index c8d3fb6..0000000
--- a/res/layout/statusbar.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal">
-
- <ImageView android:id="@+id/icon"
- android:padding="4dip"
- android:gravity="center"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- </ImageView>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView android:id="@+id/trackname"
- style="@android:style/TextAppearance.StatusBar.EventContent.Title"
- android:focusable="true"
- android:ellipsize="marquee"
- android:singleLine="true"
- android:layout_gravity="left"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <TextView android:id="@+id/artistalbum"
- style="@android:style/TextAppearance.StatusBar.EventContent"
- android:layout_gravity="left"
- android:maxLines="2"
- android:scrollHorizontally="true"
- android:ellipsize="end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- </LinearLayout>
-</LinearLayout>
diff --git a/res/layout/track_list_item.xml b/res/layout/track_list_item.xml
deleted file mode 100644
index 9b1d703..0000000
--- a/res/layout/track_list_item.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="64dip"
- android:gravity="center_vertical"
- android:ignoreGravity="@+id/icon">
-
- <include layout="@layout/track_list_item_common" />
-
-</RelativeLayout>
diff --git a/res/layout/track_list_item_child.xml b/res/layout/track_list_item_child.xml
deleted file mode 100644
index 9398182..0000000
--- a/res/layout/track_list_item_child.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="64dip"
- android:background="@drawable/list_selector"
- android:gravity="center_vertical"
- android:ignoreGravity="@+id/icon">
-
- <include layout="@layout/track_list_item_common" />
-
-</RelativeLayout>
diff --git a/res/layout/track_list_item_common.xml b/res/layout/track_list_item_common.xml
deleted file mode 100644
index e91bc29..0000000
--- a/res/layout/track_list_item_common.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2007, 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.
-*/
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
- <!-- icon is used for albumart, the grabber in edit playlist mode, and the playlist icon in the list of playlists -->
- <ImageView android:id="@+id/icon"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_alignParentBottom="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <TextView android:id="@+id/duration"
- android:textSize="12sp"
- android:textColor="?android:attr/textColorTertiary"
- android:textStyle="bold"
- android:paddingLeft="4dip"
- android:paddingRight="11dip"
- android:layout_alignParentRight="true"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignBaseline="@+id/line1"
- android:singleLine="true" />
-
- <!-- The height is set to half the height of the parent, which is 64 dip -->
- <TextView android:id="@+id/line1"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_width="wrap_content"
- android:paddingLeft="9dip"
- android:layout_height="wrap_content"
- android:layout_alignWithParentIfMissing="true"
- android:layout_toRightOf="@id/icon"
- android:layout_toLeftOf="@id/duration"
- android:ellipsize="marquee"
- android:singleLine="true" />
-
- <!-- The height is set to half the height of the parent, which is 64 dip -->
- <TextView android:id="@+id/line2" android:visibility="visible"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:singleLine="true"
- android:ellipsize="end"
- android:paddingLeft="9dip"
- android:scrollHorizontally="true"
- android:layout_below="@id/line1"
- android:layout_alignWithParentIfMissing="true"
- android:layout_toRightOf="@id/icon"
- android:layout_toLeftOf="@id/duration"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <ImageView android:id="@+id/play_indicator"
- android:layout_alignParentRight="true"
- android:layout_below="@id/duration"
- android:layout_marginTop="10dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginRight="12dip" />
-
-</merge>
diff --git a/res/layout/track_list_item_group.xml b/res/layout/track_list_item_group.xml
deleted file mode 100644
index 79a2de1..0000000
--- a/res/layout/track_list_item_group.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2008, 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.
-*/
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="64dip"
- android:gravity="center_vertical"
- android:ignoreGravity="@+id/icon"
- android:paddingLeft="47dip">
-
- <include layout="@layout/track_list_item_common" />
-
-</RelativeLayout>
diff --git a/res/layout/weekpicker.xml b/res/layout/weekpicker.xml
deleted file mode 100644
index 01869ef..0000000
--- a/res/layout/weekpicker.xml
+++ /dev/null
@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2008, 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.
-*/
--->
-
-<!-- Layout of time picker-->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:text="@string/weekpicker_title"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:layout_gravity="center_horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
-
- <!-- weeks -->
- <com.android.music.VerticalTextSpinner
- android:id="@+id/weeks"
- android:layout_width="120dip"
- android:layout_height="120dip"
- android:focusable="true"
- android:focusableInTouchMode="true"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="6dip"
- android:layout_marginBottom="6dip"
- />
-
- <!-- Set button -->
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="6dip"
- android:background="#ffffff" >
-
- <Button android:id="@+id/set"
- android:layout_width="120dip"
- android:layout_height="wrap_content"
- android:text="@string/weekpicker_set"
- android:layout_alignParentLeft="true" />
-
- <Button android:id="@+id/cancel"
- android:layout_width="120dip"
- android:layout_height="wrap_content"
- android:text="@string/cancel"
- android:layout_alignParentRight="true" />
-
- </RelativeLayout>
-
-</LinearLayout>
-
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c7f9082..ca0174d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -328,6 +328,7 @@
<string name="play_pause">play or pause</string>
<string name="skip_next">Skip to next</string>
<string name="no_search_results">No search results.</string>
+ <string name="message_seekbar">Setting Seekbar max to %d sec</string>
</resources>
diff --git a/res/xml/appwidget_info.xml b/res/xml/appwidget_info.xml
deleted file mode 100644
index 30b762c..0000000
--- a/res/xml/appwidget_info.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?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.
--->
-
-<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
- android:minWidth="294dip"
- android:minHeight="72dip"
- android:updatePeriodMillis="0"
- android:initialLayout="@layout/album_appwidget"
- >
-</appwidget-provider>
diff --git a/res/xml/automotive_app_desc.xml b/res/xml/automotive_app_desc.xml
deleted file mode 100644
index 0a6a3c9..0000000
--- a/res/xml/automotive_app_desc.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<automotiveApp>
- <uses name="media"/>
-</automotiveApp> \ No newline at end of file
diff --git a/res/xml/searchable.xml b/res/xml/searchable.xml
deleted file mode 100644
index 2cfd796..0000000
--- a/res/xml/searchable.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?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.
--->
-
-<searchable xmlns:android="http://schemas.android.com/apk/res/android"
- android:label="@string/search_title"
- android:hint="@string/search_hint"
- android:includeInGlobalSearch="true"
-
- android:searchSuggestAuthority="media"
- android:searchSuggestPath="external/audio/search"
- android:searchSuggestThreshold="3"
- android:searchSuggestIntentAction="android.intent.action.VIEW"
- android:searchSettingsDescription="@string/search_settings_description"
-/>
diff --git a/src/com/android/music/AlbumBrowserActivity.java b/src/com/android/music/AlbumBrowserActivity.java
deleted file mode 100644
index ce5dcab..0000000
--- a/src/com/android/music/AlbumBrowserActivity.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.ListActivity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.*;
-import com.android.music.utils.LogHelper;
-import com.android.music.utils.MediaIDHelper;
-import com.android.music.utils.Playback;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/*
-This activity is the albums browsing tab
- */
-public class AlbumBrowserActivity extends ListActivity {
- private static final String TAG = LogHelper.makeLogTag(AlbumBrowserActivity.class);
- private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM =
- new MediaBrowser.MediaItem(new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM)
- .build(),
- MediaBrowser.MediaItem.FLAG_BROWSABLE);
-
- private ListView mAlbumList;
- private AlbumBrowseAdapter mBrowseListAdapter;
- private MediaBrowser mMediaBrowser;
- private MediaBrowser.MediaItem mParentItem;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- Log.d(TAG, "onCreate()");
- super.onCreate(icicle);
- if (icicle != null) {
- mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
- } else if (getIntent() != null) {
- mParentItem = getIntent().getExtras().getParcelable(MusicUtils.TAG_PARENT_ITEM);
- }
- if (mParentItem == null) {
- mParentItem = DEFAULT_PARENT_ITEM;
- }
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- setContentView(R.layout.media_picker_activity);
- MusicUtils.updateButtonBar(this, R.id.albumtab);
- mAlbumList = getListView();
- mAlbumList.setOnCreateContextMenuListener(this);
- mAlbumList.setTextFilterEnabled(true);
-
- mBrowseListAdapter = (AlbumBrowseAdapter) getLastNonConfigurationInstance();
- if (mBrowseListAdapter == null) {
- // Log.i("@@@", "starting query");
- mBrowseListAdapter = new AlbumBrowseAdapter(this, R.layout.track_list_item);
- setTitle(R.string.working_albums);
- }
- setListAdapter(mBrowseListAdapter);
- Log.d(TAG, "Creating MediaBrowser");
- mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
- mConnectionCallback, null);
- }
-
- @Override
- public void onDestroy() {
- Log.d(TAG, "onDestroy()");
- ListView lv = getListView();
- // Because we pass the adapter to the next activity, we need to make
- // sure it doesn't keep a reference to this activity. We can do this
- // by clearing its DatasetObservers, which setListAdapter(null) does.
- setListAdapter(null);
- mBrowseListAdapter = null;
- super.onDestroy();
- }
-
- @Override
- public void onResume() {
- Log.d(TAG, "onResume()");
- super.onResume();
- }
-
- @Override
- public void onStart() {
- Log.d(TAG, "onStart()");
- super.onStart();
- mMediaBrowser.connect();
- }
-
- @Override
- public void onStop() {
- Log.d(TAG, "onStop()");
- super.onStop();
- mMediaBrowser.disconnect();
- }
-
- @Override
- public void onPause() {
- Log.d(TAG, "onPause()");
- super.onPause();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outcicle) {
- outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
- super.onSaveInstanceState(outcicle);
- }
-
- private void setTitle() {
- CharSequence fancyName = "";
- setTitle(R.string.albums_title);
- }
-
- private MediaBrowser.SubscriptionCallback mSubscriptionCallback =
- new MediaBrowser.SubscriptionCallback() {
-
- @Override
- public void onChildrenLoaded(
- String parentId, List<MediaBrowser.MediaItem> children) {
- mBrowseListAdapter.clear();
- mBrowseListAdapter.notifyDataSetInvalidated();
- for (MediaBrowser.MediaItem item : children) {
- mBrowseListAdapter.add(item);
- }
- mBrowseListAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onError(String id) {
- Toast.makeText(getApplicationContext(), R.string.error_loading_media,
- Toast.LENGTH_LONG)
- .show();
- }
- };
-
- private MediaBrowser.ConnectionCallback mConnectionCallback =
- new MediaBrowser.ConnectionCallback() {
- @Override
- public void onConnected() {
- Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
- mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
- if (mMediaBrowser.getSessionToken() == null) {
- throw new IllegalArgumentException("No Session token");
- }
- MediaController mediaController = new MediaController(
- AlbumBrowserActivity.this, mMediaBrowser.getSessionToken());
- mediaController.registerCallback(mMediaControllerCallback);
- AlbumBrowserActivity.this.setMediaController(mediaController);
- if (mediaController.getMetadata() != null) {
- MusicUtils.updateNowPlaying(AlbumBrowserActivity.this);
- }
- }
-
- @Override
- public void onConnectionFailed() {
- Log.d(TAG, "onConnectionFailed");
- }
-
- @Override
- public void onConnectionSuspended() {
- Log.d(TAG, "onConnectionSuspended");
- AlbumBrowserActivity.this.setMediaController(null);
- }
- };
-
- private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- super.onMetadataChanged(metadata);
- MusicUtils.updateNowPlaying(AlbumBrowserActivity.this);
- if (mBrowseListAdapter != null) {
- mBrowseListAdapter.notifyDataSetChanged();
- }
- }
- };
-
- // An adapter for showing the list of browsed MediaItem's
- private class AlbumBrowseAdapter extends ArrayAdapter<MediaBrowser.MediaItem> {
- private final Drawable mNowPlayingOverlay;
- private final BitmapDrawable mDefaultAlbumIcon;
- private int mLayoutId;
-
- private class ViewHolder {
- TextView line1;
- TextView line2;
- ImageView play_indicator;
- ImageView icon;
- }
-
- AlbumBrowseAdapter(Context context, int layout) {
- super(context, layout, new ArrayList<>());
- mNowPlayingOverlay = context.getResources().getDrawable(
- R.drawable.indicator_ic_mp_playing_list, context.getTheme());
- Bitmap b = BitmapFactory.decodeResource(
- context.getResources(), R.drawable.albumart_mp_unknown_list);
- mDefaultAlbumIcon = new BitmapDrawable(context.getResources(), b);
- // no filter or dither, it's a lot faster and we can't tell the difference
- mDefaultAlbumIcon.setFilterBitmap(false);
- mDefaultAlbumIcon.setDither(false);
- mLayoutId = layout;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Log.d(TAG, "getView()");
- if (convertView == null) {
- convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false);
- ViewHolder vh = new ViewHolder();
- vh.line1 = (TextView) convertView.findViewById(R.id.line1);
- vh.line2 = (TextView) convertView.findViewById(R.id.line2);
- vh.play_indicator = (ImageView) convertView.findViewById(R.id.play_indicator);
- vh.icon = (ImageView) convertView.findViewById(R.id.icon);
- vh.icon.setBackground(mDefaultAlbumIcon);
- vh.icon.setPadding(0, 0, 1, 0);
- vh.icon.setVisibility(View.VISIBLE);
- convertView.setTag(vh);
- }
- ViewHolder vh = (ViewHolder) convertView.getTag();
- MediaBrowser.MediaItem item = getItem(position);
- Log.d(TAG, "Album: " + item.getDescription().getTitle());
- vh.line1.setText(item.getDescription().getTitle());
- Log.d(TAG, "Artist: " + item.getDescription().getSubtitle());
- vh.line2.setText(item.getDescription().getSubtitle());
- Bitmap albumArt = item.getDescription().getIconBitmap();
- LogHelper.d(TAG, "looking for album art");
- if (albumArt != null) {
- vh.icon.setImageDrawable(MusicUtils.getDrawableBitmap(albumArt, mDefaultAlbumIcon));
- } else {
- vh.icon.setImageDrawable(mDefaultAlbumIcon);
- }
- MediaController mediaController = AlbumBrowserActivity.this.getMediaController();
- if (mediaController == null) {
- vh.play_indicator.setImageDrawable(null);
- return convertView;
- }
- MediaMetadata metadata = mediaController.getMetadata();
- if (metadata == null) {
- vh.play_indicator.setImageDrawable(null);
- return convertView;
- }
- if (metadata.getString(MediaMetadata.METADATA_KEY_ALBUM)
- .equals(item.getDescription().getTitle())) {
- vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
- } else {
- vh.play_indicator.setImageDrawable(null);
- }
- return convertView;
- }
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- Log.d(TAG, "onListItemClick at position " + position + ", id " + id);
- MediaBrowser.MediaItem item = mBrowseListAdapter.getItem(position);
- if (item.isBrowsable()) {
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
- intent.putExtra(MusicUtils.TAG_PARENT_ITEM, item);
- intent.putExtra(MusicUtils.TAG_WITH_TABS, false);
- startActivity(intent);
- }
- }
-}
diff --git a/src/com/android/music/ArtistAlbumBrowserActivity.java b/src/com/android/music/ArtistAlbumBrowserActivity.java
deleted file mode 100644
index ffccd32..0000000
--- a/src/com/android/music/ArtistAlbumBrowserActivity.java
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.ExpandableListActivity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.ExpandableListView;
-import android.widget.ImageView;
-import android.widget.SimpleExpandableListAdapter;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.music.utils.LogHelper;
-import com.android.music.utils.MediaIDHelper;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-public class ArtistAlbumBrowserActivity extends ExpandableListActivity {
- private static final String TAG = LogHelper.makeLogTag(ArtistAlbumBrowserActivity.class);
- private static final String KEY_NUM_ALBUMS = "__NUM_ALBUMS__";
- private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM =
- new MediaBrowser.MediaItem(new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)
- .build(),
- MediaBrowser.MediaItem.FLAG_BROWSABLE);
-
- private ArtistAlbumListAdapter mAdapter;
- private MediaBrowser mMediaBrowser;
- private MediaBrowser.MediaItem mParentItem;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- LogHelper.d(TAG, "onCreate()");
- // Handle past states
- if (icicle != null) {
- mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
- } else if (getIntent() != null) {
- mParentItem = getIntent().getExtras().getParcelable(MusicUtils.TAG_PARENT_ITEM);
- }
- if (mParentItem == null) {
- mParentItem = DEFAULT_PARENT_ITEM;
- }
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- // Init layout
- setContentView(R.layout.media_picker_activity_expanding);
- MusicUtils.updateButtonBar(this, R.id.artisttab);
-
- // Init expandable list
- ExpandableListView lv = getExpandableListView();
- lv.setTextFilterEnabled(true);
- mAdapter = (ArtistAlbumListAdapter) getLastNonConfigurationInstance();
- if (mAdapter == null) {
- // Log.i("@@@", "starting query");
- mAdapter = new ArtistAlbumListAdapter(this, new ArrayList<>(), new ArrayList<>());
- setListAdapter(mAdapter);
- setTitle(R.string.working_artists);
- } else {
- mAdapter.setActivity(this);
- }
- setListAdapter(mAdapter);
- LogHelper.d(TAG, "Creating MediaBrowser");
- mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
- mConnectionCallback, null);
- }
-
- @Override
- public Object onRetainNonConfigurationInstance() {
- return mAdapter;
- }
-
- @Override
- public void onSaveInstanceState(Bundle outcicle) {
- outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
- super.onSaveInstanceState(outcicle);
- }
-
- @Override
- public void onDestroy() {
- setListAdapter(null);
- mAdapter = null;
- setListAdapter(null);
- super.onDestroy();
- }
-
- @Override
- public void onStart() {
- LogHelper.d(TAG, "onStart()");
- super.onStart();
- mMediaBrowser.connect();
- }
-
- @Override
- public void onStop() {
- LogHelper.d(TAG, "onStop()");
- super.onStop();
- mMediaBrowser.disconnect();
- }
-
- private MediaBrowser
- .SubscriptionCallback mSubscriptionCallback = new MediaBrowser.SubscriptionCallback() {
- @Override
- public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
- if (parentId.equals(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)) {
- mAdapter.getArtistMap().clear();
- mAdapter.getGroupData().clear();
- mAdapter.notifyDataSetInvalidated();
- for (MediaBrowser.MediaItem item : children) {
- ConcurrentHashMap<String, MediaBrowser.MediaItem> entry =
- new ConcurrentHashMap<>();
- entry.put(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST, item);
- synchronized (this) {
- mAdapter.getArtistMap().put(item.getDescription().getTitle().toString(),
- mAdapter.getGroupData().size());
- mAdapter.getGroupData().add(entry);
- mAdapter.getChildData().add(new ArrayList<>());
- }
- mMediaBrowser.subscribe(item.getMediaId(), this);
- }
- mAdapter.notifyDataSetChanged();
- } else if (parentId.startsWith(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST)) {
- String artist = MediaIDHelper.getHierarchy(parentId)[1];
- if (!mAdapter.getArtistMap().containsKey(artist)) {
- return;
- }
- int artistIndex = mAdapter.getArtistMap().get(artist);
- mAdapter.getChildData().get(artistIndex).clear();
- mAdapter.notifyDataSetInvalidated();
- Bundle extras = new Bundle();
- extras.putLong(KEY_NUM_ALBUMS, children.size());
- MediaBrowser.MediaItem newArtistItem =
- new MediaBrowser.MediaItem(new MediaDescription.Builder()
- .setMediaId("Count")
- .setExtras(extras)
- .build(),
- 0);
- mAdapter.getGroupData().get(artistIndex).put(KEY_NUM_ALBUMS, newArtistItem);
- for (MediaBrowser.MediaItem item : children) {
- ConcurrentHashMap<String, MediaBrowser.MediaItem> entry =
- new ConcurrentHashMap<>();
- entry.put(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM, item);
- mAdapter.getChildData().get(artistIndex).add(entry);
- }
- mAdapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onError(String id) {
- Toast.makeText(getApplicationContext(), R.string.error_loading_media, Toast.LENGTH_LONG)
- .show();
- }
- };
-
- private MediaBrowser.ConnectionCallback mConnectionCallback =
- new MediaBrowser.ConnectionCallback() {
- @Override
- public void onConnected() {
- LogHelper.d(
- TAG, "onConnected: session token ", mMediaBrowser.getSessionToken());
- mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
- if (mMediaBrowser.getSessionToken() == null) {
- throw new IllegalArgumentException("No Session token");
- }
- MediaController mediaController = new MediaController(
- ArtistAlbumBrowserActivity.this, mMediaBrowser.getSessionToken());
- mediaController.registerCallback(mMediaControllerCallback);
- ArtistAlbumBrowserActivity.this.setMediaController(mediaController);
- if (mediaController.getMetadata() != null) {
- MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
- }
- }
-
- @Override
- public void onConnectionFailed() {
- LogHelper.d(TAG, "onConnectionFailed");
- }
-
- @Override
- public void onConnectionSuspended() {
- LogHelper.d(TAG, "onConnectionSuspended");
- ArtistAlbumBrowserActivity.this.setMediaController(null);
- }
- };
-
- private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- super.onMetadataChanged(metadata);
- MusicUtils.updateNowPlaying(ArtistAlbumBrowserActivity.this);
- }
- };
-
- private class ArtistAlbumListAdapter extends SimpleExpandableListAdapter {
- private final Drawable mNowPlayingOverlay;
- private final BitmapDrawable mDefaultAlbumIcon;
- private ArtistAlbumBrowserActivity mActivity;
- private ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> mGroupData;
- private ArrayList < ArrayList
- < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> mChildData;
- private ConcurrentHashMap<String, Integer> mArtistMap;
-
- private class ViewHolder {
- TextView line1;
- TextView line2;
- ImageView play_indicator;
- ImageView icon;
- }
-
- ArtistAlbumListAdapter(ArtistAlbumBrowserActivity currentActivity,
- ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> groupData,
- ArrayList < ArrayList
- < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> childData) {
- super(currentActivity, groupData, R.layout.track_list_item_group, new String[] {},
- new int[] {}, childData, R.layout.track_list_item_child, new String[] {},
- new int[] {});
- mGroupData = groupData;
- mChildData = childData;
- mActivity = currentActivity;
- mNowPlayingOverlay = currentActivity.getResources().getDrawable(
- R.drawable.indicator_ic_mp_playing_list, currentActivity.getTheme());
- mDefaultAlbumIcon = (BitmapDrawable) currentActivity.getResources().getDrawable(
- R.drawable.albumart_mp_unknown_list, currentActivity.getTheme());
- // no filter or dither, it's a lot faster and we can't tell the difference
- mDefaultAlbumIcon.setFilterBitmap(false);
- mDefaultAlbumIcon.setDither(false);
- mArtistMap = new ConcurrentHashMap<>();
- }
-
- public ArrayList<ConcurrentHashMap<String, MediaBrowser.MediaItem>> getGroupData() {
- return mGroupData;
- }
-
- public ArrayList < ArrayList
- < ConcurrentHashMap<String, MediaBrowser.MediaItem>>> getChildData() {
- return mChildData;
- }
-
- public Map<String, Integer> getArtistMap() {
- return mArtistMap;
- }
-
- public void setActivity(ArtistAlbumBrowserActivity newactivity) {
- mActivity = newactivity;
- }
-
- @Override
- public View newGroupView(boolean isExpanded, ViewGroup parent) {
- View v = super.newGroupView(isExpanded, parent);
- ImageView iv = (ImageView) v.findViewById(R.id.icon);
- ViewGroup.LayoutParams p = iv.getLayoutParams();
- p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
- p.height = ViewGroup.LayoutParams.WRAP_CONTENT;
- ViewHolder vh = new ViewHolder();
- vh.line1 = (TextView) v.findViewById(R.id.line1);
- vh.line2 = (TextView) v.findViewById(R.id.line2);
- vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
- vh.icon = (ImageView) v.findViewById(R.id.icon);
- vh.icon.setPadding(0, 0, 1, 0);
- v.setTag(vh);
- return v;
- }
-
- @Override
- public View newChildView(boolean isLastChild, ViewGroup parent) {
- View v = super.newChildView(isLastChild, parent);
- ViewHolder vh = new ViewHolder();
- vh.line1 = (TextView) v.findViewById(R.id.line1);
- vh.line2 = (TextView) v.findViewById(R.id.line2);
- vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
- vh.icon = (ImageView) v.findViewById(R.id.icon);
- vh.icon.setBackground(mDefaultAlbumIcon);
- vh.icon.setPadding(0, 0, 1, 0);
- v.setTag(vh);
- return v;
- }
-
- @Override
- public View getGroupView(
- int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = newGroupView(isExpanded, parent);
- }
- Map<String, MediaBrowser.MediaItem> artistEntry =
- (Map<String, MediaBrowser.MediaItem>) getGroup(groupPosition);
- MediaBrowser.MediaItem artistItem =
- artistEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST);
- MediaBrowser.MediaItem countItem = artistEntry.get(KEY_NUM_ALBUMS);
- ViewHolder vh = (ViewHolder) convertView.getTag();
- vh.line1.setText(artistItem.getDescription().getTitle());
- int numalbums = -1;
- if (countItem != null) {
- Bundle extras = countItem.getDescription().getExtras();
- if (extras != null) {
- numalbums = (int) extras.getLong(KEY_NUM_ALBUMS);
- }
- }
- String songs_albums = MusicUtils.makeAlbumsLabel(mActivity, numalbums, -1, false);
- vh.line2.setText(songs_albums);
- MediaController mediaController = mActivity.getMediaController();
- if (mediaController == null) {
- vh.play_indicator.setImageDrawable(null);
- return convertView;
- }
- MediaMetadata metadata = mediaController.getMetadata();
- if (metadata == null) {
- vh.play_indicator.setImageDrawable(null);
- return convertView;
- }
- if (metadata.getString(MediaMetadata.METADATA_KEY_ARTIST)
- .equals(artistItem.getDescription().getTitle())
- && !isExpanded) {
- vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
- } else {
- vh.play_indicator.setImageDrawable(null);
- }
- return convertView;
- }
-
- @Override
- public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
- View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = newChildView(isLastChild, parent);
- }
- Map<String, MediaBrowser.MediaItem> albumEntry =
- (Map<String, MediaBrowser.MediaItem>) getChild(groupPosition, childPosition);
- MediaBrowser.MediaItem albumItem =
- albumEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM);
- ViewHolder vh = (ViewHolder) convertView.getTag();
- vh.line1.setText(albumItem.getDescription().getTitle());
- vh.line2.setText(albumItem.getDescription().getDescription());
- Bitmap albumArt = albumItem.getDescription().getIconBitmap();
- if (albumArt == null) {
- vh.icon.setBackground(mDefaultAlbumIcon);
- } else {
- vh.icon.setImageDrawable(MusicUtils.getDrawableBitmap(albumArt, mDefaultAlbumIcon));
- }
- MediaController mediaController = mActivity.getMediaController();
- if (mediaController == null) {
- vh.play_indicator.setImageDrawable(null);
- return convertView;
- }
- MediaMetadata metadata = mediaController.getMetadata();
- if (metadata == null) {
- vh.play_indicator.setImageDrawable(null);
- return convertView;
- }
- if (albumItem.getDescription().getTitle().equals(
- metadata.getString(MediaMetadata.METADATA_KEY_ALBUM))) {
- vh.play_indicator.setImageDrawable(mNowPlayingOverlay);
- } else {
- vh.play_indicator.setImageDrawable(null);
- }
- return convertView;
- }
- }
-
- @Override
- public boolean onChildClick(
- ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
- Map<String, MediaBrowser.MediaItem> albumEntry =
- (Map<String, MediaBrowser.MediaItem>) mAdapter.getChild(
- groupPosition, childPosition);
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
- intent.putExtra(
- MusicUtils.TAG_PARENT_ITEM, albumEntry.get(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM));
- startActivity(intent);
- return true;
- }
-}
diff --git a/src/com/android/music/MediaPlaybackActivity.java b/src/com/android/music/MediaPlaybackActivity.java
deleted file mode 100644
index 71a3a7d..0000000
--- a/src/com/android/music/MediaPlaybackActivity.java
+++ /dev/null
@@ -1,773 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.Activity;
-import android.app.SearchManager;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.media.AudioManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
-import android.provider.MediaStore;
-import android.text.Layout;
-import android.text.TextUtils.TruncateAt;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.Window;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import com.android.music.utils.LogHelper;
-import com.android.music.utils.MediaIDHelper;
-import com.android.music.utils.MusicProvider;
-
-/*
-This is the Now Playing Activity
- */
-public class MediaPlaybackActivity
- extends Activity implements View.OnTouchListener, View.OnLongClickListener {
- private static final String TAG = LogHelper.makeLogTag(MediaPlaybackActivity.class);
-
- private long mStartSeekPos = 0;
- private long mLastSeekEventTime;
- private RepeatingImageButton mPrevButton;
- private ImageButton mPlayPauseButton;
- private RepeatingImageButton mNextButton;
- private ImageButton mRepeatButton;
- private ImageButton mShuffleButton;
- private ImageButton mQueueButton;
- private int mTouchSlop;
-
- private ImageView mAlbumArt;
- private TextView mCurrentTime;
- private TextView mTotalTime;
- private TextView mArtistName;
- private TextView mAlbumName;
- private TextView mTrackName;
- private LinearLayout mTrackInfo;
- private ProgressBar mProgress;
- private BitmapDrawable mDefaultAlbumArt;
- private Toast mToast;
-
- private MediaBrowser mMediaBrowser;
- private final Handler mHandler = new Handler();
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- LogHelper.d(TAG, "onCreate()");
- super.onCreate(icicle);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.audio_player);
-
- mCurrentTime = (TextView) findViewById(R.id.currenttime);
- mTotalTime = (TextView) findViewById(R.id.totaltime);
- mProgress = (ProgressBar) findViewById(android.R.id.progress);
- mAlbumArt = (ImageView) findViewById(R.id.album);
- mArtistName = (TextView) findViewById(R.id.artistname);
- mAlbumName = (TextView) findViewById(R.id.albumname);
- mTrackName = (TextView) findViewById(R.id.trackname);
- mTrackInfo = (LinearLayout) findViewById(R.id.trackinfo);
-
- Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.albumart_mp_unknown);
- mDefaultAlbumArt = new BitmapDrawable(getResources(), b);
- // no filter or dither, it's a lot faster and we can't tell the difference
- mDefaultAlbumArt.setFilterBitmap(false);
- mDefaultAlbumArt.setDither(false);
-
- /* Set metadata listeners */
- View v = (View) mArtistName.getParent();
- v.setOnTouchListener(this);
- v.setOnLongClickListener(this);
- v = (View) mAlbumName.getParent();
- v.setOnTouchListener(this);
- v.setOnLongClickListener(this);
- v = (View) mTrackName.getParent();
- v.setOnTouchListener(this);
- v.setOnLongClickListener(this);
-
- /* Set button listeners */
- mPrevButton = (RepeatingImageButton) findViewById(R.id.prev);
- mPrevButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- if (getMediaController() == null) return;
- if (getMediaController().getPlaybackState().getPosition() < 2000) {
- getMediaController().getTransportControls().skipToPrevious();
- } else {
- getMediaController().getTransportControls().seekTo(0);
- getMediaController().getTransportControls().play();
- }
- }
- });
- mPrevButton.setRepeatListener(new RepeatingImageButton.RepeatListener() {
- public void onRepeat(View v, long howlong, int repcnt) {
- scanBackward(repcnt, howlong);
- }
- }, 260);
- mPlayPauseButton = (ImageButton) findViewById(R.id.pause);
- mPlayPauseButton.requestFocus();
- mPlayPauseButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- if (getMediaController() != null) {
- if (getMediaController().getPlaybackState().getState()
- != PlaybackState.STATE_PLAYING) {
- getMediaController().getTransportControls().play();
- } else {
- getMediaController().getTransportControls().pause();
- }
- }
- }
- });
- mNextButton = (RepeatingImageButton) findViewById(R.id.next);
- mNextButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- if (getMediaController() == null) return;
- getMediaController().getTransportControls().skipToNext();
- }
- });
- mNextButton.setRepeatListener(new RepeatingImageButton.RepeatListener() {
- public void onRepeat(View v, long howlong, int repcnt) {
- scanForward(repcnt, howlong);
- }
- }, 260);
- mQueueButton = (ImageButton) findViewById(R.id.curplaylist);
- mQueueButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- LogHelper.d(TAG, "mQueueButton onClick");
- MediaBrowser.MediaItem parentItem = new MediaBrowser.MediaItem(
- new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.createBrowseCategoryMediaID(
- MediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST,
- MediaIDHelper.MEDIA_ID_NOW_PLAYING))
- .setTitle("Now Playing")
- .build(),
- MediaBrowser.MediaItem.FLAG_BROWSABLE);
- Intent intent = new Intent(Intent.ACTION_PICK)
- .setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track")
- .putExtra(MusicUtils.TAG_WITH_TABS, false)
- .putExtra(MusicUtils.TAG_PARENT_ITEM, parentItem);
- startActivity(intent);
- }
- });
- mShuffleButton = ((ImageButton) findViewById(R.id.shuffle));
- mShuffleButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- LogHelper.d(TAG, "Shuffle button clicked");
- if (getMediaController() == null) return;
- Bundle extras = getMediaController().getExtras();
- if (extras == null) return;
- MediaPlaybackService.ShuffleMode shuffleMode =
- MediaPlaybackService.ShuffleMode
- .values()[extras.getInt(MediaPlaybackService.SHUFFLE_MODE)];
- MediaPlaybackService.ShuffleMode nextShuffleMode;
- switch (shuffleMode) {
- case SHUFFLE_NONE:
- nextShuffleMode = MediaPlaybackService.ShuffleMode.SHUFFLE_RANDOM;
- showToast(R.string.shuffle_on_notif);
- break;
- case SHUFFLE_RANDOM:
- default:
- nextShuffleMode = MediaPlaybackService.ShuffleMode.SHUFFLE_NONE;
- showToast(R.string.shuffle_off_notif);
- break;
- }
- setShuffleMode(nextShuffleMode);
- // TODO(siyuanh): Should use a callback to register changes on service side
- setShuffleButtonImage(nextShuffleMode);
- }
- });
- mRepeatButton = ((ImageButton) findViewById(R.id.repeat));
- mRepeatButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- LogHelper.d(TAG, "Repeat button clicked");
- if (getMediaController() == null) return;
- Bundle extras = getMediaController().getExtras();
- if (extras == null) return;
- MediaPlaybackService.RepeatMode repeatMode =
- MediaPlaybackService.RepeatMode
- .values()[extras.getInt(MediaPlaybackService.REPEAT_MODE)];
- MediaPlaybackService.RepeatMode nextRepeatMode;
- switch (repeatMode) {
- case REPEAT_NONE:
- nextRepeatMode = MediaPlaybackService.RepeatMode.REPEAT_ALL;
- showToast(R.string.repeat_all_notif);
- break;
- case REPEAT_ALL:
- nextRepeatMode = MediaPlaybackService.RepeatMode.REPEAT_CURRENT;
- showToast(R.string.repeat_current_notif);
- break;
- case REPEAT_CURRENT:
- default:
- nextRepeatMode = MediaPlaybackService.RepeatMode.REPEAT_NONE;
- showToast(R.string.repeat_off_notif);
- break;
- }
- setRepeatMode(nextRepeatMode);
- // TODO(siyuanh): Should use a callback to register changes on service side
- setRepeatButtonImage(nextRepeatMode);
- }
- });
-
- if (mProgress instanceof SeekBar) {
- SeekBar seeker = (SeekBar) mProgress;
- seeker.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
- boolean mmFromTouch = false;
- public void onStartTrackingTouch(SeekBar bar) {
- mLastSeekEventTime = 0;
- mmFromTouch = true;
- }
- public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
- if (!fromuser || (getMediaController() == null)) return;
- long now = SystemClock.elapsedRealtime();
- if ((now - mLastSeekEventTime) > 250) {
- mLastSeekEventTime = now;
- long duration = getMediaController().getMetadata().getLong(
- MediaMetadata.METADATA_KEY_DURATION);
- long position = duration * progress / 1000;
- getMediaController().getTransportControls().seekTo(position);
- // trackball event, allow progress updates
- if (!mmFromTouch) {
- updateProgressBar();
- }
- }
- }
- public void onStopTrackingTouch(SeekBar bar) {
- mmFromTouch = false;
- }
- });
- } else {
- LogHelper.d(TAG, "Seeking not supported");
- }
- mProgress.setMax(1000);
-
- mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
-
- Log.d(TAG, "Creating MediaBrowser");
- mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
- mConnectionCallback, null);
- }
-
- // Receive callbacks from the MediaController. Here we update our state such as which queue
- // is being shown, the current title and description and the PlaybackState.
- private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
-
- @Override
- public void onSessionDestroyed() {
- LogHelper.d(TAG, "Session destroyed. Need to fetch a new Media Session");
- }
-
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- if (state == null) {
- return;
- }
- LogHelper.d(TAG, "Received playback state change to state ", state.toString());
- updateProgressBar();
- setPauseButtonImage();
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- if (metadata == null) {
- return;
- }
- LogHelper.d(TAG, "Received updated metadata: ", metadata);
- updateTrackInfo();
- }
- };
-
- private MediaBrowser.ConnectionCallback mConnectionCallback =
- new MediaBrowser.ConnectionCallback() {
- @Override
- public void onConnected() {
- Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
- if (mMediaBrowser.getSessionToken() == null) {
- throw new IllegalArgumentException("No Session token");
- }
- MediaController mediaController = new MediaController(
- MediaPlaybackActivity.this, mMediaBrowser.getSessionToken());
- mediaController.registerCallback(mMediaControllerCallback);
- MediaPlaybackActivity.this.setMediaController(mediaController);
- mRepeatButton.setVisibility(View.VISIBLE);
- mShuffleButton.setVisibility(View.VISIBLE);
- mQueueButton.setVisibility(View.VISIBLE);
- setRepeatButtonImage(null);
- setShuffleButtonImage(null);
- setPauseButtonImage();
- updateTrackInfo();
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- long delay = updateProgressBar();
- mHandler.postDelayed(this, delay);
- }
- });
- }
-
- @Override
- public void onConnectionFailed() {
- Log.d(TAG, "onConnectionFailed");
- }
-
- @Override
- public void onConnectionSuspended() {
- Log.d(TAG, "onConnectionSuspended");
- mHandler.removeCallbacksAndMessages(null);
- MediaPlaybackActivity.this.setMediaController(null);
- }
- };
-
- int mInitialX = -1;
- int mLastX = -1;
- int mTextWidth = 0;
- int mViewWidth = 0;
- boolean mDraggingLabel = false;
-
- TextView textViewForContainer(View v) {
- View vv = v.findViewById(R.id.artistname);
- if (vv != null) return (TextView) vv;
- vv = v.findViewById(R.id.albumname);
- if (vv != null) return (TextView) vv;
- vv = v.findViewById(R.id.trackname);
- if (vv != null) return (TextView) vv;
- return null;
- }
-
- public boolean onTouch(View v, MotionEvent event) {
- int action = event.getAction();
- TextView tv = textViewForContainer(v);
- if (tv == null) {
- return false;
- }
- if (action == MotionEvent.ACTION_DOWN) {
- v.setBackgroundColor(0xff606060);
- mInitialX = mLastX = (int) event.getX();
- mDraggingLabel = false;
- } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- v.setBackgroundColor(0);
- if (mDraggingLabel) {
- Message msg = mLabelScroller.obtainMessage(0, tv);
- mLabelScroller.sendMessageDelayed(msg, 1000);
- }
- } else if (action == MotionEvent.ACTION_MOVE) {
- if (mDraggingLabel) {
- int scrollx = tv.getScrollX();
- int x = (int) event.getX();
- int delta = mLastX - x;
- if (delta != 0) {
- mLastX = x;
- scrollx += delta;
- if (scrollx > mTextWidth) {
- // scrolled the text completely off the view to the left
- scrollx -= mTextWidth;
- scrollx -= mViewWidth;
- }
- if (scrollx < -mViewWidth) {
- // scrolled the text completely off the view to the right
- scrollx += mViewWidth;
- scrollx += mTextWidth;
- }
- tv.scrollTo(scrollx, 0);
- }
- return true;
- }
- int delta = mInitialX - (int) event.getX();
- if (Math.abs(delta) > mTouchSlop) {
- // start moving
- mLabelScroller.removeMessages(0, tv);
-
- // Only turn ellipsizing off when it's not already off, because it
- // causes the scroll position to be reset to 0.
- if (tv.getEllipsize() != null) {
- tv.setEllipsize(null);
- }
- Layout ll = tv.getLayout();
- // layout might be null if the text just changed, or ellipsizing
- // was just turned off
- if (ll == null) {
- return false;
- }
- // get the non-ellipsized line width, to determine whether scrolling
- // should even be allowed
- mTextWidth = (int) tv.getLayout().getLineWidth(0);
- mViewWidth = tv.getWidth();
- if (mViewWidth > mTextWidth) {
- tv.setEllipsize(TruncateAt.END);
- v.cancelLongPress();
- return false;
- }
- mDraggingLabel = true;
- tv.setHorizontalFadingEdgeEnabled(true);
- v.cancelLongPress();
- return true;
- }
- }
- return false;
- }
-
- Handler mLabelScroller = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- TextView tv = (TextView) msg.obj;
- int x = tv.getScrollX();
- x = x * 3 / 4;
- tv.scrollTo(x, 0);
- if (x == 0) {
- tv.setEllipsize(TruncateAt.END);
- } else {
- Message newmsg = obtainMessage(0, tv);
- mLabelScroller.sendMessageDelayed(newmsg, 15);
- }
- }
- };
-
- public boolean onLongClick(View view) {
- CharSequence title = null;
- String mime = null;
- String query = null;
- if (getMediaController() == null) {
- LogHelper.d(TAG, "No media controller avalable yet");
- return true;
- }
- MediaMetadata metadata = getMediaController().getMetadata();
- if (metadata == null) {
- LogHelper.d(TAG, "No metadata avalable yet");
- return true;
- }
- String artist = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- String album = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
- String song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
- long audioid = metadata.getLong(MediaMetadata.METADATA_KEY_MEDIA_ID);
-
- if (album == null && artist == null && song != null && song.startsWith("recording")) {
- LogHelper.d(TAG, "Item is not music");
- return false;
- }
-
- if (audioid < 0) {
- return false;
- }
-
- boolean knownartist = (artist != null) && !MediaStore.UNKNOWN_STRING.equals(artist);
- boolean knownalbum = (album != null) && !MediaStore.UNKNOWN_STRING.equals(album);
-
- if (knownartist && view.equals(mArtistName.getParent())) {
- title = artist;
- query = artist;
- mime = MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE;
- } else if (knownalbum && view.equals(mAlbumName.getParent())) {
- title = album;
- if (knownartist) {
- query = artist + " " + album;
- } else {
- query = album;
- }
- mime = MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE;
- } else if (view.equals(mTrackName.getParent()) || !knownartist || !knownalbum) {
- if ((song == null) || MediaStore.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;
- } else {
- query = song;
- }
- mime = "audio/*"; // the specific type doesn't matter, so don't bother retrieving it
- } else {
- throw new RuntimeException("shouldn't be here");
- }
- title = getString(R.string.mediasearch, title);
-
- Intent i = new Intent();
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
- i.putExtra(SearchManager.QUERY, query);
- if (knownartist) {
- i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist);
- }
- if (knownalbum) {
- i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, album);
- }
- i.putExtra(MediaStore.EXTRA_MEDIA_TITLE, song);
- i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, mime);
-
- startActivity(Intent.createChooser(i, title));
- return true;
- }
-
- @Override
- public void onStart() {
- LogHelper.d(TAG, "onStart()");
- super.onStart();
- mMediaBrowser.connect();
- }
-
- @Override
- public void onStop() {
- LogHelper.d(TAG, "onStop()");
- mMediaBrowser.disconnect();
- super.onStop();
- }
-
- @Override
- public void onResume() {
- LogHelper.d(TAG, "onResume()");
- super.onResume();
- updateTrackInfo();
- setPauseButtonImage();
- }
-
- @Override
- public void onDestroy() {
- LogHelper.d(TAG, "onDestroy()");
- super.onDestroy();
- }
-
- private void scanBackward(int repcnt, long delta) {
- if (getMediaController() == null) return;
- if (repcnt == 0) {
- mStartSeekPos = getMediaController().getPlaybackState().getPosition();
- mLastSeekEventTime = 0;
- } else {
- if (delta < 5000) {
- // seek at 10x speed for the first 5 seconds
- delta = delta * 10;
- } else {
- // seek at 40x after that
- delta = 50000 + (delta - 5000) * 40;
- }
- long newpos = mStartSeekPos - delta;
- if (newpos < 0) {
- // move to previous track
- getMediaController().getTransportControls().skipToPrevious();
- long duration = getMediaController().getMetadata().getLong(
- MediaMetadata.METADATA_KEY_DURATION);
- mStartSeekPos += duration;
- newpos += duration;
- }
- if (((delta - mLastSeekEventTime) > 250) || repcnt < 0) {
- getMediaController().getTransportControls().seekTo(newpos);
- mLastSeekEventTime = delta;
- }
- updateProgressBar();
- }
- }
-
- private void scanForward(int repcnt, long delta) {
- if (getMediaController() == null) return;
- if (repcnt == 0) {
- mStartSeekPos = getMediaController().getPlaybackState().getPosition();
- mLastSeekEventTime = 0;
- } else {
- if (delta < 5000) {
- // seek at 10x speed for the first 5 seconds
- delta = delta * 10;
- } else {
- // seek at 40x after that
- delta = 50000 + (delta - 5000) * 40;
- }
- long newpos = mStartSeekPos + delta;
- long duration =
- getMediaController().getMetadata().getLong(MediaMetadata.METADATA_KEY_DURATION);
- if (newpos >= duration) {
- // move to next track
- getMediaController().getTransportControls().skipToNext();
- mStartSeekPos -= duration; // is OK to go negative
- newpos -= duration;
- }
- if (((delta - mLastSeekEventTime) > 250) || repcnt < 0) {
- getMediaController().getTransportControls().seekTo(newpos);
- mLastSeekEventTime = delta;
- }
- updateProgressBar();
- }
- }
-
- private void setShuffleMode(MediaPlaybackService.ShuffleMode shuffleMode) {
- Bundle extras = new Bundle();
- extras.putInt(MediaPlaybackService.SHUFFLE_MODE, shuffleMode.ordinal());
- getMediaController().getTransportControls().sendCustomAction(
- MediaPlaybackService.CMD_SHUFFLE, extras);
- }
-
- private void setShuffleButtonImage(MediaPlaybackService.ShuffleMode shuffleMode) {
- if (getMediaController() == null) return;
- Bundle extras = getMediaController().getExtras();
- if (extras == null) return;
- if (shuffleMode == null) {
- shuffleMode = MediaPlaybackService.ShuffleMode
- .values()[extras.getInt(MediaPlaybackService.SHUFFLE_MODE)];
- }
- switch (shuffleMode) {
- case SHUFFLE_RANDOM:
- mShuffleButton.setImageResource(R.drawable.ic_mp_shuffle_on_btn);
- break;
- case SHUFFLE_NONE:
- default:
- mShuffleButton.setImageResource(R.drawable.ic_mp_shuffle_off_btn);
- break;
- }
- }
-
- private void setRepeatMode(MediaPlaybackService.RepeatMode repeatMode) {
- Bundle extras = new Bundle();
- extras.putInt(MediaPlaybackService.REPEAT_MODE, repeatMode.ordinal());
- getMediaController().getTransportControls().sendCustomAction(
- MediaPlaybackService.CMD_REPEAT, extras);
- }
-
- private void setRepeatButtonImage(MediaPlaybackService.RepeatMode repeatMode) {
- if (getMediaController() == null) return;
- Bundle extras = getMediaController().getExtras();
- if (extras == null) return;
- if (repeatMode == null) {
- repeatMode = MediaPlaybackService.RepeatMode
- .values()[extras.getInt(MediaPlaybackService.REPEAT_MODE)];
- }
- switch (repeatMode) {
- case REPEAT_CURRENT:
- mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_once_btn);
- break;
- case REPEAT_ALL:
- mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_all_btn);
- break;
- case REPEAT_NONE:
- default:
- mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_off_btn);
- break;
- }
- }
-
- private void showToast(int resid) {
- if (mToast == null) {
- mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
- }
- mToast.setText(resid);
- mToast.show();
- }
-
- private void setPauseButtonImage() {
- if (getMediaController() == null) {
- return;
- }
- if (getMediaController().getPlaybackState().getState() != PlaybackState.STATE_PLAYING) {
- mPlayPauseButton.setImageResource(android.R.drawable.ic_media_play);
- } else {
- mPlayPauseButton.setImageResource(android.R.drawable.ic_media_pause);
- }
- }
-
- private long updateProgressBar() {
- MediaController mediaController = getMediaController();
- if (mediaController == null || mediaController.getMetadata() == null
- || mediaController.getPlaybackState() == null) {
- return 500;
- }
- long duration = mediaController.getMetadata().getLong(MediaMetadata.METADATA_KEY_DURATION);
- long pos = mediaController.getPlaybackState().getPosition();
- if ((pos >= 0) && (duration > 0)) {
- mCurrentTime.setText(MusicUtils.makeTimeString(this, pos / 1000));
- int progress = (int) (1000 * pos / duration);
- mProgress.setProgress(progress);
-
- if (mediaController.getPlaybackState().getState() == PlaybackState.STATE_PLAYING) {
- mCurrentTime.setVisibility(View.VISIBLE);
- } else {
- // blink the counter
- int vis = mCurrentTime.getVisibility();
- mCurrentTime.setVisibility(vis == View.INVISIBLE ? View.VISIBLE : View.INVISIBLE);
- return 500;
- }
- } else {
- mCurrentTime.setText("--:--");
- mProgress.setProgress(1000);
- }
- // calculate the number of milliseconds until the next full second, so
- // the counter can be updated at just the right time
- long remaining = 1000 - (pos % 1000);
-
- // approximate how often we would need to refresh the slider to
- // move it smoothly
- int width = mProgress.getWidth();
- if (width == 0) width = 320;
- long smoothrefreshtime = duration / width;
-
- if (smoothrefreshtime > remaining) return remaining;
- if (smoothrefreshtime < 20) return 20;
- return smoothrefreshtime;
- }
-
- private void updateTrackInfo() {
- LogHelper.d(TAG, "updateTrackInfo()");
- if (getMediaController() == null) {
- return;
- }
- MediaMetadata metadata = getMediaController().getMetadata();
- if (metadata == null) {
- return;
- }
- mTrackInfo.setVisibility(View.VISIBLE);
- mTrackName.setText(metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
- LogHelper.d(TAG, "Track Name: ", mTrackName.getText());
- String artistName = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- if (artistName.equals(MusicProvider.UNKOWN)) {
- artistName = getString(R.string.unknown_artist_name);
- }
- mArtistName.setText(artistName);
- String albumName = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
- if (albumName.equals(MusicProvider.UNKOWN)) {
- albumName = getString(R.string.unknown_album_name);
- }
- mAlbumName.setText(albumName);
- Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- if (albumArt != null) {
- mAlbumArt.setImageBitmap(albumArt);
- } else {
- mAlbumArt.setImageDrawable(mDefaultAlbumArt);
- }
- mAlbumArt.setVisibility(View.VISIBLE);
-
- long duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
- mTotalTime.setText(MusicUtils.makeTimeString(this, duration / 1000));
- }
-}
diff --git a/src/com/android/music/MediaPlaybackService.java b/src/com/android/music/MediaPlaybackService.java
index 938bb99..255b52b 100644
--- a/src/com/android/music/MediaPlaybackService.java
+++ b/src/com/android/music/MediaPlaybackService.java
@@ -19,83 +19,30 @@ package com.android.music;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
import android.media.browse.MediaBrowser.MediaItem;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.SystemClock;
import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
import android.util.Log;
-import com.android.music.utils.*;
-import java.lang.ref.WeakReference;
import java.util.*;
-import static com.android.music.utils.MediaIDHelper.*;
-
/**
* Provides "background" audio playback capabilities, allowing the
* user to switch between activities without stopping playback.
*/
-public class MediaPlaybackService extends MediaBrowserService implements Playback.Callback {
- private static final String TAG = LogHelper.makeLogTag(MediaPlaybackService.class);
-
- // Delay stopSelf by using a handler.
- private static final int STOP_DELAY = 30000;
-
- public static final String ACTION_CMD = "com.android.music.ACTION_CMD";
- public static final String CMD_NAME = "CMD_NAME";
- public static final String CMD_PAUSE = "CMD_PAUSE";
- public static final String CMD_REPEAT = "CMD_PAUSE";
- public static final String REPEAT_MODE = "REPEAT_MODE";
- public static final String CMD_SHUFFLE = "CMD_SHUFFLE";
- public static final String SHUFFLE_MODE = "SHUFFLE_MODE";
-
- public enum RepeatMode { REPEAT_NONE, REPEAT_ALL, REPEAT_CURRENT }
- public enum ShuffleMode { SHUFFLE_NONE, SHUFFLE_RANDOM }
-
- // Music catalog manager
- private MusicProvider mMusicProvider;
+public class MediaPlaybackService extends MediaBrowserService {
private MediaSession mSession;
- // "Now playing" queue:
- private List<MediaSession.QueueItem> mPlayingQueue = null;
- private Sequence mQueueSeqence = createSequence(0);
- private MediaNotificationManager mMediaNotificationManager;
- // Indicates whether the service was started.
- private boolean mServiceStarted;
- private DelayedStopHandler mDelayedStopHandler = new DelayedStopHandler(this);
- private Playback mPlayback;
- // Default mode is repeat none
- private RepeatMode mRepeatMode = RepeatMode.REPEAT_NONE;
- // Default mode is shuffle none
- private ShuffleMode mShuffleMode = ShuffleMode.SHUFFLE_NONE;
- // Extra information for this session
- private Bundle mExtras;
public MediaPlaybackService() {}
@Override
public void onCreate() {
- LogHelper.d(TAG, "onCreate()");
super.onCreate();
- LogHelper.d(TAG, "Create MusicProvider");
- mPlayingQueue = new ArrayList<>();
- mMusicProvider = new MusicProvider(this);
- LogHelper.d(TAG, "Create MediaSession");
// Start a new MediaSession
mSession = new MediaSession(this, "MediaPlaybackService");
- // Set extra information
- mExtras = new Bundle();
- mExtras.putInt(REPEAT_MODE, mRepeatMode.ordinal());
- mExtras.putInt(SHUFFLE_MODE, mShuffleMode.ordinal());
- mSession.setExtras(mExtras);
// Enable callbacks from MediaButtons and TransportControls
mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS
| MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
@@ -103,778 +50,63 @@ public class MediaPlaybackService extends MediaBrowserService implements Playbac
PlaybackState.Builder stateBuilder = new PlaybackState.Builder().setActions(
PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_PAUSE);
mSession.setPlaybackState(stateBuilder.build());
- // MediaSessionCallback() has methods that handle callbacks from a media controller
- mSession.setCallback(new MediaSessionCallback());
- // Set the session's token so that client activities can communicate with it.
setSessionToken(mSession.getSessionToken());
- mPlayback = new Playback(this, mMusicProvider);
- mPlayback.setState(PlaybackState.STATE_NONE);
- mPlayback.setCallback(this);
- mPlayback.start();
-
Context context = getApplicationContext();
Intent intent = new Intent(context, MusicBrowserActivity.class);
PendingIntent pi = PendingIntent.getActivity(
context, 99 /*request code*/, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mSession.setSessionActivity(pi);
-
- updatePlaybackState(null);
-
- mMediaNotificationManager = new MediaNotificationManager(this);
}
@Override
public int onStartCommand(Intent startIntent, int flags, int startId) {
- if (startIntent != null) {
- String action = startIntent.getAction();
- String command = startIntent.getStringExtra(CMD_NAME);
- if (ACTION_CMD.equals(action)) {
- if (CMD_PAUSE.equals(command)) {
- if (mPlayback != null && mPlayback.isPlaying()) {
- handlePauseRequest();
- }
- }
- }
- }
return START_STICKY;
}
@Override
- public void onDestroy() {
- Log.d(TAG, "onDestroy");
- // Service is being killed, so make sure we release our resources
- handleStopRequest(null);
-
- mDelayedStopHandler.removeCallbacksAndMessages(null);
- // Always release the MediaSession to clean up resources
- // and notify associated MediaController(s).
- mSession.release();
- }
+ public void onDestroy() {}
@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
- Log.d(TAG,
- "OnGetRoot: clientPackageName=" + clientPackageName + "; clientUid=" + clientUid
- + " ; rootHints=" + rootHints);
- // Allow everyone to browse
- return new BrowserRoot(MEDIA_ID_ROOT, null);
+ return null;
}
@Override
public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
- Log.d(TAG, "OnLoadChildren: parentMediaId=" + parentMediaId);
- // Browsing not allowed
- if (parentMediaId == null) {
- result.sendResult(null);
- return;
- }
- if (!mMusicProvider.isInitialized()) {
- // Use result.detach to allow calling result.sendResult from another thread:
- result.detach();
-
- mMusicProvider.retrieveMediaAsync(new MusicProvider.MusicProviderCallback() {
- @Override
- public void onMusicCatalogReady(boolean success) {
- Log.d(TAG, "Received catalog result, success: " + String.valueOf(success));
- if (success) {
- onLoadChildren(parentMediaId, result);
- } else {
- result.sendResult(Collections.emptyList());
- }
- }
- });
-
- } else {
- // If our music catalog is already loaded/cached, load them into result immediately
- List<MediaItem> mediaItems = new ArrayList<>();
-
- switch (parentMediaId) {
- case MEDIA_ID_ROOT:
- Log.d(TAG, "OnLoadChildren.ROOT");
- mediaItems.add(new MediaItem(new MediaDescription.Builder()
- .setMediaId(MEDIA_ID_MUSICS_BY_ARTIST)
- .setTitle("Artists")
- .build(),
- MediaItem.FLAG_BROWSABLE));
- mediaItems.add(new MediaItem(new MediaDescription.Builder()
- .setMediaId(MEDIA_ID_MUSICS_BY_ALBUM)
- .setTitle("Albums")
- .build(),
- MediaItem.FLAG_BROWSABLE));
- mediaItems.add(new MediaItem(new MediaDescription.Builder()
- .setMediaId(MEDIA_ID_MUSICS_BY_SONG)
- .setTitle("Songs")
- .build(),
- MediaItem.FLAG_BROWSABLE));
- mediaItems.add(new MediaItem(new MediaDescription.Builder()
- .setMediaId(MEDIA_ID_MUSICS_BY_PLAYLIST)
- .setTitle("Playlists")
- .build(),
- MediaItem.FLAG_BROWSABLE));
- break;
- case MEDIA_ID_MUSICS_BY_ARTIST:
- Log.d(TAG, "OnLoadChildren.ARTIST");
- for (String artist : mMusicProvider.getArtists()) {
- MediaItem item = new MediaItem(
- new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.createBrowseCategoryMediaID(
- MEDIA_ID_MUSICS_BY_ARTIST, artist))
- .setTitle(artist)
- .build(),
- MediaItem.FLAG_BROWSABLE);
- mediaItems.add(item);
- }
- break;
- case MEDIA_ID_MUSICS_BY_PLAYLIST:
- LogHelper.d(TAG, "OnLoadChildren.PLAYLIST");
- for (String playlist : mMusicProvider.getPlaylists()) {
- MediaItem item = new MediaItem(
- new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.createBrowseCategoryMediaID(
- MEDIA_ID_MUSICS_BY_PLAYLIST, playlist))
- .setTitle(playlist)
- .build(),
- MediaItem.FLAG_BROWSABLE);
- mediaItems.add(item);
- }
- break;
- case MEDIA_ID_MUSICS_BY_ALBUM:
- Log.d(TAG, "OnLoadChildren.ALBUM");
- loadAlbum(mMusicProvider.getAlbums(), mediaItems);
- break;
- case MEDIA_ID_MUSICS_BY_SONG:
- Log.d(TAG, "OnLoadChildren.SONG");
- String hierarchyAwareMediaID = MediaIDHelper.createBrowseCategoryMediaID(
- parentMediaId, MEDIA_ID_MUSICS_BY_SONG);
- loadSong(mMusicProvider.getMusicList(), mediaItems, hierarchyAwareMediaID);
- break;
- default:
- if (parentMediaId.startsWith(MEDIA_ID_MUSICS_BY_ARTIST)) {
- String artist = MediaIDHelper.getHierarchy(parentMediaId)[1];
- Log.d(TAG, "OnLoadChildren.SONGS_BY_ARTIST artist=" + artist);
- loadAlbum(mMusicProvider.getAlbumByArtist(artist), mediaItems);
- } else if (parentMediaId.startsWith(MEDIA_ID_MUSICS_BY_ALBUM)) {
- String album = MediaIDHelper.getHierarchy(parentMediaId)[1];
- Log.d(TAG, "OnLoadChildren.SONGS_BY_ALBUM album=" + album);
- loadSong(mMusicProvider.getMusicsByAlbum(album), mediaItems, parentMediaId);
- } else if (parentMediaId.startsWith(MEDIA_ID_MUSICS_BY_PLAYLIST)) {
- String playlist = MediaIDHelper.getHierarchy(parentMediaId)[1];
- LogHelper.d(TAG, "OnLoadChildren.SONGS_BY_PLAYLIST playlist=", playlist);
- if (playlist.equals(MEDIA_ID_NOW_PLAYING) && mPlayingQueue != null
- && mPlayingQueue.size() > 0) {
- loadPlayingQueue(mediaItems, parentMediaId);
- } else {
- loadSong(mMusicProvider.getMusicsByPlaylist(playlist), mediaItems,
- parentMediaId);
- }
- } else {
- Log.w(TAG, "Skipping unmatched parentMediaId: " + parentMediaId);
- }
- break;
- }
- Log.d(TAG,
- "OnLoadChildren sending " + mediaItems.size() + " results for "
- + parentMediaId);
- result.sendResult(mediaItems);
- }
- }
-
- private void loadPlayingQueue(List<MediaItem> mediaItems, String parentId) {
- for (MediaSession.QueueItem queueItem : mPlayingQueue) {
- MediaItem mediaItem =
- new MediaItem(queueItem.getDescription(), MediaItem.FLAG_PLAYABLE);
- mediaItems.add(mediaItem);
- }
- }
-
- private void loadSong(
- Iterable<MediaMetadata> songList, List<MediaItem> mediaItems, String parentId) {
- for (MediaMetadata metadata : songList) {
- String hierarchyAwareMediaID =
- MediaIDHelper.createMediaID(metadata.getDescription().getMediaId(), parentId);
- Bundle songExtra = new Bundle();
- songExtra.putLong(MediaMetadata.METADATA_KEY_DURATION,
- metadata.getLong(MediaMetadata.METADATA_KEY_DURATION));
- String title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
- String artistName = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- MediaItem item = new MediaItem(new MediaDescription.Builder()
- .setMediaId(hierarchyAwareMediaID)
- .setTitle(title)
- .setSubtitle(artistName)
- .setExtras(songExtra)
- .build(),
- MediaItem.FLAG_PLAYABLE);
- mediaItems.add(item);
- }
- }
-
- private void loadAlbum(Iterable<MediaMetadata> albumList, List<MediaItem> mediaItems) {
- for (MediaMetadata albumMetadata : albumList) {
- String albumName = albumMetadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
- String artistName = albumMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- Bundle albumExtra = new Bundle();
- albumExtra.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS,
- albumMetadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS));
- MediaItem item = new MediaItem(
- new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.createBrowseCategoryMediaID(
- MEDIA_ID_MUSICS_BY_ALBUM, albumName))
- .setTitle(albumName)
- .setSubtitle(artistName)
- .setIconBitmap(
- albumMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART))
- .setExtras(albumExtra)
- .build(),
- MediaItem.FLAG_BROWSABLE);
- mediaItems.add(item);
- }
+ result.sendResult(null);
+ return;
}
private final class MediaSessionCallback extends MediaSession.Callback {
@Override
- public void onPlay() {
- Log.d(TAG, "play");
-
- if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
- mPlayingQueue = QueueHelper.getRandomQueue(mMusicProvider);
- mSession.setQueue(mPlayingQueue);
- mSession.setQueueTitle(getString(R.string.random_queue_title));
- // start playing from the beginning of the queue
- mQueueSeqence = createSequence(mPlayingQueue.size());
- }
-
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- handlePlayRequest();
- }
- }
-
- @Override
- public void onSkipToQueueItem(long queueId) {
- LogHelper.d(TAG, "OnSkipToQueueItem:", queueId);
-
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- // set the current index on queue from the music Id:
- mQueueSeqence.setCurrent(QueueHelper.getMusicIndexOnQueue(mPlayingQueue, queueId));
- // play the music
- handlePlayRequest();
- }
- }
-
- @Override
- public void onSeekTo(long position) {
- Log.d(TAG, "onSeekTo:" + position);
- mPlayback.seekTo((int) position);
- }
+ public void onPlay() {}
@Override
- public void onPlayFromMediaId(String mediaId, Bundle extras) {
- LogHelper.d(TAG, "playFromMediaId mediaId:", mediaId, " extras=", extras);
-
- // The mediaId used here is not the unique musicId. This one comes from the
- // MediaBrowser, and is actually a "hierarchy-aware mediaID": a concatenation of
- // the hierarchy in MediaBrowser and the actual unique musicID. This is necessary
- // so we can build the correct playing queue, based on where the track was
- // selected from.
- mPlayingQueue = QueueHelper.getPlayingQueue(mediaId, mMusicProvider);
- mSession.setQueue(mPlayingQueue);
- String queueTitle = getString(R.string.browse_musics_by_genre_subtitle,
- MediaIDHelper.extractBrowseCategoryValueFromMediaID(mediaId));
- mSession.setQueueTitle(queueTitle);
- mQueueSeqence = createSequence(mPlayingQueue.size());
-
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- // get the current index on queue from the media Id:
- int index = QueueHelper.getMusicIndexOnQueue(mPlayingQueue, mediaId);
- if (index < 0) {
- LogHelper.e(TAG, "playFromMediaId: media ID ", mediaId,
- " could not be found on queue. Ignoring.");
- } else {
- mQueueSeqence.setCurrent(index);
- // play the music
- handlePlayRequest();
- }
- }
- }
+ public void onSkipToQueueItem(long queueId) {}
@Override
- public void onPause() {
- LogHelper.d(TAG, "pause. current state=" + mPlayback.getState());
- handlePauseRequest();
- }
+ public void onSeekTo(long position) {}
@Override
- public void onStop() {
- LogHelper.d(TAG, "stop. current state=" + mPlayback.getState());
- handleStopRequest(null);
- }
+ public void onPlayFromMediaId(String mediaId, Bundle extras) {}
@Override
- public void onSkipToNext() {
- LogHelper.d(TAG, "skipToNext");
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- if (!mQueueSeqence.hasNext()) {
- // This sample's behavior: skipping to next when in last song returns to the
- // first song.
- mQueueSeqence.reset();
- } else {
- mQueueSeqence.next();
- }
- }
- if (QueueHelper.isIndexPlayable(mQueueSeqence.getCurrent(), mPlayingQueue)) {
- handlePlayRequest();
- } else {
- LogHelper.e(TAG,
- "skipToNext: cannot skip to next. next Index=" + mQueueSeqence.getCurrent()
- + " queue length="
- + (mPlayingQueue == null ? "null" : mPlayingQueue.size()));
- handleStopRequest("Cannot skip");
- }
- }
+ public void onPause() {}
@Override
- public void onSkipToPrevious() {
- LogHelper.d(TAG, "skipToPrevious");
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- if (!mQueueSeqence.hasPrev()) {
- // This sample's behavior: skipping to previous when in first song restarts the
- // first song.
- mQueueSeqence.reset();
- } else {
- mQueueSeqence.prev();
- }
- }
- if (QueueHelper.isIndexPlayable(mQueueSeqence.getCurrent(), mPlayingQueue)) {
- handlePlayRequest();
- } else {
- LogHelper.e(TAG,
- "skipToPrevious: cannot skip to previous. previous Index="
- + mQueueSeqence.getCurrent() + " queue length="
- + (mPlayingQueue == null ? "null" : mPlayingQueue.size()));
- handleStopRequest("Cannot skip");
- }
- }
+ public void onStop() {}
@Override
- public void onPlayFromSearch(String query, Bundle extras) {
- LogHelper.d(TAG, "playFromSearch query=", query);
-
- if (TextUtils.isEmpty(query)) {
- // A generic search like "Play music" sends an empty query
- // and it's expected that we start playing something. What will be played depends
- // on the app: favorite playlist, "I'm feeling lucky", most recent, etc.
- mPlayingQueue = QueueHelper.getRandomQueue(mMusicProvider);
- } else {
- mPlayingQueue = QueueHelper.getPlayingQueueFromSearch(query, mMusicProvider);
- }
-
- LogHelper.d(TAG, "playFromSearch playqueue.length=" + mPlayingQueue.size());
- mSession.setQueue(mPlayingQueue);
- mQueueSeqence = createSequence(mPlayingQueue.size());
-
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- // immediately start playing from the beginning of the search results
- handlePlayRequest();
- } else {
- // if nothing was found, we need to warn the user and stop playing
- handleStopRequest(getString(R.string.no_search_results));
- }
- }
-
- @Override
- public void onCustomAction(String action, Bundle extras) {
- LogHelper.d(TAG, "onCustomAction action=", action, ", extras=", extras);
- switch (action) {
- case CMD_REPEAT:
- mRepeatMode = RepeatMode.values()[extras.getInt(REPEAT_MODE)];
- mExtras.putInt(REPEAT_MODE, mRepeatMode.ordinal());
- mSession.setExtras(mExtras);
- LogHelper.d(TAG, "modified repeatMode=", mRepeatMode);
- break;
- case CMD_SHUFFLE:
- mShuffleMode = ShuffleMode.values()[extras.getInt(SHUFFLE_MODE)];
- mExtras.putInt(SHUFFLE_MODE, mShuffleMode.ordinal());
- mSession.setExtras(mExtras);
- LogHelper.d(TAG, "modified shuffleMode=", mShuffleMode);
- // Shuffle mode was updated, need to update current sequence to reflect this
- updateSequence();
- break;
- default:
- LogHelper.d(TAG, "Unkown action=", action);
- break;
- }
- }
- }
-
- /**
- * Handle a request to play music
- */
- private void handlePlayRequest() {
- LogHelper.d(TAG, "handlePlayRequest: mState=" + mPlayback.getState());
-
- mDelayedStopHandler.removeCallbacksAndMessages(null);
- if (!mServiceStarted) {
- LogHelper.v(TAG, "Starting service");
- // The MusicService needs to keep running even after the calling MediaBrowser
- // is disconnected. Call startService(Intent) and then stopSelf(..) when we no longer
- // need to play media.
- startService(new Intent(getApplicationContext(), MediaPlaybackService.class));
- mServiceStarted = true;
- }
-
- if (!mSession.isActive()) {
- mSession.setActive(true);
- }
-
- if (QueueHelper.isIndexPlayable(mQueueSeqence.getCurrent(), mPlayingQueue)) {
- updateMetadata();
- mPlayback.play(mPlayingQueue.get(mQueueSeqence.getCurrent()));
- }
- }
-
- /**
- * Handle a request to pause music
- */
- private void handlePauseRequest() {
- LogHelper.d(TAG, "handlePauseRequest: mState=" + mPlayback.getState());
- mPlayback.pause();
- // reset the delayed stop handler.
- mDelayedStopHandler.removeCallbacksAndMessages(null);
- mDelayedStopHandler.sendEmptyMessageDelayed(0, STOP_DELAY);
- }
-
- /**
- * Handle a request to stop music
- */
- private void handleStopRequest(String withError) {
- LogHelper.d(
- TAG, "handleStopRequest: mState=" + mPlayback.getState() + " error=", withError);
- mPlayback.stop(true);
- // reset the delayed stop handler.
- mDelayedStopHandler.removeCallbacksAndMessages(null);
- mDelayedStopHandler.sendEmptyMessageDelayed(0, STOP_DELAY);
-
- updatePlaybackState(withError);
-
- // service is no longer necessary. Will be started again if needed.
- stopSelf();
- mServiceStarted = false;
- }
-
- private void updateMetadata() {
- if (!QueueHelper.isIndexPlayable(mQueueSeqence.getCurrent(), mPlayingQueue)) {
- LogHelper.e(TAG, "Can't retrieve current metadata.");
- updatePlaybackState(getResources().getString(R.string.error_no_metadata));
- return;
- }
- MediaSession.QueueItem queueItem = mPlayingQueue.get(mQueueSeqence.getCurrent());
- String musicId =
- MediaIDHelper.extractMusicIDFromMediaID(queueItem.getDescription().getMediaId());
- MediaMetadata track = mMusicProvider.getMusicByMediaId(musicId).getMetadata();
- final String trackId = track.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
- if (!musicId.equals(trackId)) {
- IllegalStateException e = new IllegalStateException("track ID should match musicId.");
- LogHelper.e(TAG, "track ID should match musicId.", " musicId=", musicId,
- " trackId=", trackId,
- " mediaId from queueItem=", queueItem.getDescription().getMediaId(),
- " title from queueItem=", queueItem.getDescription().getTitle(),
- " mediaId from track=", track.getDescription().getMediaId(),
- " title from track=", track.getDescription().getTitle(),
- " source.hashcode from track=",
- track.getString(MusicProvider.CUSTOM_METADATA_TRACK_SOURCE).hashCode(), e);
- throw e;
- }
- LogHelper.d(TAG, "Updating metadata for MusicID= " + musicId);
- mSession.setMetadata(track);
-
- // Set the proper album artwork on the media session, so it can be shown in the
- // locked screen and in other places.
- if (track.getDescription().getIconBitmap() == null
- && track.getDescription().getIconUri() != null) {
- String albumUri = track.getDescription().getIconUri().toString();
- AlbumArtCache.getInstance().fetch(albumUri, new AlbumArtCache.FetchListener() {
- @Override
- public void onFetched(String artUrl, Bitmap bitmap, Bitmap icon) {
- MediaSession.QueueItem queueItem =
- mPlayingQueue.get(mQueueSeqence.getCurrent());
- MediaMetadata track = mMusicProvider.getMusicByMediaId(trackId).getMetadata();
- track = new MediaMetadata
- .Builder(track)
-
- // set high resolution bitmap in METADATA_KEY_ALBUM_ART. This is
- // used, for
- // example, on the lockscreen background when the media session
- // is active.
- .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap)
-
- // set small version of the album art in the DISPLAY_ICON. This
- // is used on
- // the MediaDescription and thus it should be small to be
- // serialized if
- // necessary..
- .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, icon)
-
- .build();
-
- mMusicProvider.updateMusic(trackId, track);
-
- // If we are still playing the same music
- String currentPlayingId = MediaIDHelper.extractMusicIDFromMediaID(
- queueItem.getDescription().getMediaId());
- if (trackId.equals(currentPlayingId)) {
- mSession.setMetadata(track);
- }
- }
- });
- }
- }
-
- /**
- * Update the current media player state, optionally showing an error message.
- *
- * @param error if not null, error message to present to the user.
- */
- private void updatePlaybackState(String error) {
- LogHelper.d(TAG, "updatePlaybackState, playback state=" + mPlayback.getState());
- long position = PlaybackState.PLAYBACK_POSITION_UNKNOWN;
- if (mPlayback != null && mPlayback.isConnected()) {
- position = mPlayback.getCurrentStreamPosition();
- }
-
- PlaybackState.Builder stateBuilder =
- new PlaybackState.Builder().setActions(getAvailableActions());
-
- int state = mPlayback.getState();
-
- // If there is an error message, send it to the playback state:
- if (error != null) {
- // Error states are really only supposed to be used for errors that cause playback to
- // stop unexpectedly and persist until the user takes action to fix it.
- stateBuilder.setErrorMessage(error);
- state = PlaybackState.STATE_ERROR;
- }
- stateBuilder.setState(state, position, 1.0f, SystemClock.elapsedRealtime());
-
- // Set the activeQueueItemId if the current index is valid.
- if (QueueHelper.isIndexPlayable(mQueueSeqence.getCurrent(), mPlayingQueue)) {
- MediaSession.QueueItem item = mPlayingQueue.get(mQueueSeqence.getCurrent());
- stateBuilder.setActiveQueueItemId(item.getQueueId());
- }
-
- mSession.setPlaybackState(stateBuilder.build());
-
- if (state == PlaybackState.STATE_PLAYING || state == PlaybackState.STATE_PAUSED) {
- mMediaNotificationManager.startNotification();
- }
- }
-
- private long getAvailableActions() {
- long actions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_FROM_MEDIA_ID
- | PlaybackState.ACTION_PLAY_FROM_SEARCH;
- if (mPlayingQueue == null || mPlayingQueue.isEmpty()) {
- return actions;
- }
- if (mPlayback.isPlaying()) {
- actions |= PlaybackState.ACTION_PAUSE;
- }
- if (mQueueSeqence.hasPrev()) {
- actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
- }
- if (mQueueSeqence.hasNext()) {
- actions |= PlaybackState.ACTION_SKIP_TO_NEXT;
- }
- return actions;
- }
-
- private MediaMetadata getCurrentPlayingMusic() {
- if (QueueHelper.isIndexPlayable(mQueueSeqence.getCurrent(), mPlayingQueue)) {
- MediaSession.QueueItem item = mPlayingQueue.get(mQueueSeqence.getCurrent());
- if (item != null) {
- LogHelper.d(TAG,
- "getCurrentPlayingMusic for musicId=", item.getDescription().getMediaId());
- return mMusicProvider
- .getMusicByMediaId(MediaIDHelper.extractMusicIDFromMediaID(
- item.getDescription().getMediaId()))
- .getMetadata();
- }
- }
- return null;
- }
-
- /**
- * Implementation of the Playback.Callback interface
- */
- @Override
- public void onCompletion() {
- // The media player finished playing the current song, so we go ahead
- // and start the next.
- if (mPlayingQueue != null && !mPlayingQueue.isEmpty()) {
- switch (mRepeatMode) {
- case REPEAT_ALL:
- if (mQueueSeqence.hasNext()) {
- // Increase the index
- mQueueSeqence.next();
- } else {
- // Restart queue when reaching the end
- mQueueSeqence.reset();
- }
- break;
- case REPEAT_CURRENT:
- // Do not change the index
- break;
- case REPEAT_NONE:
- default:
- if (mQueueSeqence.hasNext()) {
- // Increase the index
- mQueueSeqence.next();
- } else {
- // Stop the queue when reaching the end
- handleStopRequest(null);
- }
- break;
- }
- handlePlayRequest();
- } else {
- // If there is nothing to play, we stop and release the resources:
- handleStopRequest(null);
- }
- }
-
- @Override
- public void onPlaybackStatusChanged(int state) {
- updatePlaybackState(null);
- }
-
- @Override
- public void onError(String error) {
- updatePlaybackState(error);
- }
-
- /**
- * A simple handler that stops the service if playback is not active (playing)
- */
- private static class DelayedStopHandler extends Handler {
- private final WeakReference<MediaPlaybackService> mWeakReference;
-
- private DelayedStopHandler(MediaPlaybackService service) {
- mWeakReference = new WeakReference<>(service);
- }
-
- @Override
- public void handleMessage(Message msg) {
- MediaPlaybackService service = mWeakReference.get();
- if (service != null && service.mPlayback != null) {
- if (service.mPlayback.isPlaying()) {
- Log.d(TAG, "Ignoring delayed stop since the media player is in use.");
- return;
- }
- Log.d(TAG, "Stopping service with delay handler.");
- service.stopSelf();
- service.mServiceStarted = false;
- }
- }
- }
-
- private Sequence createSequence(int length) {
- // Create new sequence based on current shuffle mode
- if (mShuffleMode == ShuffleMode.SHUFFLE_RANDOM) {
- return new RandomSequence(length);
- }
- return new Sequence(length);
- }
-
- private void updateSequence() {
- // Get current playing index
- int current = mQueueSeqence.getCurrent();
- // Create new sequence with current shuffle mode
- mQueueSeqence = createSequence(mQueueSeqence.getLength());
- // Restore current playing index
- mQueueSeqence.setCurrent(current);
- }
-
- /*
- * Sequence of integers 0..n-1 in order
- */
- private static class Sequence {
- private final int mLength;
- private int mCurrent;
-
- private Sequence(int length) {
- mLength = length;
- mCurrent = 0;
- }
-
- void reset() {
- mCurrent = 0;
- }
-
- int getLength() {
- return mLength;
- }
-
- void setCurrent(int current) {
- if (current < 0 || current >= mLength) {
- throw new IllegalArgumentException();
- }
- mCurrent = current;
- }
-
- int getCurrent() {
- return mCurrent;
- }
-
- boolean hasNext() {
- return mCurrent < mLength - 1;
- }
-
- boolean hasPrev() {
- return mCurrent > 0;
- }
-
- void next() {
- if (!hasNext()) {
- throw new IllegalStateException();
- }
- ++mCurrent;
- }
-
- void prev() {
- if (!hasPrev()) {
- throw new IllegalStateException();
- }
- --mCurrent;
- }
- }
-
- /*
- * Random sequence of integers 0..n-1
- */
- private static class RandomSequence extends Sequence {
- private final ArrayList<Integer> mShuffledSequence;
-
- private RandomSequence(int length) {
- super(length);
- mShuffledSequence = new ArrayList<>(length);
- for (int i = 0; i < length; ++i) {
- mShuffledSequence.add(i);
- }
- Collections.shuffle(mShuffledSequence);
- }
+ public void onSkipToNext() {}
@Override
- void reset() {
- super.reset();
- Collections.shuffle(mShuffledSequence);
- }
+ public void onSkipToPrevious() {}
@Override
- void setCurrent(int current) {
- super.setCurrent(mShuffledSequence.indexOf(current));
- }
+ public void onPlayFromSearch(String query, Bundle extras) {}
@Override
- int getCurrent() {
- return mShuffledSequence.get(super.getCurrent());
- }
+ public void onCustomAction(String action, Bundle extras) {}
}
}
diff --git a/src/com/android/music/MusicAlphabetIndexer.java b/src/com/android/music/MusicAlphabetIndexer.java
deleted file mode 100644
index 8e84a72..0000000
--- a/src/com/android/music/MusicAlphabetIndexer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.database.Cursor;
-import android.provider.MediaStore;
-import android.widget.AlphabetIndexer;
-
-/**
- * Handles comparisons in a different way because the Album, Song and Artist name
- * are stripped of some prefixes such as "a", "an", "the" and some symbols.
- *
- */
-class MusicAlphabetIndexer extends AlphabetIndexer {
- public MusicAlphabetIndexer(Cursor cursor, int sortedColumnIndex, CharSequence alphabet) {
- super(cursor, sortedColumnIndex, alphabet);
- }
-
- @Override
- protected int compare(String word, String letter) {
- String wordKey = MediaStore.Audio.keyFor(word);
- String letterKey = MediaStore.Audio.keyFor(letter);
- if (wordKey.startsWith(letter)) {
- return 0;
- } else {
- return wordKey.compareTo(letterKey);
- }
- }
-}
diff --git a/src/com/android/music/MusicBrowserActivity.java b/src/com/android/music/MusicBrowserActivity.java
index b6b30e8..ca9615e 100644
--- a/src/com/android/music/MusicBrowserActivity.java
+++ b/src/com/android/music/MusicBrowserActivity.java
@@ -16,63 +16,22 @@
package com.android.music;
-import android.Manifest.permission;
import android.app.Activity;
-import android.content.pm.PackageManager;
import android.os.Bundle;
-import com.android.music.utils.LogHelper;
+/**
+ * A skeleton class that provides empty implementations for Activity class.
+ */
public class MusicBrowserActivity extends Activity {
- private static final String TAG = LogHelper.makeLogTag(MusicBrowserActivity.class);
-
- private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 42;
-
public MusicBrowserActivity() {}
- /**
- * Called when the activity is first created.
- */
@Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- LogHelper.d(TAG, "onCreate()");
- if (checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE},
- MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
- return;
- }
- initApp();
- }
-
- public void initApp() {
- int activeTab = MusicUtils.getIntPref(this, "activetab", R.id.artisttab);
- LogHelper.d(TAG, "initApp() activeTab = ", activeTab);
- if (activeTab != R.id.artisttab && activeTab != R.id.albumtab && activeTab != R.id.songtab
- && activeTab != R.id.playlisttab) {
- activeTab = R.id.artisttab;
- }
- MusicUtils.activateTab(this, activeTab);
- }
+ public void onCreate(Bundle icicle) {}
@Override
- public void onDestroy() {
- LogHelper.d(TAG, "onDestroy()");
- super.onDestroy();
- }
+ public void onDestroy() {}
@Override
public void onRequestPermissionsResult(
- int requestCode, String permissions[], int[] grantResults) {
- switch (requestCode) {
- case MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE: {
- if (grantResults.length == 0
- || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
- finish();
- return;
- }
- initApp();
- }
- }
- }
+ int requestCode, String permissions[], int[] grantResults) {}
}
diff --git a/src/com/android/music/MusicPicker.java b/src/com/android/music/MusicPicker.java
deleted file mode 100644
index ea32ec9..0000000
--- a/src/com/android/music/MusicPicker.java
+++ /dev/null
@@ -1,688 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.ListActivity;
-import android.content.AsyncQueryHandler;
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Intent;
-import android.database.CharArrayBuffer;
-import android.database.Cursor;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.provider.MediaStore;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.animation.AnimationUtils;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.RadioButton;
-import android.widget.SectionIndexer;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-
-import java.io.IOException;
-import java.text.Collator;
-import java.util.Formatter;
-import java.util.Locale;
-
-/**
- * Activity allowing the user to select a music track on the device, and
- * return it to its caller. The music picker user interface is fairly
- * extensive, providing information about each track like the music
- * application (title, author, album, duration), as well as the ability to
- * previous tracks and sort them in different orders.
- *
- * <p>This class also illustrates how you can load data from a content
- * provider asynchronously, providing a good UI while doing so, perform
- * indexing of the content for use inside of a {@link FastScrollView}, and
- * perform filtering of the data as the user presses keys.
- */
-public class MusicPicker
- extends ListActivity implements View.OnClickListener, MediaPlayer.OnCompletionListener {
- static final boolean DBG = false;
- static final String TAG = "MusicPicker";
-
- /** Holds the previous state of the list, to restore after the async
- * query has completed. */
- static final String LIST_STATE_KEY = "liststate";
- /** Remember whether the list last had focus for restoring its state. */
- static final String FOCUS_KEY = "focused";
- /** Remember the last ordering mode for restoring state. */
- static final String SORT_MODE_KEY = "sortMode";
-
- /** Arbitrary number, doesn't matter since we only do one query type. */
- static final int MY_QUERY_TOKEN = 42;
-
- /** Menu item to sort the music list by track title. */
- static final int TRACK_MENU = Menu.FIRST;
- /** Menu item to sort the music list by album title. */
- static final int ALBUM_MENU = Menu.FIRST + 1;
- /** Menu item to sort the music list by artist name. */
- static final int ARTIST_MENU = Menu.FIRST + 2;
-
- /** These are the columns in the music cursor that we are interested in. */
- static final String[] CURSOR_COLS = new String[] {MediaStore.Audio.Media._ID,
- MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.TITLE_KEY,
- MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM,
- MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ARTIST_ID,
- MediaStore.Audio.Media.DURATION, MediaStore.Audio.Media.TRACK};
-
- /** Formatting optimization to avoid creating many temporary objects. */
- static StringBuilder sFormatBuilder = new StringBuilder();
- /** Formatting optimization to avoid creating many temporary objects. */
- static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
- /** Formatting optimization to avoid creating many temporary objects. */
- static final Object[] sTimeArgs = new Object[5];
-
- /** Uri to the directory of all music being displayed. */
- Uri mBaseUri;
-
- /** This is the adapter used to display all of the tracks. */
- TrackListAdapter mAdapter;
- /** Our instance of QueryHandler used to perform async background queries. */
- QueryHandler mQueryHandler;
-
- /** Used to keep track of the last scroll state of the list. */
- Parcelable mListState = null;
- /** Used to keep track of whether the list last had focus. */
- boolean mListHasFocus;
-
- /** The current cursor on the music that is being displayed. */
- Cursor mCursor;
- /** The actual sort order the user has selected. */
- int mSortMode = -1;
- /** SQL order by string describing the currently selected sort order. */
- String mSortOrder;
-
- /** Container of the in-screen progress indicator, to be able to hide it
- * when done loading the initial cursor. */
- View mProgressContainer;
- /** Container of the list view hierarchy, to be able to show it when done
- * loading the initial cursor. */
- View mListContainer;
- /** Set to true when the list view has been shown for the first time. */
- boolean mListShown;
-
- /** View holding the okay button. */
- View mOkayButton;
- /** View holding the cancel button. */
- View mCancelButton;
-
- /** Which track row ID the user has last selected. */
- long mSelectedId = -1;
- /** Completel Uri that the user has last selected. */
- Uri mSelectedUri;
-
- /** If >= 0, we are currently playing a track for preview, and this is its
- * row ID. */
- long mPlayingId = -1;
-
- /** This is used for playing previews of the music files. */
- MediaPlayer mMediaPlayer;
-
- /**
- * A special implementation of SimpleCursorAdapter that knows how to bind
- * our cursor data to our list item structure, and takes care of other
- * advanced features such as indexing and filtering.
- */
- class TrackListAdapter extends SimpleCursorAdapter implements SectionIndexer {
- final ListView mListView;
-
- private final StringBuilder mBuilder = new StringBuilder();
- private final String mUnknownArtist;
- private final String mUnknownAlbum;
-
- private int mIdIdx;
- private int mTitleIdx;
- private int mArtistIdx;
- private int mAlbumIdx;
- private int mDurationIdx;
-
- private boolean mLoading = true;
- private int mIndexerSortMode;
- private MusicAlphabetIndexer mIndexer;
-
- class ViewHolder {
- TextView line1;
- TextView line2;
- TextView duration;
- RadioButton radio;
- ImageView play_indicator;
- CharArrayBuffer buffer1;
- char[] buffer2;
- }
-
- TrackListAdapter(Context context, ListView listView, int layout, String[] from, int[] to) {
- super(context, layout, null, from, to);
- mListView = listView;
- mUnknownArtist = context.getString(R.string.unknown_artist_name);
- mUnknownAlbum = context.getString(R.string.unknown_album_name);
- }
-
- /**
- * The mLoading flag is set while we are performing a background
- * query, to avoid displaying the "No music" empty view during
- * this time.
- */
- public void setLoading(boolean loading) {
- mLoading = loading;
- }
-
- @Override
- public boolean isEmpty() {
- if (mLoading) {
- // We don't want the empty state to show when loading.
- return false;
- } else {
- return super.isEmpty();
- }
- }
-
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- View v = super.newView(context, cursor, parent);
- 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.radio = (RadioButton) v.findViewById(R.id.radio);
- vh.play_indicator = (ImageView) v.findViewById(R.id.play_indicator);
- vh.buffer1 = new CharArrayBuffer(100);
- vh.buffer2 = new char[200];
- v.setTag(vh);
- return v;
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- ViewHolder vh = (ViewHolder) view.getTag();
-
- cursor.copyStringToBuffer(mTitleIdx, vh.buffer1);
- vh.line1.setText(vh.buffer1.data, 0, vh.buffer1.sizeCopied);
-
- int secs = cursor.getInt(mDurationIdx) / 1000;
- if (secs == 0) {
- vh.duration.setText("");
- } else {
- vh.duration.setText(MusicUtils.makeTimeString(context, secs));
- }
-
- final StringBuilder builder = mBuilder;
- builder.delete(0, builder.length());
-
- String name = cursor.getString(mAlbumIdx);
- if (name == null || name.equals("<unknown>")) {
- builder.append(mUnknownAlbum);
- } else {
- builder.append(name);
- }
- builder.append('\n');
- name = cursor.getString(mArtistIdx);
- if (name == null || name.equals("<unknown>")) {
- builder.append(mUnknownArtist);
- } else {
- builder.append(name);
- }
- int len = builder.length();
- if (vh.buffer2.length < len) {
- vh.buffer2 = new char[len];
- }
- builder.getChars(0, len, vh.buffer2, 0);
- vh.line2.setText(vh.buffer2, 0, len);
-
- // Update the checkbox of the item, based on which the user last
- // selected. Note that doing it this way means we must have the
- // list view update all of its items when the selected item
- // changes.
- final long id = cursor.getLong(mIdIdx);
- vh.radio.setChecked(id == mSelectedId);
- if (DBG)
- Log.v(TAG,
- "Binding id=" + id + " sel=" + mSelectedId + " playing=" + mPlayingId
- + " cursor=" + cursor);
-
- // Likewise, display the "now playing" icon if this item is
- // currently being previewed for the user.
- ImageView iv = vh.play_indicator;
- if (id == mPlayingId) {
- iv.setImageResource(R.drawable.indicator_ic_mp_playing_list);
- iv.setVisibility(View.VISIBLE);
- } else {
- iv.setVisibility(View.GONE);
- }
- }
-
- /**
- * This method is called whenever we receive a new cursor due to
- * an async query, and must take care of plugging the new one in
- * to the adapter.
- */
- @Override
- public void changeCursor(Cursor cursor) {
- super.changeCursor(cursor);
- if (DBG)
- Log.v(TAG, "Setting cursor to: " + cursor + " from: " + MusicPicker.this.mCursor);
-
- MusicPicker.this.mCursor = cursor;
-
- if (cursor != null) {
- // Retrieve indices of the various columns we are interested in.
- mIdIdx = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
- mTitleIdx = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
- mArtistIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST);
- mAlbumIdx = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM);
- mDurationIdx = cursor.getColumnIndex(MediaStore.Audio.Media.DURATION);
-
- // 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(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);
- }
- }
-
- // Ensure that the list is shown (and initial progress indicator
- // hidden) in case this is the first cursor we have gotten.
- makeListShown();
- }
-
- /**
- * This method is called from a background thread by the list view
- * when the user has typed a letter that should result in a filtering
- * of the displayed items. It returns a Cursor, when will then be
- * handed to changeCursor.
- */
- @Override
- public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
- if (DBG) Log.v(TAG, "Getting new cursor...");
- return doQuery(true, constraint.toString());
- }
-
- public int getPositionForSection(int section) {
- Cursor cursor = getCursor();
- if (cursor == null) {
- // No cursor, the section doesn't exist so just return 0
- return 0;
- }
-
- return mIndexer.getPositionForSection(section);
- }
-
- public int getSectionForPosition(int position) {
- return 0;
- }
-
- public Object[] getSections() {
- if (mIndexer != null) {
- return mIndexer.getSections();
- }
- return null;
- }
- }
-
- /**
- * This is our specialization of AsyncQueryHandler applies new cursors
- * to our state as they become available.
- */
- private final class QueryHandler extends AsyncQueryHandler {
- public QueryHandler(Context context) {
- super(context.getContentResolver());
- }
-
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- if (!isFinishing()) {
- // Update the adapter: we are no longer loading, and have
- // a new cursor for it.
- mAdapter.setLoading(false);
- mAdapter.changeCursor(cursor);
- setProgressBarIndeterminateVisibility(false);
-
- // Now that the cursor is populated again, it's possible to restore the list state
- if (mListState != null) {
- getListView().onRestoreInstanceState(mListState);
- if (mListHasFocus) {
- getListView().requestFocus();
- }
- mListHasFocus = false;
- mListState = null;
- }
- } else {
- cursor.close();
- }
- }
- }
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
- int sortMode = TRACK_MENU;
- if (icicle == null) {
- mSelectedUri =
- getIntent().getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
- } else {
- mSelectedUri = (Uri) icicle.getParcelable(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI);
- // Retrieve list state. This will be applied after the
- // QueryHandler has run
- mListState = icicle.getParcelable(LIST_STATE_KEY);
- mListHasFocus = icicle.getBoolean(FOCUS_KEY);
- sortMode = icicle.getInt(SORT_MODE_KEY, sortMode);
- }
- if (Intent.ACTION_GET_CONTENT.equals(getIntent().getAction())) {
- mBaseUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- } else {
- mBaseUri = getIntent().getData();
- if (mBaseUri == null) {
- Log.w("MusicPicker", "No data URI given to PICK action");
- finish();
- return;
- }
- }
-
- setContentView(R.layout.music_picker);
-
- mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
-
- final ListView listView = getListView();
-
- listView.setItemsCanFocus(false);
-
- mAdapter = new TrackListAdapter(
- this, listView, R.layout.music_picker_item, new String[] {}, new int[] {});
-
- setListAdapter(mAdapter);
-
- listView.setTextFilterEnabled(true);
-
- // We manually save/restore the listview state
- listView.setSaveEnabled(false);
-
- mQueryHandler = new QueryHandler(this);
-
- mProgressContainer = findViewById(R.id.progressContainer);
- mListContainer = findViewById(R.id.listContainer);
-
- mOkayButton = findViewById(R.id.okayButton);
- mOkayButton.setOnClickListener(this);
- mCancelButton = findViewById(R.id.cancelButton);
- mCancelButton.setOnClickListener(this);
-
- // If there is a currently selected Uri, then try to determine who
- // it is.
- if (mSelectedUri != null) {
- Uri.Builder builder = mSelectedUri.buildUpon();
- String path = mSelectedUri.getEncodedPath();
- int idx = path.lastIndexOf('/');
- if (idx >= 0) {
- path = path.substring(0, idx);
- }
- builder.encodedPath(path);
- Uri baseSelectedUri = builder.build();
- if (DBG) Log.v(TAG, "Selected Uri: " + mSelectedUri);
- if (DBG) Log.v(TAG, "Selected base Uri: " + baseSelectedUri);
- if (DBG) Log.v(TAG, "Base Uri: " + mBaseUri);
- if (baseSelectedUri.equals(mBaseUri)) {
- // If the base Uri of the selected Uri is the same as our
- // content's base Uri, then use the selection!
- mSelectedId = ContentUris.parseId(mSelectedUri);
- }
- }
-
- setSortMode(sortMode);
- }
-
- @Override
- public void onRestart() {
- super.onRestart();
- doQuery(false, null);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (setSortMode(item.getItemId())) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
- menu.add(Menu.NONE, TRACK_MENU, Menu.NONE, R.string.sort_by_track);
- menu.add(Menu.NONE, ALBUM_MENU, Menu.NONE, R.string.sort_by_album);
- menu.add(Menu.NONE, ARTIST_MENU, Menu.NONE, R.string.sort_by_artist);
- return true;
- }
-
- @Override
- protected void onSaveInstanceState(Bundle icicle) {
- super.onSaveInstanceState(icicle);
- // Save list state in the bundle so we can restore it after the
- // QueryHandler has run
- icicle.putParcelable(LIST_STATE_KEY, getListView().onSaveInstanceState());
- icicle.putBoolean(FOCUS_KEY, getListView().hasFocus());
- icicle.putInt(SORT_MODE_KEY, mSortMode);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- stopMediaPlayer();
- }
-
- @Override
- public void onStop() {
- super.onStop();
-
- // We don't want the list to display the empty state, since when we
- // resume it will still be there and show up while the new query is
- // happening. After the async query finishes in response to onResume()
- // setLoading(false) will be called.
- mAdapter.setLoading(true);
- mAdapter.changeCursor(null);
- }
-
- /**
- * Changes the current sort order, building the appropriate query string
- * for the selected order.
- */
- boolean setSortMode(int sortMode) {
- if (sortMode != mSortMode) {
- switch (sortMode) {
- case TRACK_MENU:
- mSortMode = sortMode;
- mSortOrder = MediaStore.Audio.Media.TITLE_KEY;
- doQuery(false, null);
- return true;
- case ALBUM_MENU:
- mSortMode = sortMode;
- mSortOrder = MediaStore.Audio.Media.ALBUM_KEY + " ASC, "
- + MediaStore.Audio.Media.TRACK + " ASC, "
- + MediaStore.Audio.Media.TITLE_KEY + " ASC";
- doQuery(false, null);
- return true;
- case ARTIST_MENU:
- mSortMode = sortMode;
- mSortOrder = MediaStore.Audio.Media.ARTIST_KEY + " ASC, "
- + MediaStore.Audio.Media.ALBUM_KEY + " ASC, "
- + MediaStore.Audio.Media.TRACK + " ASC, "
- + MediaStore.Audio.Media.TITLE_KEY + " ASC";
- doQuery(false, null);
- return true;
- }
- }
- return false;
- }
-
- /**
- * The first time this is called, we hide the large progress indicator
- * and show the list view, doing fade animations between them.
- */
- void makeListShown() {
- if (!mListShown) {
- mListShown = true;
- mProgressContainer.startAnimation(
- AnimationUtils.loadAnimation(this, android.R.anim.fade_out));
- mProgressContainer.setVisibility(View.GONE);
- mListContainer.startAnimation(
- AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
- mListContainer.setVisibility(View.VISIBLE);
- }
- }
-
- /**
- * Common method for performing a query of the music database, called for
- * both top-level queries and filtering.
- *
- * @param sync If true, this query should be done synchronously and the
- * resulting cursor returned. If false, it will be done asynchronously and
- * null returned.
- * @param filterstring If non-null, this is a filter to apply to the query.
- */
- Cursor doQuery(boolean sync, String filterstring) {
- // Cancel any pending queries
- mQueryHandler.cancelOperation(MY_QUERY_TOKEN);
-
- StringBuilder where = new StringBuilder();
- where.append(MediaStore.Audio.Media.TITLE + " != ''");
-
- // We want to show all audio files, even recordings. Enforcing the
- // following condition would hide recordings.
- // where.append(" AND " + MediaStore.Audio.Media.IS_MUSIC + "=1");
-
- Uri uri = mBaseUri;
- if (!TextUtils.isEmpty(filterstring)) {
- uri = uri.buildUpon().appendQueryParameter("filter", Uri.encode(filterstring)).build();
- }
-
- if (sync) {
- try {
- return getContentResolver().query(
- uri, CURSOR_COLS, where.toString(), null, mSortOrder);
- } catch (UnsupportedOperationException ex) {
- }
- } else {
- mAdapter.setLoading(true);
- setProgressBarIndeterminateVisibility(true);
- mQueryHandler.startQuery(
- MY_QUERY_TOKEN, null, uri, CURSOR_COLS, where.toString(), null, mSortOrder);
- }
- return null;
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- mCursor.moveToPosition(position);
- if (DBG)
- Log.v(TAG,
- "Click on " + position + " (id=" + id + ", cursid="
- + mCursor.getLong(mCursor.getColumnIndex(MediaStore.Audio.Media._ID))
- + ") in cursor " + mCursor + " adapter=" + l.getAdapter());
- setSelected(mCursor);
- }
-
- void setSelected(Cursor c) {
- Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- long newId = mCursor.getLong(mCursor.getColumnIndex(MediaStore.Audio.Media._ID));
- mSelectedUri = ContentUris.withAppendedId(uri, newId);
-
- mSelectedId = newId;
- if (newId != mPlayingId || mMediaPlayer == null) {
- stopMediaPlayer();
- mMediaPlayer = new MediaPlayer();
- try {
- mMediaPlayer.setDataSource(this, mSelectedUri);
- mMediaPlayer.setOnCompletionListener(this);
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_RING);
- mMediaPlayer.prepare();
- mMediaPlayer.start();
- mPlayingId = newId;
- getListView().invalidateViews();
- } catch (IOException e) {
- Log.w("MusicPicker", "Unable to play track", e);
- }
- } else if (mMediaPlayer != null) {
- stopMediaPlayer();
- getListView().invalidateViews();
- }
- }
-
- public void onCompletion(MediaPlayer mp) {
- if (mMediaPlayer == mp) {
- mp.stop();
- mp.release();
- mMediaPlayer = null;
- mPlayingId = -1;
- getListView().invalidateViews();
- }
- }
-
- void stopMediaPlayer() {
- if (mMediaPlayer != null) {
- mMediaPlayer.stop();
- mMediaPlayer.release();
- mMediaPlayer = null;
- mPlayingId = -1;
- }
- }
-
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.okayButton:
- if (mSelectedId >= 0) {
- setResult(RESULT_OK, new Intent().setData(mSelectedUri));
- finish();
- }
- break;
-
- case R.id.cancelButton:
- finish();
- break;
- }
- }
-} \ No newline at end of file
diff --git a/src/com/android/music/MusicUtils.java b/src/com/android/music/MusicUtils.java
deleted file mode 100644
index a8a93e1..0000000
--- a/src/com/android/music/MusicUtils.java
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.net.Uri;
-import android.provider.MediaStore;
-import android.view.View;
-import android.widget.TabWidget;
-import android.widget.TextView;
-import com.android.music.utils.LogHelper;
-import com.android.music.utils.MusicProvider;
-
-import java.util.Formatter;
-import java.util.Iterator;
-import java.util.Locale;
-
-/*
-Static methods useful for activities
- */
-public class MusicUtils {
- private static final String TAG = LogHelper.makeLogTag(MusicUtils.class);
-
- public static final String TAG_MEDIA_ID = "__MEDIA_ID";
- public static final String TAG_PARENT_ITEM = "__PARENT_ITEM";
- public static final String TAG_WITH_TABS = "__WITH_TABS";
-
- // A really simple BitmapDrawable-like class, that doesn't do
- // scaling, dithering or filtering.
- private static class FastBitmapDrawable extends Drawable {
- private Bitmap mBitmap;
- public FastBitmapDrawable(Bitmap b) {
- mBitmap = b;
- }
- @Override
- public void draw(Canvas canvas) {
- canvas.drawBitmap(mBitmap, 0, 0, null);
- }
- @Override
- public int getOpacity() {
- return PixelFormat.OPAQUE;
- }
- @Override
- public void setAlpha(int alpha) {}
- @Override
- public void setColorFilter(ColorFilter cf) {}
- }
-
- public static Bitmap resizeBitmap(Bitmap bitmap, Bitmap ref) {
- int w = ref.getWidth();
- int h = ref.getHeight();
- return Bitmap.createScaledBitmap(bitmap, w, h, false);
- }
-
- public static Drawable getDrawableBitmap(Bitmap bitmap, BitmapDrawable defaultArtwork) {
- final Bitmap icon = defaultArtwork.getBitmap();
- int w = icon.getWidth();
- int h = icon.getHeight();
- bitmap = Bitmap.createScaledBitmap(bitmap, w, h, false);
- return new FastBitmapDrawable(bitmap);
- }
-
- public static String makeAlbumsLabel(
- Context context, int numalbums, int numsongs, boolean isUnknown) {
- // There are two formats for the albums/songs information:
- // "N Song(s)" - used for unknown artist/album
- // "N Album(s)" - used for known albums
-
- StringBuilder songs_albums = new StringBuilder();
-
- Resources r = context.getResources();
- if (isUnknown) {
- if (numsongs == 1) {
- songs_albums.append(context.getString(R.string.onesong));
- } else {
- String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
- sFormatBuilder.setLength(0);
- sFormatter.format(f, Integer.valueOf(numsongs));
- songs_albums.append(sFormatBuilder);
- }
- } else {
- String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
- sFormatBuilder.setLength(0);
- sFormatter.format(f, Integer.valueOf(numalbums));
- songs_albums.append(sFormatBuilder);
- songs_albums.append(context.getString(R.string.albumsongseparator));
- }
- return songs_albums.toString();
- }
-
- /**
- * This is now only used for the query screen
- */
- public static String makeAlbumsSongsLabel(
- Context context, int numalbums, int numsongs, boolean isUnknown) {
- // There are several formats for the albums/songs information:
- // "1 Song" - used if there is only 1 song
- // "N Songs" - used for the "unknown artist" item
- // "1 Album"/"N Songs"
- // "N Album"/"M Songs"
- // Depending on locale, these may need to be further subdivided
-
- StringBuilder songs_albums = new StringBuilder();
-
- if (numsongs == 1) {
- songs_albums.append(context.getString(R.string.onesong));
- } else {
- Resources r = context.getResources();
- if (!isUnknown) {
- String f = r.getQuantityText(R.plurals.Nalbums, numalbums).toString();
- sFormatBuilder.setLength(0);
- sFormatter.format(f, Integer.valueOf(numalbums));
- songs_albums.append(sFormatBuilder);
- songs_albums.append(context.getString(R.string.albumsongseparator));
- }
- String f = r.getQuantityText(R.plurals.Nsongs, numsongs).toString();
- sFormatBuilder.setLength(0);
- sFormatter.format(f, Integer.valueOf(numsongs));
- songs_albums.append(sFormatBuilder);
- }
- return songs_albums.toString();
- }
-
- /* Try to use String.format() as little as possible, because it creates a
- * new Formatter every time you call it, which is very inefficient.
- * Reusing an existing Formatter more than tripled the speed of
- * makeTimeString().
- * This Formatter/StringBuilder are also used by makeAlbumSongsLabel()
- */
- private static StringBuilder sFormatBuilder = new StringBuilder();
- private static Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
- private static final Object[] sTimeArgs = new Object[5];
-
- public static String makeTimeString(Context context, long secs) {
- String durationformat = context.getString(
- secs < 3600 ? R.string.durationformatshort : R.string.durationformatlong);
-
- /* Provide multiple arguments so the format can be changed easily
- * by modifying the xml.
- */
- sFormatBuilder.setLength(0);
-
- final Object[] timeArgs = sTimeArgs;
- timeArgs[0] = secs / 3600;
- timeArgs[1] = secs / 60;
- timeArgs[2] = (secs / 60) % 60;
- timeArgs[3] = secs;
- timeArgs[4] = secs % 60;
-
- return sFormatter.format(durationformat, timeArgs).toString();
- }
-
- static int getIntPref(Context context, String name, int def) {
- SharedPreferences prefs =
- context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
- return prefs.getInt(name, def);
- }
-
- static void setIntPref(Context context, String name, int value) {
- SharedPreferences prefs =
- context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
- Editor ed = prefs.edit();
- ed.putInt(name, value);
- SharedPreferencesCompat.apply(ed);
- }
-
- static int sActiveTabIndex = -1;
-
- static boolean updateButtonBar(Activity a, int highlight) {
- final TabWidget ll = (TabWidget) a.findViewById(R.id.buttonbar);
- boolean withtabs = false;
- Intent intent = a.getIntent();
- if (intent != null) {
- withtabs = intent.getBooleanExtra(MusicUtils.TAG_WITH_TABS, false);
- }
-
- if (highlight == 0 || !withtabs) {
- ll.setVisibility(View.GONE);
- return withtabs;
- } else if (withtabs) {
- ll.setVisibility(View.VISIBLE);
- }
- for (int i = ll.getChildCount() - 1; i >= 0; i--) {
- View v = ll.getChildAt(i);
- boolean isActive = (v.getId() == highlight);
- if (isActive) {
- ll.setCurrentTab(i);
- sActiveTabIndex = i;
- }
- v.setTag(i);
- v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- for (int i = 0; i < ll.getTabCount(); i++) {
- if (ll.getChildTabViewAt(i) == v) {
- ll.setCurrentTab(i);
- processTabClick((Activity) ll.getContext(), v,
- ll.getChildAt(sActiveTabIndex).getId());
- break;
- }
- }
- }
- }
- });
-
- v.setOnClickListener(new View.OnClickListener() {
-
- public void onClick(View v) {
- processTabClick(
- (Activity) ll.getContext(), v, ll.getChildAt(sActiveTabIndex).getId());
- }
- });
- }
- return withtabs;
- }
-
- static void processTabClick(Activity a, View v, int current) {
- int id = v.getId();
- if (id == current) {
- return;
- }
-
- final TabWidget ll = (TabWidget) a.findViewById(R.id.buttonbar);
-
- activateTab(a, id);
- if (id != R.id.nowplayingtab) {
- ll.setCurrentTab((Integer) v.getTag());
- setIntPref(a, "activetab", id);
- }
- }
-
- static void activateTab(Activity a, int id) {
- Intent intent = new Intent(Intent.ACTION_PICK);
- switch (id) {
- case R.id.artisttab:
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/artistalbum");
- break;
- case R.id.albumtab:
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/album");
- break;
- case R.id.songtab:
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
- break;
- case R.id.playlisttab:
- intent.setDataAndType(Uri.EMPTY, MediaStore.Audio.Playlists.CONTENT_TYPE);
- break;
- case R.id.nowplayingtab:
- intent = new Intent(a, MediaPlaybackActivity.class);
- a.startActivity(intent);
- // fall through and return
- default:
- return;
- }
- intent.putExtra(MusicUtils.TAG_WITH_TABS, true);
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- a.startActivity(intent);
- a.finish();
- a.overridePendingTransition(0, 0);
- }
-
- static void updateNowPlaying(Activity a) {
- View nowPlayingView = a.findViewById(R.id.nowplaying);
- if (nowPlayingView == null) {
- return;
- }
- MediaController controller = a.getMediaController();
- if (controller != null) {
- MediaMetadata metadata = controller.getMetadata();
- if (metadata != null) {
- TextView title = (TextView) nowPlayingView.findViewById(R.id.title);
- TextView artist = (TextView) nowPlayingView.findViewById(R.id.artist);
- title.setText(metadata.getString(MediaMetadata.METADATA_KEY_TITLE));
- String artistName = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- if (MusicProvider.UNKOWN.equals(artistName)) {
- artistName = a.getString(R.string.unknown_artist_name);
- }
- artist.setText(artistName);
- nowPlayingView.setVisibility(View.VISIBLE);
- nowPlayingView.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Context c = v.getContext();
- c.startActivity(new Intent(c, MediaPlaybackActivity.class));
- }
- });
- return;
- }
- }
- nowPlayingView.setVisibility(View.GONE);
- }
-}
diff --git a/src/com/android/music/PlaylistBrowserActivity.java b/src/com/android/music/PlaylistBrowserActivity.java
deleted file mode 100644
index fccee6d..0000000
--- a/src/com/android/music/PlaylistBrowserActivity.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.Activity;
-import android.app.ListActivity;
-import android.content.*;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.database.MergeCursor;
-import android.database.sqlite.SQLiteException;
-import android.media.AudioManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.MediaStore;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.*;
-import com.android.music.utils.LogHelper;
-import com.android.music.utils.MediaIDHelper;
-
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.List;
-
-public class PlaylistBrowserActivity
- extends ListActivity implements View.OnCreateContextMenuListener {
- private static final String TAG = LogHelper.makeLogTag(PlaylistBrowserActivity.class);
- private PlaylistListAdapter mAdapter;
- boolean mAdapterSent;
- private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM = new MediaBrowser.MediaItem(
- new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST)
- .setTitle("Playlists")
- .build(),
- MediaBrowser.MediaItem.FLAG_BROWSABLE);
-
- private MediaBrowser mMediaBrowser;
- private MediaBrowser.MediaItem mParentItem;
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- LogHelper.d(TAG, "onCreate()");
- // Process past states
- Intent intent = getIntent();
- if (icicle != null) {
- LogHelper.d(TAG, "Launch by saved instance state");
- mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
- MusicUtils.updateNowPlaying(this);
- } else if (intent != null) {
- LogHelper.d(TAG, "Launch by intent");
- mParentItem = intent.getExtras().getParcelable(MusicUtils.TAG_PARENT_ITEM);
- }
- if (mParentItem == null) {
- LogHelper.d(TAG, "Launch by default parameters");
- mParentItem = DEFAULT_PARENT_ITEM;
- }
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- setTitle(R.string.playlists_title);
- setContentView(R.layout.media_picker_activity);
- MusicUtils.updateButtonBar(this, R.id.playlisttab);
- ListView lv = getListView();
- lv.setOnCreateContextMenuListener(this);
- lv.setTextFilterEnabled(true);
-
- mAdapter = (PlaylistListAdapter) getLastNonConfigurationInstance();
- if (mAdapter == null) {
- // Log.i("@@@", "starting query");
- mAdapter = new PlaylistListAdapter(this, R.layout.track_list_item);
- setTitle(R.string.working_playlists);
- } else {
- mAdapter.setActivity(this);
- }
- setListAdapter(mAdapter);
- Log.d(TAG, "Creating MediaBrowser");
- mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
- mConnectionCallback, null);
- }
-
- @Override
- public Object onRetainNonConfigurationInstance() {
- PlaylistListAdapter a = mAdapter;
- mAdapterSent = true;
- return a;
- }
-
- @Override
- public void onDestroy() {
- setListAdapter(null);
- mAdapter = null;
- super.onDestroy();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- }
-
- @Override
- public void onStart() {
- Log.d(TAG, "onStart()");
- super.onStart();
- mMediaBrowser.connect();
- }
-
- @Override
- public void onStop() {
- Log.d(TAG, "onStop()");
- super.onStop();
- mMediaBrowser.disconnect();
- }
-
- private MediaBrowser.SubscriptionCallback mSubscriptionCallback =
- new MediaBrowser.SubscriptionCallback() {
-
- @Override
- public void onChildrenLoaded(
- String parentId, List<MediaBrowser.MediaItem> children) {
- mAdapter.clear();
- mAdapter.notifyDataSetInvalidated();
- for (MediaBrowser.MediaItem item : children) {
- mAdapter.add(item);
- }
- mAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onError(String id) {
- Toast.makeText(getApplicationContext(), R.string.error_loading_media,
- Toast.LENGTH_LONG)
- .show();
- }
- };
-
- private MediaBrowser.ConnectionCallback mConnectionCallback =
- new MediaBrowser.ConnectionCallback() {
- @Override
- public void onConnected() {
- Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
- mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
- if (mMediaBrowser.getSessionToken() == null) {
- throw new IllegalArgumentException("No Session token");
- }
- MediaController mediaController = new MediaController(
- PlaylistBrowserActivity.this, mMediaBrowser.getSessionToken());
- mediaController.registerCallback(mMediaControllerCallback);
- PlaylistBrowserActivity.this.setMediaController(mediaController);
- if (mediaController.getMetadata() != null) {
- MusicUtils.updateNowPlaying(PlaylistBrowserActivity.this);
- }
- }
-
- @Override
- public void onConnectionFailed() {
- Log.d(TAG, "onConnectionFailed");
- }
-
- @Override
- public void onConnectionSuspended() {
- Log.d(TAG, "onConnectionSuspended");
- PlaylistBrowserActivity.this.setMediaController(null);
- }
- };
-
- private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- super.onMetadataChanged(metadata);
- MusicUtils.updateNowPlaying(PlaylistBrowserActivity.this);
- }
- };
-
- private class PlaylistListAdapter extends ArrayAdapter<MediaBrowser.MediaItem> {
- private int mLayoutId;
- private Activity mActivity;
-
- PlaylistListAdapter(PlaylistBrowserActivity currentactivity, int layout) {
- super(currentactivity, layout);
- mActivity = currentactivity;
- mLayoutId = layout;
- }
-
- private class ViewHolder {
- TextView line1;
- TextView line2;
- ImageView icon;
- ImageView play_indicator;
- }
-
- public void setActivity(PlaylistBrowserActivity newactivity) {
- mActivity = newactivity;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false);
- ViewHolder vhx = new ViewHolder();
- vhx.line1 = (TextView) convertView.findViewById(R.id.line1);
- vhx.line2 = (TextView) convertView.findViewById(R.id.line2);
- vhx.icon = (ImageView) convertView.findViewById(R.id.icon);
- vhx.play_indicator = (ImageView) convertView.findViewById(R.id.play_indicator);
- convertView.setTag(vhx);
- }
- ViewHolder vh = (ViewHolder) convertView.getTag();
- MediaBrowser.MediaItem item = getItem(position);
- vh.line1.setText(item.getDescription().getTitle());
- vh.line2.setVisibility(View.GONE);
- vh.play_indicator.setVisibility(View.GONE);
- vh.icon.setImageResource(R.drawable.ic_mp_playlist_list);
- ViewGroup.LayoutParams p = vh.icon.getLayoutParams();
- p.width = ViewGroup.LayoutParams.WRAP_CONTENT;
- p.height = ViewGroup.LayoutParams.WRAP_CONTENT;
- return convertView;
- }
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- MediaBrowser.MediaItem item = mAdapter.getItem(position);
- Intent intent = new Intent(Intent.ACTION_PICK);
- intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track");
- intent.putExtra(MusicUtils.TAG_PARENT_ITEM, item);
- startActivity(intent);
- }
-}
diff --git a/src/com/android/music/RepeatingImageButton.java b/src/com/android/music/RepeatingImageButton.java
deleted file mode 100644
index 7dc5a65..0000000
--- a/src/com/android/music/RepeatingImageButton.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageButton;
-
-/**
- * A button that will repeatedly call a 'listener' method
- * as long as the button is pressed.
- */
-public class RepeatingImageButton extends ImageButton {
- private long mStartTime;
- private int mRepeatCount;
- private RepeatListener mListener;
- private long mInterval = 500;
-
- public RepeatingImageButton(Context context) {
- this(context, null);
- }
-
- public RepeatingImageButton(Context context, AttributeSet attrs) {
- this(context, attrs, android.R.attr.imageButtonStyle);
- }
-
- public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- setFocusable(true);
- setLongClickable(true);
- }
-
- /**
- * Sets the listener to be called while the button is pressed and
- * the interval in milliseconds with which it will be called.
- * @param l The listener that will be called
- * @param interval The interval in milliseconds for calls
- */
- public void setRepeatListener(RepeatListener l, long interval) {
- mListener = l;
- mInterval = interval;
- }
-
- @Override
- public boolean performLongClick() {
- mStartTime = SystemClock.elapsedRealtime();
- mRepeatCount = 0;
- post(mRepeater);
- return true;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_UP) {
- // remove the repeater, but call the hook one more time
- removeCallbacks(mRepeater);
- if (mStartTime != 0) {
- doRepeat(true);
- mStartTime = 0;
- }
- }
- return super.onTouchEvent(event);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- // need to call super to make long press work, but return
- // true so that the application doesn't get the down event.
- super.onKeyDown(keyCode, event);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- // remove the repeater, but call the hook one more time
- removeCallbacks(mRepeater);
- if (mStartTime != 0) {
- doRepeat(true);
- mStartTime = 0;
- }
- }
- return super.onKeyUp(keyCode, event);
- }
-
- private Runnable mRepeater = new Runnable() {
- public void run() {
- doRepeat(false);
- if (isPressed()) {
- postDelayed(this, mInterval);
- }
- }
- };
-
- private void doRepeat(boolean last) {
- long now = SystemClock.elapsedRealtime();
- if (mListener != null) {
- mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++);
- }
- }
-
- public interface RepeatListener {
- /**
- * This method will be called repeatedly at roughly the interval
- * specified in setRepeatListener(), for as long as the button
- * is pressed.
- * @param v The button as a View.
- * @param duration The number of milliseconds the button has been pressed so far.
- * @param repeatcount The number of previous calls in this sequence.
- * If this is going to be the last call in this sequence (i.e. the user
- * just stopped pressing the button), the value will be -1.
- */
- void onRepeat(View v, long duration, int repeatcount);
- }
-}
diff --git a/src/com/android/music/SharedPreferencesCompat.java b/src/com/android/music/SharedPreferencesCompat.java
deleted file mode 100644
index 92780a6..0000000
--- a/src/com/android/music/SharedPreferencesCompat.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.content.SharedPreferences;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * Reflection utils to call SharedPreferences$Editor.apply when possible,
- * falling back to commit when apply isn't available.
- */
-public class SharedPreferencesCompat {
- private static final Method sApplyMethod = findApplyMethod();
-
- private static Method findApplyMethod() {
- try {
- Class cls = SharedPreferences.Editor.class;
- return cls.getMethod("apply");
- } catch (NoSuchMethodException unused) {
- // fall through
- }
- return null;
- }
-
- public static void apply(SharedPreferences.Editor editor) {
- if (sApplyMethod != null) {
- try {
- sApplyMethod.invoke(editor);
- return;
- } catch (InvocationTargetException unused) {
- // fall through
- } catch (IllegalAccessException unused) {
- // fall through
- }
- }
- editor.commit();
- }
-}
diff --git a/src/com/android/music/TouchInterceptor.java b/src/com/android/music/TouchInterceptor.java
deleted file mode 100644
index eee7c87..0000000
--- a/src/com/android/music/TouchInterceptor.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LevelListDrawable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.GestureDetector.SimpleOnGestureListener;
-import android.widget.AdapterView;
-import android.widget.ImageView;
-import android.widget.ListView;
-
-public class TouchInterceptor extends ListView {
- private ImageView mDragView;
- private WindowManager mWindowManager;
- private WindowManager.LayoutParams mWindowParams;
- /**
- * At which position is the item currently being dragged. Note that this
- * takes in to account header items.
- */
- private int mDragPos;
- /**
- * At which position was the item being dragged originally
- */
- private int mSrcDragPos;
- private int mDragPointX; // at what x offset inside the item did the user grab it
- private int mDragPointY; // at what y offset inside the item did the user grab it
- private int mXOffset; // the difference between screen coordinates and coordinates in this view
- private int mYOffset; // the difference between screen coordinates and coordinates in this view
- private DragListener mDragListener;
- private DropListener mDropListener;
- private RemoveListener mRemoveListener;
- private int mUpperBound;
- private int mLowerBound;
- private int mHeight;
- private GestureDetector mGestureDetector;
- private static final int FLING = 0;
- private static final int SLIDE = 1;
- private static final int TRASH = 2;
- private int mRemoveMode = -1;
- private Rect mTempRect = new Rect();
- private Bitmap mDragBitmap;
- private final int mTouchSlop;
- private int mItemHeightNormal;
- private int mItemHeightExpanded;
- private int mItemHeightHalf;
- private Drawable mTrashcan;
-
- public TouchInterceptor(Context context, AttributeSet attrs) {
- super(context, attrs);
- SharedPreferences pref = context.getSharedPreferences("Music", 0);
- mRemoveMode = pref.getInt("deletemode", -1);
- mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- Resources res = getResources();
- mItemHeightNormal = res.getDimensionPixelSize(R.dimen.normal_height);
- mItemHeightHalf = mItemHeightNormal / 2;
- mItemHeightExpanded = res.getDimensionPixelSize(R.dimen.expanded_height);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (mRemoveListener != null && mGestureDetector == null) {
- if (mRemoveMode == FLING) {
- mGestureDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
- @Override
- public boolean onFling(
- MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- if (mDragView != null) {
- if (velocityX > 1000) {
- Rect r = mTempRect;
- mDragView.getDrawingRect(r);
- if (e2.getX() > r.right * 2 / 3) {
- // fast fling right with release near the right edge of the
- // screen
- stopDragging();
- mRemoveListener.remove(mSrcDragPos);
- unExpandViews(true);
- }
- }
- // flinging while dragging should have no effect
- return true;
- }
- return false;
- }
- });
- }
- }
- if (mDragListener != null || mDropListener != null) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- int x = (int) ev.getX();
- int y = (int) ev.getY();
- int itemnum = pointToPosition(x, y);
- if (itemnum == AdapterView.INVALID_POSITION) {
- break;
- }
- ViewGroup item = (ViewGroup) getChildAt(itemnum - getFirstVisiblePosition());
- mDragPointX = x - item.getLeft();
- mDragPointY = y - item.getTop();
- mXOffset = ((int) ev.getRawX()) - x;
- mYOffset = ((int) ev.getRawY()) - y;
- // The left side of the item is the grabber for dragging the item
- if (x < 64) {
- item.setDrawingCacheEnabled(true);
- // Create a copy of the drawing cache so that it does not get recycled
- // by the framework when the list tries to clean up memory
- Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());
- startDragging(bitmap, x, y);
- mDragPos = itemnum;
- mSrcDragPos = mDragPos;
- mHeight = getHeight();
- int touchSlop = mTouchSlop;
- mUpperBound = Math.min(y - touchSlop, mHeight / 3);
- mLowerBound = Math.max(y + touchSlop, mHeight * 2 / 3);
- return false;
- }
- stopDragging();
- break;
- }
- }
- return super.onInterceptTouchEvent(ev);
- }
-
- /*
- * pointToPosition() doesn't consider invisible views, but we
- * need to, so implement a slightly different version.
- */
- private int myPointToPosition(int x, int y) {
- if (y < 0) {
- // when dragging off the top of the screen, calculate position
- // by going back from a visible item
- int pos = myPointToPosition(x, y + mItemHeightNormal);
- if (pos > 0) {
- return pos - 1;
- }
- }
-
- Rect frame = mTempRect;
- final int count = getChildCount();
- for (int i = count - 1; i >= 0; i--) {
- final View child = getChildAt(i);
- child.getHitRect(frame);
- if (frame.contains(x, y)) {
- return getFirstVisiblePosition() + i;
- }
- }
- return INVALID_POSITION;
- }
-
- private int getItemForPosition(int y) {
- int adjustedy = y - mDragPointY - mItemHeightHalf;
- int pos = myPointToPosition(0, adjustedy);
- if (pos >= 0) {
- if (pos <= mSrcDragPos) {
- pos += 1;
- }
- } else if (adjustedy < 0) {
- // this shouldn't happen anymore now that myPointToPosition deals
- // with this situation
- pos = 0;
- }
- return pos;
- }
-
- private void adjustScrollBounds(int y) {
- if (y >= mHeight / 3) {
- mUpperBound = mHeight / 3;
- }
- if (y <= mHeight * 2 / 3) {
- mLowerBound = mHeight * 2 / 3;
- }
- }
-
- /*
- * Restore size and visibility for all listitems
- */
- private void unExpandViews(boolean deletion) {
- for (int i = 0;; i++) {
- View v = getChildAt(i);
- if (v == null) {
- if (deletion) {
- // HACK force update of mItemCount
- int position = getFirstVisiblePosition();
- int y = getChildAt(0).getTop();
- setAdapter(getAdapter());
- setSelectionFromTop(position, y);
- // end hack
- }
- try {
- layoutChildren(); // force children to be recreated where needed
- v = getChildAt(i);
- } catch (IllegalStateException ex) {
- // layoutChildren throws this sometimes, presumably because we're
- // in the process of being torn down but are still getting touch
- // events
- }
- if (v == null) {
- return;
- }
- }
- ViewGroup.LayoutParams params = v.getLayoutParams();
- params.height = mItemHeightNormal;
- v.setLayoutParams(params);
- v.setVisibility(View.VISIBLE);
- }
- }
-
- /* Adjust visibility and size to make it appear as though
- * an item is being dragged around and other items are making
- * room for it:
- * If dropping the item would result in it still being in the
- * same place, then make the dragged listitem's size normal,
- * but make the item invisible.
- * Otherwise, if the dragged listitem is still on screen, make
- * it as small as possible and expand the item below the insert
- * point.
- * If the dragged item is not on screen, only expand the item
- * below the current insertpoint.
- */
- private void doExpansion() {
- int childnum = mDragPos - getFirstVisiblePosition();
- if (mDragPos > mSrcDragPos) {
- childnum++;
- }
- int numheaders = getHeaderViewsCount();
-
- View first = getChildAt(mSrcDragPos - getFirstVisiblePosition());
- for (int i = 0;; i++) {
- View vv = getChildAt(i);
- if (vv == null) {
- break;
- }
-
- int height = mItemHeightNormal;
- int visibility = View.VISIBLE;
- if (mDragPos < numheaders && i == numheaders) {
- // dragging on top of the header item, so adjust the item below
- // instead
- if (vv.equals(first)) {
- visibility = View.INVISIBLE;
- } else {
- height = mItemHeightExpanded;
- }
- } else if (vv.equals(first)) {
- // processing the item that is being dragged
- if (mDragPos == mSrcDragPos || getPositionForView(vv) == getCount() - 1) {
- // hovering over the original location
- visibility = View.INVISIBLE;
- } else {
- // not hovering over it
- // Ideally the item would be completely gone, but neither
- // setting its size to 0 nor settings visibility to GONE
- // has the desired effect.
- height = 1;
- }
- } else if (i == childnum) {
- if (mDragPos >= numheaders && mDragPos < getCount() - 1) {
- height = mItemHeightExpanded;
- }
- }
- ViewGroup.LayoutParams params = vv.getLayoutParams();
- params.height = height;
- vv.setLayoutParams(params);
- vv.setVisibility(visibility);
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- if (mGestureDetector != null) {
- mGestureDetector.onTouchEvent(ev);
- }
- if ((mDragListener != null || mDropListener != null) && mDragView != null) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- Rect r = mTempRect;
- mDragView.getDrawingRect(r);
- stopDragging();
- if (mRemoveMode == SLIDE && ev.getX() > r.right * 3 / 4) {
- if (mRemoveListener != null) {
- mRemoveListener.remove(mSrcDragPos);
- }
- unExpandViews(true);
- } else {
- if (mDropListener != null && mDragPos >= 0 && mDragPos < getCount()) {
- mDropListener.drop(mSrcDragPos, mDragPos);
- }
- unExpandViews(false);
- }
- break;
-
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- int x = (int) ev.getX();
- int y = (int) ev.getY();
- dragView(x, y);
- int itemnum = getItemForPosition(y);
- if (itemnum >= 0) {
- if (action == MotionEvent.ACTION_DOWN || itemnum != mDragPos) {
- if (mDragListener != null) {
- mDragListener.drag(mDragPos, itemnum);
- }
- mDragPos = itemnum;
- doExpansion();
- }
- int speed = 0;
- adjustScrollBounds(y);
- if (y > mLowerBound) {
- // scroll the list up a bit
- if (getLastVisiblePosition() < getCount() - 1) {
- speed = y > (mHeight + mLowerBound) / 2 ? 16 : 4;
- } else {
- speed = 1;
- }
- } else if (y < mUpperBound) {
- // scroll the list down a bit
- speed = y < mUpperBound / 2 ? -16 : -4;
- if (getFirstVisiblePosition() == 0
- && getChildAt(0).getTop() >= getPaddingTop()) {
- // if we're already at the top, don't try to scroll, because
- // it causes the framework to do some extra drawing that messes
- // up our animation
- speed = 0;
- }
- }
- if (speed != 0) {
- smoothScrollBy(speed, 30);
- }
- }
- break;
- }
- return true;
- }
- return super.onTouchEvent(ev);
- }
-
- private void startDragging(Bitmap bm, int x, int y) {
- stopDragging();
-
- mWindowParams = new WindowManager.LayoutParams();
- mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;
- mWindowParams.x = x - mDragPointX + mXOffset;
- mWindowParams.y = y - mDragPointY + mYOffset;
-
- mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
- mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
- mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
- mWindowParams.format = PixelFormat.TRANSLUCENT;
- mWindowParams.windowAnimations = 0;
-
- Context context = getContext();
- ImageView v = new ImageView(context);
- // int backGroundColor = context.getResources().getColor(R.color.dragndrop_background);
- // v.setBackgroundColor(backGroundColor);
- v.setBackgroundResource(R.drawable.playlist_tile_drag);
- v.setPadding(0, 0, 0, 0);
- v.setImageBitmap(bm);
- mDragBitmap = bm;
-
- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mWindowManager.addView(v, mWindowParams);
- mDragView = v;
- }
-
- private void dragView(int x, int y) {
- if (mRemoveMode == SLIDE) {
- float alpha = 1.0f;
- int width = mDragView.getWidth();
- if (x > width / 2) {
- alpha = ((float) (width - x)) / (width / 2);
- }
- mWindowParams.alpha = alpha;
- }
-
- if (mRemoveMode == FLING || mRemoveMode == TRASH) {
- mWindowParams.x = x - mDragPointX + mXOffset;
- } else {
- mWindowParams.x = 0;
- }
- mWindowParams.y = y - mDragPointY + mYOffset;
- mWindowManager.updateViewLayout(mDragView, mWindowParams);
-
- if (mTrashcan != null) {
- int width = mDragView.getWidth();
- if (y > getHeight() * 3 / 4) {
- mTrashcan.setLevel(2);
- } else if (width > 0 && x > width / 4) {
- mTrashcan.setLevel(1);
- } else {
- mTrashcan.setLevel(0);
- }
- }
- }
-
- private void stopDragging() {
- if (mDragView != null) {
- mDragView.setVisibility(GONE);
- WindowManager wm =
- (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
- wm.removeView(mDragView);
- mDragView.setImageDrawable(null);
- mDragView = null;
- }
- if (mDragBitmap != null) {
- mDragBitmap.recycle();
- mDragBitmap = null;
- }
- if (mTrashcan != null) {
- mTrashcan.setLevel(0);
- }
- }
-
- public void setTrashcan(Drawable trash) {
- mTrashcan = trash;
- mRemoveMode = TRASH;
- }
-
- public void setDragListener(DragListener l) {
- mDragListener = l;
- }
-
- public void setDropListener(DropListener l) {
- mDropListener = l;
- }
-
- public void setRemoveListener(RemoveListener l) {
- mRemoveListener = l;
- }
-
- public interface DragListener { void drag(int from, int to); }
- public interface DropListener { void drop(int from, int to); }
- public interface RemoveListener { void remove(int which); }
-}
diff --git a/src/com/android/music/TrackBrowserActivity.java b/src/com/android/music/TrackBrowserActivity.java
deleted file mode 100644
index 7fb41b4..0000000
--- a/src/com/android/music/TrackBrowserActivity.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.app.Activity;
-import android.app.ListActivity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.graphics.drawable.Drawable;
-import android.media.AudioManager;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.*;
-import com.android.music.utils.LogHelper;
-import com.android.music.utils.MediaIDHelper;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/*
-This activity shows when there is a need for
- 1. Songs tab [withtab = true]
- 2. Browse songs within an album [withtab = false]
- 3. Browse songs within a playlist [withtab = false]
- 4. Browse songs within now playing queue [withtab = false]
- */
-public class TrackBrowserActivity extends ListActivity {
- private static final String TAG = LogHelper.makeLogTag(TrackBrowserActivity.class);
- private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM =
- new MediaBrowser.MediaItem(new MediaDescription.Builder()
- .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_SONG)
- .setTitle("Songs")
- .build(),
- MediaBrowser.MediaItem.FLAG_BROWSABLE);
-
- // Underlining ListView of this Activity
- private ListView mTrackList;
- // The mediaId to be used for subscribing for children using the MediaBrowser.
- private MediaBrowser.MediaItem mParentItem;
- private MediaBrowser mMediaBrowser;
- private TrackBrowseAdapter mBrowseListAdapter;
- private boolean mWithTabs;
-
- /**
- * Called when the activity is first created.
- */
- @Override
- public void onCreate(Bundle icicle) {
- Log.d(TAG, "onCreate()");
- super.onCreate(icicle);
- // Process past states
- Intent intent = getIntent();
- if (icicle != null) {
- LogHelper.d(TAG, "Launch by saved instance state");
- mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
- mWithTabs = icicle.getBoolean(MusicUtils.TAG_WITH_TABS);
- MusicUtils.updateNowPlaying(this);
- } else if (intent != null) {
- LogHelper.d(TAG, "Launch by intent");
- mParentItem = intent.getParcelableExtra(MusicUtils.TAG_PARENT_ITEM);
- mWithTabs = intent.getBooleanExtra(MusicUtils.TAG_WITH_TABS, false);
- }
- if (mParentItem == null) {
- LogHelper.d(TAG, "Launch by default parameters");
- mParentItem = DEFAULT_PARENT_ITEM;
- mWithTabs = true;
- }
- if (mWithTabs) {
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- }
- setTitle(mParentItem.getDescription().getTitle());
- setVolumeControlStream(AudioManager.STREAM_MUSIC);
-
- // Init layout
- LogHelper.d(TAG, "init layout");
- setContentView(R.layout.media_picker_activity);
- MusicUtils.updateButtonBar(this, R.id.songtab);
-
- // Init the ListView
- Log.d(TAG, "Creating ListView");
- mTrackList = getListView();
- mTrackList.setCacheColorHint(0);
- mTrackList.setTextFilterEnabled(true);
- mBrowseListAdapter = (TrackBrowseAdapter) getLastNonConfigurationInstance();
- if (mBrowseListAdapter == null) {
- mBrowseListAdapter = new TrackBrowseAdapter(this, R.layout.track_list_item);
- }
- setListAdapter(mBrowseListAdapter);
- // don't set the album art until after the view has been layed out
- mTrackList.post(new Runnable() {
- public void run() {
- mTrackList.setBackgroundColor(Color.WHITE);
- mTrackList.setCacheColorHint(0);
- }
- });
-
- // Create media browser
- Log.d(TAG, "Creating MediaBrowser");
- mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
- mConnectionCallback, null);
- }
-
- @Override
- public void onStart() {
- Log.d(TAG, "onStart()");
- super.onStart();
- mMediaBrowser.connect();
- }
-
- @Override
- public void onStop() {
- Log.d(TAG, "onStop()");
- super.onStop();
- mMediaBrowser.disconnect();
- }
-
- @Override
- public void onDestroy() {
- Log.d(TAG, "onDestroy()");
- ListView lv = getListView();
- // Because we pass the adapter to the next activity, we need to make
- // sure it doesn't keep a reference to this activity. We can do this
- // by clearing its DatasetObservers, which setListAdapter(null) does.
- setListAdapter(null);
- mBrowseListAdapter = null;
- super.onDestroy();
- }
-
- @Override
- public void onResume() {
- Log.d(TAG, "onResume()");
- super.onResume();
- }
-
- @Override
- public void onPause() {
- Log.d(TAG, "onPause()");
- super.onPause();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outcicle) {
- outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
- outcicle.putBoolean(MusicUtils.TAG_WITH_TABS, mWithTabs);
- super.onSaveInstanceState(outcicle);
- }
-
- private MediaBrowser.SubscriptionCallback mSubscriptionCallback =
- new MediaBrowser.SubscriptionCallback() {
-
- @Override
- public void onChildrenLoaded(
- String parentId, List<MediaBrowser.MediaItem> children) {
- mBrowseListAdapter.clear();
- mBrowseListAdapter.notifyDataSetInvalidated();
- for (MediaBrowser.MediaItem item : children) {
- mBrowseListAdapter.add(item);
- }
- mBrowseListAdapter.notifyDataSetChanged();
- }
-
- @Override
- public void onError(String id) {
- Toast.makeText(getApplicationContext(), R.string.error_loading_media,
- Toast.LENGTH_LONG)
- .show();
- }
- };
-
- private MediaBrowser.ConnectionCallback mConnectionCallback =
- new MediaBrowser.ConnectionCallback() {
- @Override
- public void onConnected() {
- Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
- mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
- if (mMediaBrowser.getSessionToken() == null) {
- throw new IllegalArgumentException("No Session token");
- }
- MediaController mediaController = new MediaController(
- TrackBrowserActivity.this, mMediaBrowser.getSessionToken());
- mediaController.registerCallback(mMediaControllerCallback);
- TrackBrowserActivity.this.setMediaController(mediaController);
- if (mediaController.getMetadata() != null && mWithTabs) {
- MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
- }
- }
-
- @Override
- public void onConnectionFailed() {
- Log.d(TAG, "onConnectionFailed");
- }
-
- @Override
- public void onConnectionSuspended() {
- Log.d(TAG, "onConnectionSuspended");
- TrackBrowserActivity.this.setMediaController(null);
- }
- };
-
- private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- super.onMetadataChanged(metadata);
- if (mWithTabs) {
- MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
- }
- if (mBrowseListAdapter != null) {
- mBrowseListAdapter.notifyDataSetChanged();
- }
- }
- };
-
- // An adapter for showing the list of browsed MediaItem's
- private static class TrackBrowseAdapter extends ArrayAdapter<MediaBrowser.MediaItem> {
- private int mLayoutId;
- private final Drawable mNowPlayingOverlay;
- private Activity mActivity;
-
- static class ViewHolder {
- TextView line1;
- TextView line2;
- TextView duration;
- ImageView play_indicator;
- }
-
- TrackBrowseAdapter(Activity activity, int layout) {
- super(activity, layout, new ArrayList<>());
- mLayoutId = layout;
- mNowPlayingOverlay = activity.getResources().getDrawable(
- R.drawable.indicator_ic_mp_playing_list, activity.getTheme());
- mActivity = activity;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Log.d(TAG, "getView()");
- if (convertView == null) {
- convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false);
- ImageView iv = (ImageView) convertView.findViewById(R.id.icon);
- iv.setVisibility(View.GONE);
- ViewHolder vh = new ViewHolder();
- vh.line1 = (TextView) convertView.findViewById(R.id.line1);
- vh.line2 = (TextView) convertView.findViewById(R.id.line2);
- vh.duration = (TextView) convertView.findViewById(R.id.duration);
- vh.play_indicator = (ImageView) convertView.findViewById(R.id.play_indicator);
- convertView.setTag(vh);
- }
- ViewHolder holder = (ViewHolder) convertView.getTag();
- MediaBrowser.MediaItem item = getItem(position);
- Log.d(TAG, "title: " + item.getDescription().getTitle());
- holder.line1.setText(item.getDescription().getTitle());
- Log.d(TAG, "artist: " + item.getDescription().getSubtitle());
- holder.line2.setText(item.getDescription().getSubtitle());
- long duration =
- item.getDescription().getExtras().getLong(MediaMetadata.METADATA_KEY_DURATION);
- LogHelper.d(TAG, "duration: ", duration);
- holder.duration.setText(MusicUtils.makeTimeString(getContext(), duration / 1000));
- MediaController mediaController = mActivity.getMediaController();
- if (mediaController == null) {
- holder.play_indicator.setImageDrawable(null);
- return convertView;
- }
- MediaMetadata metadata = mediaController.getMetadata();
- if (metadata == null) {
- holder.play_indicator.setImageDrawable(null);
- return convertView;
- }
- if (item.getDescription().getMediaId().endsWith(
- metadata.getString(MediaMetadata.METADATA_KEY_MEDIA_ID))) {
- holder.play_indicator.setImageDrawable(mNowPlayingOverlay);
- } else {
- holder.play_indicator.setImageDrawable(null);
- }
- return convertView;
- }
- }
-
- @Override
- public Object onRetainNonConfigurationInstance() {
- TrackBrowseAdapter a = mBrowseListAdapter;
- return a;
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- Log.d(TAG, "onListItemClick at position " + position + ", id " + id);
- MediaBrowser.MediaItem item = mBrowseListAdapter.getItem(position);
- if (item.isPlayable()) {
- getMediaController().getTransportControls().playFromMediaId(item.getMediaId(), null);
- }
- }
-}
diff --git a/src/com/android/music/VerticalTextSpinner.java b/src/com/android/music/VerticalTextSpinner.java
deleted file mode 100644
index c2d896b..0000000
--- a/src/com/android/music/VerticalTextSpinner.java
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.NinePatchDrawable;
-import android.text.TextPaint;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-
-public class VerticalTextSpinner extends View {
- private static final int SELECTOR_ARROW_HEIGHT = 15;
-
- private static int TEXT_SPACING;
- private static int TEXT_MARGIN_RIGHT;
- private static int TEXT_SIZE;
- private static int TEXT1_Y;
- private static int TEXT2_Y;
- private static int TEXT3_Y;
- private static int TEXT4_Y;
- private static int TEXT5_Y;
- private static int SCROLL_DISTANCE;
-
- private static final int SCROLL_MODE_NONE = 0;
- private static final int SCROLL_MODE_UP = 1;
- private static final int SCROLL_MODE_DOWN = 2;
-
- private static final long DEFAULT_SCROLL_INTERVAL_MS = 400;
- private static final int MIN_ANIMATIONS = 4;
-
- private final Drawable mBackgroundFocused;
- private final Drawable mSelectorFocused;
- private final Drawable mSelectorNormal;
- private final int mSelectorDefaultY;
- private final int mSelectorMinY;
- private final int mSelectorMaxY;
- private final int mSelectorHeight;
- private final TextPaint mTextPaintDark;
- private final TextPaint mTextPaintLight;
-
- private int mSelectorY;
- private Drawable mSelector;
- private int mDownY;
- private boolean isDraggingSelector;
- private int mScrollMode;
- private long mScrollInterval;
- private boolean mIsAnimationRunning;
- private boolean mStopAnimation;
- private boolean mWrapAround = true;
-
- private int mTotalAnimatedDistance;
- private int mNumberOfAnimations;
- private long mDelayBetweenAnimations;
- private int mDistanceOfEachAnimation;
-
- private String[] mTextList;
- private int mCurrentSelectedPos;
- private OnChangedListener mListener;
-
- private String mText1;
- private String mText2;
- private String mText3;
- private String mText4;
- private String mText5;
-
- public interface OnChangedListener {
- void onChanged(VerticalTextSpinner spinner, int oldPos, int newPos, String[] items);
- }
-
- public VerticalTextSpinner(Context context) {
- this(context, null);
- }
-
- public VerticalTextSpinner(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public VerticalTextSpinner(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- float scale = getResources().getDisplayMetrics().density;
- TEXT_SPACING = (int) (18 * scale);
- TEXT_MARGIN_RIGHT = (int) (25 * scale);
- TEXT_SIZE = (int) (22 * scale);
- SCROLL_DISTANCE = TEXT_SIZE + TEXT_SPACING;
- TEXT1_Y = (TEXT_SIZE * (-2 + 2)) + (TEXT_SPACING * (-2 + 1));
- TEXT2_Y = (TEXT_SIZE * (-1 + 2)) + (TEXT_SPACING * (-1 + 1));
- TEXT3_Y = (TEXT_SIZE * (0 + 2)) + (TEXT_SPACING * (0 + 1));
- TEXT4_Y = (TEXT_SIZE * (1 + 2)) + (TEXT_SPACING * (1 + 1));
- TEXT5_Y = (TEXT_SIZE * (2 + 2)) + (TEXT_SPACING * (2 + 1));
-
- mBackgroundFocused = context.getResources().getDrawable(R.drawable.pickerbox_background);
- mSelectorFocused = context.getResources().getDrawable(R.drawable.pickerbox_selected);
- mSelectorNormal = context.getResources().getDrawable(R.drawable.pickerbox_unselected);
-
- mSelectorHeight = mSelectorFocused.getIntrinsicHeight();
- mSelectorDefaultY = (mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight) / 2;
- mSelectorMinY = 0;
- mSelectorMaxY = mBackgroundFocused.getIntrinsicHeight() - mSelectorHeight;
-
- mSelector = mSelectorNormal;
- mSelectorY = mSelectorDefaultY;
-
- mTextPaintDark = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaintDark.setTextSize(TEXT_SIZE);
- mTextPaintDark.setColor(
- context.getResources().getColor(android.R.color.primary_text_light));
-
- mTextPaintLight = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaintLight.setTextSize(TEXT_SIZE);
- mTextPaintLight.setColor(
- context.getResources().getColor(android.R.color.secondary_text_dark));
-
- mScrollMode = SCROLL_MODE_NONE;
- mScrollInterval = DEFAULT_SCROLL_INTERVAL_MS;
- calculateAnimationValues();
- }
-
- public void setOnChangeListener(OnChangedListener listener) {
- mListener = listener;
- }
-
- public void setItems(String[] textList) {
- mTextList = textList;
- calculateTextPositions();
- }
-
- public void setSelectedPos(int selectedPos) {
- mCurrentSelectedPos = selectedPos;
- calculateTextPositions();
- postInvalidate();
- }
-
- public void setScrollInterval(long interval) {
- mScrollInterval = interval;
- calculateAnimationValues();
- }
-
- public void setWrapAround(boolean wrap) {
- mWrapAround = wrap;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- /* This is a bit confusing, when we get the key event
- * DPAD_DOWN we actually roll the spinner up. When the
- * key event is DPAD_UP we roll the spinner down.
- */
- if ((keyCode == KeyEvent.KEYCODE_DPAD_UP) && canScrollDown()) {
- mScrollMode = SCROLL_MODE_DOWN;
- scroll();
- mStopAnimation = true;
- return true;
- } else if ((keyCode == KeyEvent.KEYCODE_DPAD_DOWN) && canScrollUp()) {
- mScrollMode = SCROLL_MODE_UP;
- scroll();
- mStopAnimation = true;
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
-
- private boolean canScrollDown() {
- return (mCurrentSelectedPos > 0) || mWrapAround;
- }
-
- private boolean canScrollUp() {
- return ((mCurrentSelectedPos < (mTextList.length - 1)) || mWrapAround);
- }
-
- @Override
- protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
- if (gainFocus) {
- setBackgroundDrawable(mBackgroundFocused);
- mSelector = mSelectorFocused;
- } else {
- setBackgroundDrawable(null);
- mSelector = mSelectorNormal;
- mSelectorY = mSelectorDefaultY;
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- final int action = event.getAction();
- final int y = (int) event.getY();
-
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- requestFocus();
- mDownY = y;
- isDraggingSelector =
- (y >= mSelectorY) && (y <= (mSelectorY + mSelector.getIntrinsicHeight()));
- break;
-
- case MotionEvent.ACTION_MOVE:
- if (isDraggingSelector) {
- int top = mSelectorDefaultY + (y - mDownY);
- if (top <= mSelectorMinY && canScrollDown()) {
- mSelectorY = mSelectorMinY;
- mStopAnimation = false;
- if (mScrollMode != SCROLL_MODE_DOWN) {
- mScrollMode = SCROLL_MODE_DOWN;
- scroll();
- }
- } else if (top >= mSelectorMaxY && canScrollUp()) {
- mSelectorY = mSelectorMaxY;
- mStopAnimation = false;
- if (mScrollMode != SCROLL_MODE_UP) {
- mScrollMode = SCROLL_MODE_UP;
- scroll();
- }
- } else {
- mSelectorY = top;
- mStopAnimation = true;
- }
- }
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- default:
- mSelectorY = mSelectorDefaultY;
- mStopAnimation = true;
- invalidate();
- break;
- }
- return true;
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- /* The bounds of the selector */
- final int selectorLeft = 0;
- final int selectorTop = mSelectorY;
- final int selectorRight = getWidth();
- final int selectorBottom = mSelectorY + mSelectorHeight;
-
- /* Draw the selector */
- mSelector.setBounds(selectorLeft, selectorTop, selectorRight, selectorBottom);
- mSelector.draw(canvas);
-
- if (mTextList == null) {
- /* We're not setup with values so don't draw anything else */
- return;
- }
-
- final TextPaint textPaintDark = mTextPaintDark;
- if (hasFocus()) {
- /* The bounds of the top area where the text should be light */
- final int topLeft = 0;
- final int topTop = 0;
- final int topRight = selectorRight;
- final int topBottom = selectorTop + SELECTOR_ARROW_HEIGHT;
-
- /* Assign a bunch of local finals for performance */
- final String text1 = mText1;
- final String text2 = mText2;
- final String text3 = mText3;
- final String text4 = mText4;
- final String text5 = mText5;
- final TextPaint textPaintLight = mTextPaintLight;
-
- /*
- * Draw the 1st, 2nd and 3rd item in light only, clip it so it only
- * draws in the area above the selector
- */
- canvas.save();
- canvas.clipRect(topLeft, topTop, topRight, topBottom);
- drawText(canvas, text1, TEXT1_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text2, TEXT2_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text3, TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
- canvas.restore();
-
- /*
- * Draw the 2nd, 3rd and 4th clipped to the selector bounds in dark
- * paint
- */
- canvas.save();
- canvas.clipRect(selectorLeft, selectorTop + SELECTOR_ARROW_HEIGHT, selectorRight,
- selectorBottom - SELECTOR_ARROW_HEIGHT);
- drawText(canvas, text2, TEXT2_Y + mTotalAnimatedDistance, textPaintDark);
- drawText(canvas, text3, TEXT3_Y + mTotalAnimatedDistance, textPaintDark);
- drawText(canvas, text4, TEXT4_Y + mTotalAnimatedDistance, textPaintDark);
- canvas.restore();
-
- /* The bounds of the bottom area where the text should be light */
- final int bottomLeft = 0;
- final int bottomTop = selectorBottom - SELECTOR_ARROW_HEIGHT;
- final int bottomRight = selectorRight;
- final int bottomBottom = getMeasuredHeight();
-
- /*
- * Draw the 3rd, 4th and 5th in white text, clip it so it only draws
- * in the area below the selector.
- */
- canvas.save();
- canvas.clipRect(bottomLeft, bottomTop, bottomRight, bottomBottom);
- drawText(canvas, text3, TEXT3_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text4, TEXT4_Y + mTotalAnimatedDistance, textPaintLight);
- drawText(canvas, text5, TEXT5_Y + mTotalAnimatedDistance, textPaintLight);
- canvas.restore();
-
- } else {
- drawText(canvas, mText3, TEXT3_Y, textPaintDark);
- }
- if (mIsAnimationRunning) {
- if ((Math.abs(mTotalAnimatedDistance) + mDistanceOfEachAnimation) > SCROLL_DISTANCE) {
- mTotalAnimatedDistance = 0;
- if (mScrollMode == SCROLL_MODE_UP) {
- int oldPos = mCurrentSelectedPos;
- int newPos = getNewIndex(1);
- if (newPos >= 0) {
- mCurrentSelectedPos = newPos;
- if (mListener != null) {
- mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
- }
- }
- if (newPos < 0 || ((newPos >= mTextList.length - 1) && !mWrapAround)) {
- mStopAnimation = true;
- }
- calculateTextPositions();
- } else if (mScrollMode == SCROLL_MODE_DOWN) {
- int oldPos = mCurrentSelectedPos;
- int newPos = getNewIndex(-1);
- if (newPos >= 0) {
- mCurrentSelectedPos = newPos;
- if (mListener != null) {
- mListener.onChanged(this, oldPos, mCurrentSelectedPos, mTextList);
- }
- }
- if (newPos < 0 || (newPos == 0 && !mWrapAround)) {
- mStopAnimation = true;
- }
- calculateTextPositions();
- }
- if (mStopAnimation) {
- final int previousScrollMode = mScrollMode;
-
- /* No longer scrolling, we wait till the current animation
- * completes then we stop.
- */
- mIsAnimationRunning = false;
- mStopAnimation = false;
- mScrollMode = SCROLL_MODE_NONE;
-
- /* If the current selected item is an empty string
- * scroll past it.
- */
- if ("".equals(mTextList[mCurrentSelectedPos])) {
- mScrollMode = previousScrollMode;
- scroll();
- mStopAnimation = true;
- }
- }
- } else {
- if (mScrollMode == SCROLL_MODE_UP) {
- mTotalAnimatedDistance -= mDistanceOfEachAnimation;
- } else if (mScrollMode == SCROLL_MODE_DOWN) {
- mTotalAnimatedDistance += mDistanceOfEachAnimation;
- }
- }
- if (mDelayBetweenAnimations > 0) {
- postInvalidateDelayed(mDelayBetweenAnimations);
- } else {
- invalidate();
- }
- }
- }
-
- /**
- * Called every time the text items or current position
- * changes. We calculate store we don't have to calculate
- * onDraw.
- */
- private void calculateTextPositions() {
- mText1 = getTextToDraw(-2);
- mText2 = getTextToDraw(-1);
- mText3 = getTextToDraw(0);
- mText4 = getTextToDraw(1);
- mText5 = getTextToDraw(2);
- }
-
- private String getTextToDraw(int offset) {
- int index = getNewIndex(offset);
- if (index < 0) {
- return "";
- }
- return mTextList[index];
- }
-
- private int getNewIndex(int offset) {
- int index = mCurrentSelectedPos + offset;
- if (index < 0) {
- if (mWrapAround) {
- index += mTextList.length;
- } else {
- return -1;
- }
- } else if (index >= mTextList.length) {
- if (mWrapAround) {
- index -= mTextList.length;
- } else {
- return -1;
- }
- }
- return index;
- }
-
- private void scroll() {
- if (mIsAnimationRunning) {
- return;
- }
- mTotalAnimatedDistance = 0;
- mIsAnimationRunning = true;
- invalidate();
- }
-
- private void calculateAnimationValues() {
- mNumberOfAnimations = (int) mScrollInterval / SCROLL_DISTANCE;
- if (mNumberOfAnimations < MIN_ANIMATIONS) {
- mNumberOfAnimations = MIN_ANIMATIONS;
- mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
- mDelayBetweenAnimations = 0;
- } else {
- mDistanceOfEachAnimation = SCROLL_DISTANCE / mNumberOfAnimations;
- mDelayBetweenAnimations = mScrollInterval / mNumberOfAnimations;
- }
- }
-
- private void drawText(Canvas canvas, String text, int y, TextPaint paint) {
- int width = (int) paint.measureText(text);
- int x = getMeasuredWidth() - width - TEXT_MARGIN_RIGHT;
- canvas.drawText(text, x, y, paint);
- }
-
- public int getCurrentSelectedPos() {
- return mCurrentSelectedPos;
- }
-}
diff --git a/src/com/android/music/utils/AlbumArtCache.java b/src/com/android/music/utils/AlbumArtCache.java
deleted file mode 100644
index 7021021..0000000
--- a/src/com/android/music/utils/AlbumArtCache.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import android.graphics.Bitmap;
-import android.os.AsyncTask;
-import android.util.LruCache;
-
-import java.io.IOException;
-
-/**
- * Implements a basic cache of album arts, with async loading support.
- */
-public final class AlbumArtCache {
- private static final String TAG = LogHelper.makeLogTag(AlbumArtCache.class);
-
- private static final int MAX_ALBUM_ART_CACHE_SIZE = 12 * 1024 * 1024; // 12 MB
- private static final int MAX_ART_WIDTH = 800; // pixels
- private static final int MAX_ART_HEIGHT = 480; // pixels
-
- // Resolution reasonable for carrying around as an icon (generally in
- // MediaDescription.getIconBitmap). This should not be bigger than necessary, because
- // the MediaDescription object should be lightweight. If you set it too high and try to
- // serialize the MediaDescription, you may get FAILED BINDER TRANSACTION errors.
- private static final int MAX_ART_WIDTH_ICON = 128; // pixels
- private static final int MAX_ART_HEIGHT_ICON = 128; // pixels
-
- private static final int BIG_BITMAP_INDEX = 0;
- private static final int ICON_BITMAP_INDEX = 1;
-
- private final LruCache<String, Bitmap[]> mCache;
-
- private static final AlbumArtCache sInstance = new AlbumArtCache();
-
- public static AlbumArtCache getInstance() {
- return sInstance;
- }
-
- private AlbumArtCache() {
- // Holds no more than MAX_ALBUM_ART_CACHE_SIZE bytes, bounded by maxmemory/4 and
- // Integer.MAX_VALUE:
- int maxSize = Math.min(MAX_ALBUM_ART_CACHE_SIZE,
- (int) (Math.min(Integer.MAX_VALUE, Runtime.getRuntime().maxMemory() / 4)));
- mCache = new LruCache<String, Bitmap[]>(maxSize) {
- @Override
- protected int sizeOf(String key, Bitmap[] value) {
- return value[BIG_BITMAP_INDEX].getByteCount()
- + value[ICON_BITMAP_INDEX].getByteCount();
- }
- };
- }
-
- public Bitmap getBigImage(String artUrl) {
- Bitmap[] result = mCache.get(artUrl);
- return result == null ? null : result[BIG_BITMAP_INDEX];
- }
-
- public Bitmap getIconImage(String artUrl) {
- Bitmap[] result = mCache.get(artUrl);
- return result == null ? null : result[ICON_BITMAP_INDEX];
- }
-
- public void fetch(final String artUrl, final FetchListener listener) {
- // WARNING: for the sake of simplicity, simultaneous multi-thread fetch requests
- // are not handled properly: they may cause redundant costly operations, like HTTP
- // requests and bitmap rescales. For production-level apps, we recommend you use
- // a proper image loading library, like Glide.
- Bitmap[] bitmap = mCache.get(artUrl);
- if (bitmap != null) {
- LogHelper.d(TAG, "getOrFetch: album art is in cache, using it", artUrl);
- listener.onFetched(artUrl, bitmap[BIG_BITMAP_INDEX], bitmap[ICON_BITMAP_INDEX]);
- return;
- }
- LogHelper.d(TAG, "getOrFetch: starting asynctask to fetch ", artUrl);
-
- new AsyncTask<Void, Void, Bitmap[]>() {
- @Override
- protected Bitmap[] doInBackground(Void[] objects) {
- Bitmap[] bitmaps;
- try {
- Bitmap bitmap = BitmapHelper.fetchAndRescaleBitmap(
- artUrl, MAX_ART_WIDTH, MAX_ART_HEIGHT);
- Bitmap icon = BitmapHelper.scaleBitmap(
- bitmap, MAX_ART_WIDTH_ICON, MAX_ART_HEIGHT_ICON);
- bitmaps = new Bitmap[] {bitmap, icon};
- mCache.put(artUrl, bitmaps);
- } catch (IOException e) {
- return null;
- }
- LogHelper.d(TAG,
- "doInBackground: putting bitmap in cache. cache size=" + mCache.size());
- return bitmaps;
- }
-
- @Override
- protected void onPostExecute(Bitmap[] bitmaps) {
- if (bitmaps == null) {
- listener.onError(artUrl, new IllegalArgumentException("got null bitmaps"));
- } else {
- listener.onFetched(
- artUrl, bitmaps[BIG_BITMAP_INDEX], bitmaps[ICON_BITMAP_INDEX]);
- }
- }
- }
- .execute();
- }
-
- public static abstract class FetchListener {
- public abstract void onFetched(String artUrl, Bitmap bigImage, Bitmap iconImage);
- public void onError(String artUrl, Exception e) {
- LogHelper.e(TAG, e, "AlbumArtFetchListener: error while downloading " + artUrl);
- }
- }
-}
diff --git a/src/com/android/music/utils/BitmapHelper.java b/src/com/android/music/utils/BitmapHelper.java
deleted file mode 100644
index 5746233..0000000
--- a/src/com/android/music/utils/BitmapHelper.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.music.utils;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-
-public class BitmapHelper {
- private static final String TAG = LogHelper.makeLogTag(BitmapHelper.class);
-
- // Max read limit that we allow our input stream to mark/reset.
- private static final int MAX_READ_LIMIT_PER_IMG = 1024 * 1024;
-
- public static Bitmap scaleBitmap(Bitmap src, int maxWidth, int maxHeight) {
- double scaleFactor = Math.min(
- ((double) maxWidth) / src.getWidth(), ((double) maxHeight) / src.getHeight());
- return Bitmap.createScaledBitmap(src, (int) (src.getWidth() * scaleFactor),
- (int) (src.getHeight() * scaleFactor), false);
- }
-
- public static Bitmap scaleBitmap(int scaleFactor, InputStream is) {
- // Get the dimensions of the bitmap
- BitmapFactory.Options bmOptions = new BitmapFactory.Options();
-
- // Decode the image file into a Bitmap sized to fill the View
- bmOptions.inJustDecodeBounds = false;
- bmOptions.inSampleSize = scaleFactor;
-
- return BitmapFactory.decodeStream(is, null, bmOptions);
- }
-
- public static int findScaleFactor(int targetW, int targetH, InputStream is) {
- // Get the dimensions of the bitmap
- BitmapFactory.Options bmOptions = new BitmapFactory.Options();
- bmOptions.inJustDecodeBounds = true;
- BitmapFactory.decodeStream(is, null, bmOptions);
- int actualW = bmOptions.outWidth;
- int actualH = bmOptions.outHeight;
-
- // Determine how much to scale down the image
- return Math.min(actualW / targetW, actualH / targetH);
- }
-
- @SuppressWarnings("SameParameterValue")
- public static Bitmap fetchAndRescaleBitmap(String uri, int width, int height)
- throws IOException {
- URL url = new URL(uri);
- BufferedInputStream is = null;
- try {
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- is = new BufferedInputStream(urlConnection.getInputStream());
- is.mark(MAX_READ_LIMIT_PER_IMG);
- int scaleFactor = findScaleFactor(width, height, is);
- LogHelper.d(TAG, "Scaling bitmap ", uri, " by factor ", scaleFactor, " to support ",
- width, "x", height, "requested dimension");
- is.reset();
- return scaleBitmap(scaleFactor, is);
- } finally {
- if (is != null) {
- is.close();
- }
- }
- }
-}
diff --git a/src/com/android/music/utils/CheckableRelativeLayout.java b/src/com/android/music/utils/CheckableRelativeLayout.java
deleted file mode 100644
index 125fecb..0000000
--- a/src/com/android/music/utils/CheckableRelativeLayout.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.Checkable;
-import android.widget.RelativeLayout;
-
-/**
- * A special variation of RelativeLayout that can be used as a checkable object.
- * This allows it to be used as the top-level view of a list view item, which
- * also supports checking. Otherwise, it works identically to a RelativeLayout.
- */
-public class CheckableRelativeLayout extends RelativeLayout implements Checkable {
- private boolean mChecked;
-
- private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
-
- public CheckableRelativeLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- protected int[] onCreateDrawableState(int extraSpace) {
- final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
- if (isChecked()) {
- mergeDrawableStates(drawableState, CHECKED_STATE_SET);
- }
- return drawableState;
- }
-
- public void toggle() {
- setChecked(!mChecked);
- }
-
- public boolean isChecked() {
- return mChecked;
- }
-
- public void setChecked(boolean checked) {
- if (mChecked != checked) {
- mChecked = checked;
- refreshDrawableState();
- }
- }
-}
diff --git a/src/com/android/music/utils/LogHelper.java b/src/com/android/music/utils/LogHelper.java
deleted file mode 100644
index 3a0d2ee..0000000
--- a/src/com/android/music/utils/LogHelper.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.music.utils;
-
-import android.util.Log;
-
-public class LogHelper {
- private static final String LOG_PREFIX = "music_";
- private static final int LOG_PREFIX_LENGTH = LOG_PREFIX.length();
- private static final int MAX_LOG_TAG_LENGTH = 23;
- private static final boolean DEBUG = true;
-
- public static String makeLogTag(String str) {
- if (str.length() > MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH) {
- return LOG_PREFIX + str.substring(0, MAX_LOG_TAG_LENGTH - LOG_PREFIX_LENGTH - 1);
- }
-
- return LOG_PREFIX + str;
- }
-
- /**
- * Don't use this when obfuscating class names!
- */
- public static String makeLogTag(Class cls) {
- return makeLogTag(cls.getSimpleName());
- }
-
- public static void v(String tag, Object... messages) {
- // Only log VERBOSE if build type is DEBUG
- if (DEBUG) {
- log(tag, Log.VERBOSE, null, messages);
- }
- }
-
- public static void d(String tag, Object... messages) {
- // Only log DEBUG if build type is DEBUG
- if (DEBUG) {
- log(tag, Log.DEBUG, null, messages);
- }
- }
-
- public static void i(String tag, Object... messages) {
- log(tag, Log.INFO, null, messages);
- }
-
- public static void w(String tag, Object... messages) {
- log(tag, Log.WARN, null, messages);
- }
-
- public static void w(String tag, Throwable t, Object... messages) {
- log(tag, Log.WARN, t, messages);
- }
-
- public static void e(String tag, Object... messages) {
- log(tag, Log.ERROR, null, messages);
- }
-
- public static void e(String tag, Throwable t, Object... messages) {
- log(tag, Log.ERROR, t, messages);
- }
-
- public static void log(String tag, int level, Throwable t, Object... messages) {
- String message;
- if (t == null && messages != null && messages.length == 1) {
- // handle this common case without the extra cost of creating a stringbuffer:
- message = messages[0].toString();
- } else {
- StringBuilder sb = new StringBuilder();
- if (messages != null)
- for (Object m : messages) {
- sb.append(m);
- }
- if (t != null) {
- sb.append("\n").append(Log.getStackTraceString(t));
- }
- message = sb.toString();
- }
- Log.println(level, tag, message);
- }
-}
diff --git a/src/com/android/music/utils/MediaIDHelper.java b/src/com/android/music/utils/MediaIDHelper.java
deleted file mode 100644
index e991e4a..0000000
--- a/src/com/android/music/utils/MediaIDHelper.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import java.util.Arrays;
-
-/**
- * Utility class to help on queue related tasks.
- */
-public class MediaIDHelper {
- private static final String TAG = "MediaIDHelper";
-
- // Media IDs used on browseable items of MediaBrowser
- public static final String MEDIA_ID_ROOT = "__ROOT__";
- public static final String MEDIA_ID_MUSICS_BY_ARTIST = "__BY_ARTIST__";
- public static final String MEDIA_ID_MUSICS_BY_ALBUM = "__BY_ALBUM__";
- public static final String MEDIA_ID_MUSICS_BY_SONG = "__BY_SONG__";
- public static final String MEDIA_ID_MUSICS_BY_PLAYLIST = "__BY_PLAYLIST__";
- public static final String MEDIA_ID_MUSICS_BY_SEARCH = "__BY_SEARCH__";
- public static final String MEDIA_ID_NOW_PLAYING = "__NOW_PLAYING__";
-
- private static final char CATEGORY_SEPARATOR = 31;
- private static final char LEAF_SEPARATOR = 30;
-
- public static String createMediaID(String musicID, String... categories) {
- // MediaIDs are of the form <categoryType>/<categoryValue>|<musicUniqueId>, to make it easy
- // to find the category (like genre) that a music was selected from, so we
- // can correctly build the playing queue. This is specially useful when
- // one music can appear in more than one list, like "by genre -> genre_1"
- // and "by artist -> artist_1".
- StringBuilder sb = new StringBuilder();
- if (categories != null && categories.length > 0) {
- sb.append(categories[0]);
- for (int i = 1; i < categories.length; i++) {
- sb.append(CATEGORY_SEPARATOR).append(categories[i]);
- }
- }
- if (musicID != null) {
- sb.append(LEAF_SEPARATOR).append(musicID);
- }
- return sb.toString();
- }
-
- public static String createBrowseCategoryMediaID(String categoryType, String categoryValue) {
- return categoryType + CATEGORY_SEPARATOR + categoryValue;
- }
-
- /**
- * Extracts unique musicID from the mediaID. mediaID is, by this sample's convention, a
- * concatenation of category (eg "by_genre"), categoryValue (eg "Classical") and unique
- * musicID. This is necessary so we know where the user selected the music from, when the music
- * exists in more than one music list, and thus we are able to correctly build the playing
- * queue.
- *
- * @param mediaID that contains the musicID
- * @return musicID
- */
- public static String extractMusicIDFromMediaID(String mediaID) {
- int pos = mediaID.indexOf(LEAF_SEPARATOR);
- if (pos >= 0) {
- return mediaID.substring(pos + 1);
- }
- return null;
- }
-
- /**
- * Extracts category and categoryValue from the mediaID. mediaID is, by this sample's
- * convention, a concatenation of category (eg "by_genre"), categoryValue (eg "Classical") and
- * mediaID. This is necessary so we know where the user selected the music from, when the music
- * exists in more than one music list, and thus we are able to correctly build the playing
- * queue.
- *
- * @param mediaID that contains a category and categoryValue.
- */
- public static String[] getHierarchy(String mediaID) {
- int pos = mediaID.indexOf(LEAF_SEPARATOR);
- if (pos >= 0) {
- mediaID = mediaID.substring(0, pos);
- }
- return mediaID.split(String.valueOf(CATEGORY_SEPARATOR));
- }
-
- public static String extractBrowseCategoryValueFromMediaID(String mediaID) {
- String[] hierarchy = getHierarchy(mediaID);
- if (hierarchy != null && hierarchy.length == 2) {
- return hierarchy[1];
- }
- return null;
- }
-
- private static boolean isBrowseable(String mediaID) {
- return mediaID.indexOf(LEAF_SEPARATOR) < 0;
- }
-
- public static String getParentMediaID(String mediaID) {
- String[] hierarchy = getHierarchy(mediaID);
- if (!isBrowseable(mediaID)) {
- return createMediaID(null, hierarchy);
- }
- if (hierarchy == null || hierarchy.length <= 1) {
- return MEDIA_ID_ROOT;
- }
- String[] parentHierarchy = Arrays.copyOf(hierarchy, hierarchy.length - 1);
- return createMediaID(null, parentHierarchy);
- }
-}
diff --git a/src/com/android/music/utils/MediaNotificationManager.java b/src/com/android/music/utils/MediaNotificationManager.java
deleted file mode 100644
index 65b9797..0000000
--- a/src/com/android/music/utils/MediaNotificationManager.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.media.session.PlaybackState;
-import android.service.media.MediaBrowserService;
-import android.util.Log;
-import com.android.music.MediaPlaybackService;
-import com.android.music.R;
-
-/**
- * Keeps track of a notification and updates it automatically for a given
- * MediaSession. Maintaining a visible notification (usually) guarantees that the music service
- * won't be killed during playback.
- */
-public class MediaNotificationManager extends BroadcastReceiver {
- private static final String TAG = LogHelper.makeLogTag(MediaNotificationManager.class);
-
- private static final int NOTIFICATION_ID = 412;
- private static final int REQUEST_CODE = 100;
-
- public static final String ACTION_PAUSE = "com.android.music.pause";
- public static final String ACTION_PLAY = "com.android.music.play";
- public static final String ACTION_PREV = "com.android.music.prev";
- public static final String ACTION_NEXT = "com.android.music.next";
-
- private final MediaPlaybackService mService;
- private MediaSession.Token mSessionToken;
- private MediaController mController;
- private MediaController.TransportControls mTransportControls;
-
- private PlaybackState mPlaybackState;
- private MediaMetadata mMetadata;
-
- private NotificationManager mNotificationManager;
-
- private PendingIntent mPauseIntent;
- private PendingIntent mPlayIntent;
- private PendingIntent mPreviousIntent;
- private PendingIntent mNextIntent;
-
- private int mNotificationColor;
-
- private boolean mStarted = false;
-
- public MediaNotificationManager(MediaPlaybackService service) {
- mService = service;
- updateSessionToken();
-
- mNotificationColor =
- ResourceHelper.getThemeColor(mService, android.R.attr.colorPrimary, Color.DKGRAY);
-
- mNotificationManager =
- (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
-
- String pkg = mService.getPackageName();
- mPauseIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE,
- new Intent(ACTION_PAUSE).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT);
- mPlayIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE,
- new Intent(ACTION_PLAY).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT);
- mPreviousIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE,
- new Intent(ACTION_PREV).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT);
- mNextIntent = PendingIntent.getBroadcast(mService, REQUEST_CODE,
- new Intent(ACTION_NEXT).setPackage(pkg), PendingIntent.FLAG_CANCEL_CURRENT);
-
- // Cancel all notifications to handle the case where the Service was killed and
- // restarted by the system.
- mNotificationManager.cancelAll();
- }
-
- /**
- * Posts the notification and starts tracking the session to keep it
- * updated. The notification will automatically be removed if the session is
- * destroyed before {@link #stopNotification} is called.
- */
- public void startNotification() {
- if (!mStarted) {
- mMetadata = mController.getMetadata();
- mPlaybackState = mController.getPlaybackState();
-
- // The notification must be updated after setting started to true
- Notification notification = createNotification();
- if (notification != null) {
- mController.registerCallback(mCb);
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_NEXT);
- filter.addAction(ACTION_PAUSE);
- filter.addAction(ACTION_PLAY);
- filter.addAction(ACTION_PREV);
- mService.registerReceiver(this, filter);
-
- mService.startForeground(NOTIFICATION_ID, notification);
- mStarted = true;
- }
- }
- }
-
- /**
- * Removes the notification and stops tracking the session. If the session
- * was destroyed this has no effect.
- */
- public void stopNotification() {
- if (mStarted) {
- mStarted = false;
- mController.unregisterCallback(mCb);
- try {
- mNotificationManager.cancel(NOTIFICATION_ID);
- mService.unregisterReceiver(this);
- } catch (IllegalArgumentException ex) {
- // ignore if the receiver is not registered.
- }
- mService.stopForeground(true);
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- LogHelper.d(TAG, "Received intent with action " + action);
- switch (action) {
- case ACTION_PAUSE:
- mTransportControls.pause();
- break;
- case ACTION_PLAY:
- mTransportControls.play();
- break;
- case ACTION_NEXT:
- mTransportControls.skipToNext();
- break;
- case ACTION_PREV:
- mTransportControls.skipToPrevious();
- break;
- default:
- LogHelper.w(TAG, "Unknown intent ignored. Action=", action);
- }
- }
-
- /**
- * Update the state based on a change on the session token. Called either when
- * we are running for the first time or when the media session owner has destroyed the session
- * (see {@link android.media.session.MediaController.Callback#onSessionDestroyed()})
- */
- private void updateSessionToken() {
- MediaSession.Token freshToken = mService.getSessionToken();
- if (mSessionToken == null || !mSessionToken.equals(freshToken)) {
- if (mController != null) {
- mController.unregisterCallback(mCb);
- }
- mSessionToken = freshToken;
- mController = new MediaController(mService, mSessionToken);
- mTransportControls = mController.getTransportControls();
- if (mStarted) {
- mController.registerCallback(mCb);
- }
- }
- }
-
- private PendingIntent createContentIntent() {
- Intent openUI = new Intent(mService, MediaBrowserService.class);
- openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- return PendingIntent.getActivity(
- mService, REQUEST_CODE, openUI, PendingIntent.FLAG_CANCEL_CURRENT);
- }
-
- private final MediaController.Callback mCb = new MediaController.Callback() {
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- mPlaybackState = state;
- LogHelper.d(TAG, "Received new playback state", state);
- if (state != null
- && (state.getState() == PlaybackState.STATE_STOPPED
- || state.getState() == PlaybackState.STATE_NONE)) {
- stopNotification();
- } else {
- Notification notification = createNotification();
- if (notification != null) {
- mNotificationManager.notify(NOTIFICATION_ID, notification);
- }
- }
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- mMetadata = metadata;
- LogHelper.d(TAG, "Received new metadata ", metadata);
- Notification notification = createNotification();
- if (notification != null) {
- mNotificationManager.notify(NOTIFICATION_ID, notification);
- }
- }
-
- @Override
- public void onSessionDestroyed() {
- super.onSessionDestroyed();
- LogHelper.d(TAG, "Session was destroyed, resetting to the new session token");
- updateSessionToken();
- }
- };
-
- private Notification createNotification() {
- LogHelper.d(TAG, "updateNotificationMetadata. mMetadata=" + mMetadata);
- if (mMetadata == null || mPlaybackState == null) {
- return null;
- }
-
- Notification.Builder notificationBuilder = new Notification.Builder(mService);
- int playPauseButtonPosition = 0;
-
- // If skip to previous action is enabled
- if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
- notificationBuilder.addAction(R.drawable.ic_skip_previous_white_24dp,
- mService.getString(R.string.skip_previous), mPreviousIntent);
-
- // If there is a "skip to previous" button, the play/pause button will
- // be the second one. We need to keep track of it, because the MediaStyle notification
- // requires to specify the index of the buttons (actions) that should be visible
- // when in compact view.
- playPauseButtonPosition = 1;
- }
-
- addPlayPauseAction(notificationBuilder);
-
- // If skip to next action is enabled
- if ((mPlaybackState.getActions() & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
- notificationBuilder.addAction(R.drawable.ic_skip_next_white_24dp,
- mService.getString(R.string.skip_next), mNextIntent);
- }
-
- MediaDescription description = mMetadata.getDescription();
-
- String fetchArtUrl = null;
- Bitmap art = null;
- if (description.getIconUri() != null) {
- // This sample assumes the iconUri will be a valid URL formatted String, but
- // it can actually be any valid Android Uri formatted String.
- // async fetch the album art icon
- String artUrl = description.getIconUri().toString();
- art = AlbumArtCache.getInstance().getBigImage(artUrl);
- if (art == null) {
- fetchArtUrl = artUrl;
- // use a placeholder art while the remote art is being downloaded
- art = BitmapFactory.decodeResource(
- mService.getResources(), R.drawable.ic_default_art);
- }
- }
-
- notificationBuilder
- .setStyle(new Notification.MediaStyle()
- .setShowActionsInCompactView(
- playPauseButtonPosition) // show only play/pause in
- // compact view
- .setMediaSession(mSessionToken))
- .setColor(mNotificationColor)
- .setSmallIcon(R.drawable.ic_notification)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setUsesChronometer(true)
- .setContentIntent(createContentIntent())
- .setContentTitle(description.getTitle())
- .setContentText(description.getSubtitle())
- .setLargeIcon(art);
-
- setNotificationPlaybackState(notificationBuilder);
- if (fetchArtUrl != null) {
- fetchBitmapFromURLAsync(fetchArtUrl, notificationBuilder);
- }
-
- return notificationBuilder.build();
- }
-
- private void addPlayPauseAction(Notification.Builder builder) {
- LogHelper.d(TAG, "updatePlayPauseAction");
- String label;
- int icon;
- PendingIntent intent;
- if (mPlaybackState.getState() == PlaybackState.STATE_PLAYING) {
- label = mService.getString(R.string.play_pause);
- icon = R.drawable.ic_pause_white_24dp;
- intent = mPauseIntent;
- } else {
- label = mService.getString(R.string.play_item);
- icon = R.drawable.ic_play_arrow_white_24dp;
- intent = mPlayIntent;
- }
- builder.addAction(new Notification.Action(icon, label, intent));
- }
-
- private void setNotificationPlaybackState(Notification.Builder builder) {
- LogHelper.d(TAG, "updateNotificationPlaybackState. mPlaybackState=" + mPlaybackState);
- if (mPlaybackState == null || !mStarted) {
- LogHelper.d(TAG, "updateNotificationPlaybackState. cancelling notification!");
- mService.stopForeground(true);
- return;
- }
- if (mPlaybackState.getState() == PlaybackState.STATE_PLAYING
- && mPlaybackState.getPosition() >= 0) {
- LogHelper.d(TAG, "updateNotificationPlaybackState. updating playback position to ",
- (System.currentTimeMillis() - mPlaybackState.getPosition()) / 1000, " seconds");
- builder.setWhen(System.currentTimeMillis() - mPlaybackState.getPosition())
- .setShowWhen(true)
- .setUsesChronometer(true);
- } else {
- LogHelper.d(TAG, "updateNotificationPlaybackState. hiding playback position");
- builder.setWhen(0).setShowWhen(false).setUsesChronometer(false);
- }
-
- // Make sure that the notification can be dismissed by the user when we are not playing:
- builder.setOngoing(mPlaybackState.getState() == PlaybackState.STATE_PLAYING);
- }
-
- private void fetchBitmapFromURLAsync(
- final String bitmapUrl, final Notification.Builder builder) {
- AlbumArtCache.getInstance().fetch(bitmapUrl, new AlbumArtCache.FetchListener() {
- @Override
- public void onFetched(String artUrl, Bitmap bitmap, Bitmap icon) {
- if (mMetadata != null && mMetadata.getDescription() != null
- && artUrl.equals(mMetadata.getDescription().getIconUri().toString())) {
- // If the media is still the same, update the notification:
- LogHelper.d(TAG, "fetchBitmapFromURLAsync: set bitmap to ", artUrl);
- builder.setLargeIcon(bitmap);
- mNotificationManager.notify(NOTIFICATION_ID, builder.build());
- }
- }
- });
- }
-}
diff --git a/src/com/android/music/utils/MusicProvider.java b/src/com/android/music/utils/MusicProvider.java
deleted file mode 100644
index 77ea9c1..0000000
--- a/src/com/android/music/utils/MusicProvider.java
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.media.MediaActionSound;
-import android.media.MediaMetadata;
-import android.media.MediaMetadataRetriever;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.provider.MediaStore;
-import android.util.Log;
-import com.android.music.MediaPlaybackService;
-import com.android.music.MusicUtils;
-import com.android.music.R;
-
-import java.io.File;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/*
-A provider of music contents to the music application, it reads external storage for any music
-files, parse them and
-store them in this class for future use.
- */
-public class MusicProvider {
- private static final String TAG = "MusicProvider";
-
- // Public constants
- public static final String UNKOWN = "UNKNOWN";
- // Uri source of this track
- public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__";
- // Sort key for this tack
- public static final String CUSTOM_METADATA_SORT_KEY = "__SORT_KEY__";
-
- // Content select criteria
- private static final String MUSIC_SELECT_FILTER = MediaStore.Audio.Media.IS_MUSIC + " != 0";
- private static final String MUSIC_SORT_ORDER = MediaStore.Audio.Media.TITLE + " ASC";
-
- // Categorized caches for music track data:
- private Context mContext;
- // Album Name --> list of Metadata
- private ConcurrentMap<String, List<MediaMetadata>> mMusicListByAlbum;
- // Playlist Name --> list of Metadata
- private ConcurrentMap<String, List<MediaMetadata>> mMusicListByPlaylist;
- // Artist Name --> Map of (album name --> album metadata)
- private ConcurrentMap<String, Map<String, MediaMetadata>> mArtistAlbumDb;
- private List<MediaMetadata> mMusicList;
- private final ConcurrentMap<Long, Song> mMusicListById;
- private final ConcurrentMap<String, Song> mMusicListByMediaId;
-
- enum State { NON_INITIALIZED, INITIALIZING, INITIALIZED }
-
- private volatile State mCurrentState = State.NON_INITIALIZED;
-
- public MusicProvider(Context context) {
- mContext = context;
- mArtistAlbumDb = new ConcurrentHashMap<>();
- mMusicListByAlbum = new ConcurrentHashMap<>();
- mMusicListByPlaylist = new ConcurrentHashMap<>();
- mMusicListById = new ConcurrentHashMap<>();
- mMusicList = new ArrayList<>();
- mMusicListByMediaId = new ConcurrentHashMap<>();
- mMusicListByPlaylist.put(MediaIDHelper.MEDIA_ID_NOW_PLAYING, new ArrayList<>());
- }
-
- public boolean isInitialized() {
- return mCurrentState == State.INITIALIZED;
- }
-
- /**
- * Get an iterator over the list of artists
- *
- * @return list of artists
- */
- public Iterable<String> getArtists() {
- if (mCurrentState != State.INITIALIZED) {
- return Collections.emptyList();
- }
- return mArtistAlbumDb.keySet();
- }
-
- /**
- * Get an iterator over the list of albums
- *
- * @return list of albums
- */
- public Iterable<MediaMetadata> getAlbums() {
- if (mCurrentState != State.INITIALIZED) {
- return Collections.emptyList();
- }
- ArrayList<MediaMetadata> albumList = new ArrayList<>();
- for (Map<String, MediaMetadata> artist_albums : mArtistAlbumDb.values()) {
- albumList.addAll(artist_albums.values());
- }
- return albumList;
- }
-
- /**
- * Get an iterator over the list of playlists
- *
- * @return list of playlists
- */
- public Iterable<String> getPlaylists() {
- if (mCurrentState != State.INITIALIZED) {
- return Collections.emptyList();
- }
- return mMusicListByPlaylist.keySet();
- }
-
- public Iterable<MediaMetadata> getMusicList() {
- return mMusicList;
- }
-
- /**
- * Get albums of a certain artist
- *
- */
- public Iterable<MediaMetadata> getAlbumByArtist(String artist) {
- if (mCurrentState != State.INITIALIZED || !mArtistAlbumDb.containsKey(artist)) {
- return Collections.emptyList();
- }
- return mArtistAlbumDb.get(artist).values();
- }
-
- /**
- * Get music tracks of the given album
- *
- */
- public Iterable<MediaMetadata> getMusicsByAlbum(String album) {
- if (mCurrentState != State.INITIALIZED || !mMusicListByAlbum.containsKey(album)) {
- return Collections.emptyList();
- }
- return mMusicListByAlbum.get(album);
- }
-
- /**
- * Get music tracks of the given playlist
- *
- */
- public Iterable<MediaMetadata> getMusicsByPlaylist(String playlist) {
- if (mCurrentState != State.INITIALIZED || !mMusicListByPlaylist.containsKey(playlist)) {
- return Collections.emptyList();
- }
- return mMusicListByPlaylist.get(playlist);
- }
-
- /**
- * Return the MediaMetadata for the given musicID.
- *
- * @param musicId The unique, non-hierarchical music ID.
- */
- public Song getMusicById(long musicId) {
- return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId) : null;
- }
-
- /**
- * Return the MediaMetadata for the given musicID.
- *
- * @param musicId The unique, non-hierarchical music ID.
- */
- public Song getMusicByMediaId(String musicId) {
- return mMusicListByMediaId.containsKey(musicId) ? mMusicListByMediaId.get(musicId) : null;
- }
-
- /**
- * Very basic implementation of a search that filter music tracks which title containing
- * the given query.
- *
- */
- public Iterable<MediaMetadata> searchMusic(String titleQuery) {
- if (mCurrentState != State.INITIALIZED) {
- return Collections.emptyList();
- }
- ArrayList<MediaMetadata> result = new ArrayList<>();
- titleQuery = titleQuery.toLowerCase();
- for (Song song : mMusicListByMediaId.values()) {
- if (song.getMetadata()
- .getString(MediaMetadata.METADATA_KEY_TITLE)
- .toLowerCase()
- .contains(titleQuery)) {
- result.add(song.getMetadata());
- }
- }
- return result;
- }
-
- public interface MusicProviderCallback { void onMusicCatalogReady(boolean success); }
-
- /**
- * Get the list of music tracks from disk and caches the track information
- * for future reference, keying tracks by musicId and grouping by genre.
- */
- public void retrieveMediaAsync(final MusicProviderCallback callback) {
- Log.d(TAG, "retrieveMediaAsync called");
- if (mCurrentState == State.INITIALIZED) {
- // Nothing to do, execute callback immediately
- callback.onMusicCatalogReady(true);
- return;
- }
-
- // Asynchronously load the music catalog in a separate thread
- new AsyncTask<Void, Void, State>() {
- @Override
- protected State doInBackground(Void... params) {
- if (mCurrentState == State.INITIALIZED) {
- return mCurrentState;
- }
- mCurrentState = State.INITIALIZING;
- if (retrieveMedia()) {
- mCurrentState = State.INITIALIZED;
- } else {
- mCurrentState = State.NON_INITIALIZED;
- }
- return mCurrentState;
- }
-
- @Override
- protected void onPostExecute(State current) {
- if (callback != null) {
- callback.onMusicCatalogReady(current == State.INITIALIZED);
- }
- }
- }
- .execute();
- }
-
- public synchronized boolean retrieveAllPlayLists() {
- Cursor cursor = mContext.getContentResolver().query(
- MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, null, null, null, null);
- if (cursor == null) {
- Log.e(TAG, "Failed to retreive playlist: cursor is null");
- return false;
- }
- if (!cursor.moveToFirst()) {
- Log.d(TAG, "Failed to move cursor to first row (no query result)");
- cursor.close();
- return true;
- }
- int idColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists._ID);
- int nameColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.NAME);
- int pathColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.DATA);
- do {
- long thisId = cursor.getLong(idColumn);
- String thisPath = cursor.getString(pathColumn);
- String thisName = cursor.getString(nameColumn);
- Log.i(TAG, "PlayList ID: " + thisId + " Name: " + thisName);
- List<MediaMetadata> songList = retreivePlaylistMetadata(thisId, thisPath);
- LogHelper.i(TAG, "Found ", songList.size(), " items for playlist name: ", thisName);
- mMusicListByPlaylist.put(thisName, songList);
- } while (cursor.moveToNext());
- cursor.close();
- return true;
- }
-
- public synchronized List<MediaMetadata> retreivePlaylistMetadata(
- long playlistId, String playlistPath) {
- Cursor cursor = mContext.getContentResolver().query(Uri.parse(playlistPath), null,
- MediaStore.Audio.Playlists.Members.PLAYLIST_ID + " == " + playlistId, null, null);
- if (cursor == null) {
- Log.e(TAG, "Failed to retreive individual playlist: cursor is null");
- return null;
- }
- if (!cursor.moveToFirst()) {
- Log.d(TAG, "Failed to move cursor to first row (no query result for playlist)");
- cursor.close();
- return null;
- }
- List<Song> songList = new ArrayList<>();
- int idColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members._ID);
- int audioIdColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID);
- int orderColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER);
- int audioPathColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.DATA);
- int audioNameColumn = cursor.getColumnIndex(MediaStore.Audio.Playlists.Members.TITLE);
- do {
- long thisId = cursor.getLong(idColumn);
- long thisAudioId = cursor.getLong(audioIdColumn);
- long thisOrder = cursor.getLong(orderColumn);
- String thisAudioPath = cursor.getString(audioPathColumn);
- Log.i(TAG,
- "Playlist ID: " + playlistId + " Music ID: " + thisAudioId
- + " Name: " + audioNameColumn);
- if (!mMusicListById.containsKey(thisAudioId)) {
- LogHelper.d(TAG, "Music does not exist");
- continue;
- }
- Song song = mMusicListById.get(thisAudioId);
- song.setSortKey(thisOrder);
- songList.add(song);
- } while (cursor.moveToNext());
- cursor.close();
- songList.sort(new Comparator<Song>() {
- @Override
- public int compare(Song s1, Song s2) {
- long key1 = s1.getSortKey();
- long key2 = s2.getSortKey();
- if (key1 < key2) {
- return -1;
- } else if (key1 == key2) {
- return 0;
- } else {
- return 1;
- }
- }
- });
- List<MediaMetadata> metadataList = new ArrayList<>();
- for (Song song : songList) {
- metadataList.add(song.getMetadata());
- }
- return metadataList;
- }
-
- private synchronized boolean retrieveMedia() {
- if (mContext.checkSelfPermission(READ_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
- return false;
- }
-
- Cursor cursor =
- mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
- null, MUSIC_SELECT_FILTER, null, MUSIC_SORT_ORDER);
- if (cursor == null) {
- Log.e(TAG, "Failed to retreive music: cursor is null");
- mCurrentState = State.NON_INITIALIZED;
- return false;
- }
- if (!cursor.moveToFirst()) {
- Log.d(TAG, "Failed to move cursor to first row (no query result)");
- cursor.close();
- return true;
- }
- int idColumn = cursor.getColumnIndex(MediaStore.Audio.Media._ID);
- int titleColumn = cursor.getColumnIndex(MediaStore.Audio.Media.TITLE);
- int pathColumn = cursor.getColumnIndex(MediaStore.Audio.Media.DATA);
- do {
- Log.i(TAG,
- "Music ID: " + cursor.getString(idColumn)
- + " Title: " + cursor.getString(titleColumn));
- long thisId = cursor.getLong(idColumn);
- String thisPath = cursor.getString(pathColumn);
- MediaMetadata metadata = retrievMediaMetadata(thisId, thisPath);
- Log.i(TAG, "MediaMetadata: " + metadata);
- if (metadata == null) {
- continue;
- }
- Song thisSong = new Song(thisId, metadata, null);
- // Construct per feature database
- mMusicList.add(metadata);
- mMusicListById.put(thisId, thisSong);
- mMusicListByMediaId.put(String.valueOf(thisId), thisSong);
- addMusicToAlbumList(metadata);
- addMusicToArtistList(metadata);
- } while (cursor.moveToNext());
- cursor.close();
- return true;
- }
-
- private synchronized MediaMetadata retrievMediaMetadata(long musicId, String musicPath) {
- LogHelper.d(TAG, "getting metadata for music: ", musicPath);
- MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- Uri contentUri = ContentUris.withAppendedId(
- android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, musicId);
- if (!(new File(musicPath).exists())) {
- LogHelper.d(TAG, "Does not exist, deleting item");
- mContext.getContentResolver().delete(contentUri, null, null);
- return null;
- }
- retriever.setDataSource(mContext, contentUri);
- String title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- String album = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- String artist = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
- String durationString =
- retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
- long duration = durationString != null ? Long.parseLong(durationString) : 0;
- MediaMetadata.Builder metadataBuilder =
- new MediaMetadata.Builder()
- .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, String.valueOf(musicId))
- .putString(CUSTOM_METADATA_TRACK_SOURCE, musicPath)
- .putString(MediaMetadata.METADATA_KEY_TITLE, title != null ? title : UNKOWN)
- .putString(MediaMetadata.METADATA_KEY_ALBUM, album != null ? album : UNKOWN)
- .putString(
- MediaMetadata.METADATA_KEY_ARTIST, artist != null ? artist : UNKOWN)
- .putLong(MediaMetadata.METADATA_KEY_DURATION, duration);
- byte[] albumArtData = retriever.getEmbeddedPicture();
- Bitmap bitmap;
- if (albumArtData != null) {
- bitmap = BitmapFactory.decodeByteArray(albumArtData, 0, albumArtData.length);
- bitmap = MusicUtils.resizeBitmap(bitmap, getDefaultAlbumArt());
- metadataBuilder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, bitmap);
- }
- retriever.release();
- return metadataBuilder.build();
- }
-
- private Bitmap getDefaultAlbumArt() {
- BitmapFactory.Options opts = new BitmapFactory.Options();
- opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
- return BitmapFactory.decodeStream(
- mContext.getResources().openRawResource(R.drawable.albumart_mp_unknown), null,
- opts);
- }
-
- private void addMusicToAlbumList(MediaMetadata metadata) {
- String thisAlbum = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
- if (thisAlbum == null) {
- thisAlbum = UNKOWN;
- }
- if (!mMusicListByAlbum.containsKey(thisAlbum)) {
- mMusicListByAlbum.put(thisAlbum, new ArrayList<>());
- }
- mMusicListByAlbum.get(thisAlbum).add(metadata);
- }
-
- private void addMusicToArtistList(MediaMetadata metadata) {
- String thisArtist = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
- if (thisArtist == null) {
- thisArtist = UNKOWN;
- }
- String thisAlbum = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM);
- if (thisAlbum == null) {
- thisAlbum = UNKOWN;
- }
- if (!mArtistAlbumDb.containsKey(thisArtist)) {
- mArtistAlbumDb.put(thisArtist, new ConcurrentHashMap<>());
- }
- Map<String, MediaMetadata> albumsMap = mArtistAlbumDb.get(thisArtist);
- MediaMetadata.Builder builder;
- long count = 0;
- Bitmap thisAlbumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- if (albumsMap.containsKey(thisAlbum)) {
- MediaMetadata album_metadata = albumsMap.get(thisAlbum);
- count = album_metadata.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS);
- Bitmap nAlbumArt = album_metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
- builder = new MediaMetadata.Builder(album_metadata);
- if (nAlbumArt != null) {
- thisAlbumArt = null;
- }
- } else {
- builder = new MediaMetadata.Builder();
- builder.putString(MediaMetadata.METADATA_KEY_ALBUM, thisAlbum)
- .putString(MediaMetadata.METADATA_KEY_ARTIST, thisArtist);
- }
- if (thisAlbumArt != null) {
- builder.putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, thisAlbumArt);
- }
- builder.putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, count + 1);
- albumsMap.put(thisAlbum, builder.build());
- }
-
- public synchronized void updateMusic(String musicId, MediaMetadata metadata) {
- Song song = mMusicListByMediaId.get(musicId);
- if (song == null) {
- return;
- }
-
- String oldGenre = song.getMetadata().getString(MediaMetadata.METADATA_KEY_GENRE);
- String newGenre = metadata.getString(MediaMetadata.METADATA_KEY_GENRE);
-
- song.setMetadata(metadata);
-
- // if genre has changed, we need to rebuild the list by genre
- if (!oldGenre.equals(newGenre)) {
- // buildListsByGenre();
- }
- }
-}
diff --git a/src/com/android/music/utils/Playback.java b/src/com/android/music/utils/Playback.java
deleted file mode 100644
index 02114bd..0000000
--- a/src/com/android/music/utils/Playback.java
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.music.utils;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.MediaPlayer;
-import android.media.session.PlaybackState;
-import android.net.wifi.WifiManager;
-import android.os.PowerManager;
-import android.text.TextUtils;
-import android.util.Log;
-import com.android.music.MediaPlaybackService;
-
-import java.io.IOException;
-
-import static android.media.MediaPlayer.OnCompletionListener;
-import static android.media.MediaPlayer.OnErrorListener;
-import static android.media.MediaPlayer.OnPreparedListener;
-import static android.media.MediaPlayer.OnSeekCompleteListener;
-import static android.media.session.MediaSession.QueueItem;
-
-/**
- * A class that implements local media playback using {@link android.media.MediaPlayer}
- */
-public class Playback implements AudioManager.OnAudioFocusChangeListener, OnCompletionListener,
- OnErrorListener, OnPreparedListener, OnSeekCompleteListener {
- private static final String TAG = "Playback";
-
- // 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 static final float VOLUME_DUCK = 0.2f;
- // The volume we set the media player when we have audio focus.
- public static final float VOLUME_NORMAL = 1.0f;
-
- // we don't have audio focus, and can't duck (play at a low volume)
- private static final int AUDIO_NO_FOCUS_NO_DUCK = 0;
- // we don't have focus, but can duck (play at a low volume)
- private static final int AUDIO_NO_FOCUS_CAN_DUCK = 1;
- // we have full audio focus
- private static final int AUDIO_FOCUSED = 2;
-
- private final MediaPlaybackService mService;
- private final WifiManager.WifiLock mWifiLock;
- private int mState;
- private boolean mPlayOnFocusGain;
- private Callback mCallback;
- private MusicProvider mMusicProvider;
- private volatile boolean mAudioNoisyReceiverRegistered;
- private volatile int mCurrentPosition;
- private volatile String mCurrentMediaId;
-
- // Type of audio focus we have:
- private int mAudioFocus = AUDIO_NO_FOCUS_NO_DUCK;
- private AudioManager mAudioManager;
- private MediaPlayer mMediaPlayer;
-
- private IntentFilter mAudioNoisyIntentFilter =
- new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
-
- private BroadcastReceiver mAudioNoisyReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
- Log.d(TAG, "Headphones disconnected.");
- if (isPlaying()) {
- Intent i = new Intent(context, MediaPlaybackService.class);
- i.setAction(MediaPlaybackService.ACTION_CMD);
- i.putExtra(MediaPlaybackService.CMD_NAME, MediaPlaybackService.CMD_PAUSE);
- mService.startService(i);
- }
- }
- }
- };
-
- public Playback(MediaPlaybackService service, MusicProvider musicProvider) {
- this.mService = service;
- this.mMusicProvider = musicProvider;
- this.mAudioManager = (AudioManager) service.getSystemService(Context.AUDIO_SERVICE);
- // Create the Wifi lock (this does not acquire the lock, this just creates it)
- this.mWifiLock = ((WifiManager) service.getSystemService(Context.WIFI_SERVICE))
- .createWifiLock(WifiManager.WIFI_MODE_FULL, "sample_lock");
- }
-
- public void start() {}
-
- public void stop(boolean notifyListeners) {
- mState = PlaybackState.STATE_STOPPED;
- if (notifyListeners && mCallback != null) {
- mCallback.onPlaybackStatusChanged(mState);
- }
- mCurrentPosition = getCurrentStreamPosition();
- // Give up Audio focus
- giveUpAudioFocus();
- unregisterAudioNoisyReceiver();
- // Relax all resources
- relaxResources(true);
- if (mWifiLock.isHeld()) {
- mWifiLock.release();
- }
- }
-
- public void setState(int state) {
- this.mState = state;
- }
-
- public int getState() {
- return mState;
- }
-
- public boolean isConnected() {
- return true;
- }
-
- public boolean isPlaying() {
- return mPlayOnFocusGain || (mMediaPlayer != null && mMediaPlayer.isPlaying());
- }
-
- public int getCurrentStreamPosition() {
- return mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : mCurrentPosition;
- }
-
- public void play(QueueItem item) {
- mPlayOnFocusGain = true;
- tryToGetAudioFocus();
- registerAudioNoisyReceiver();
- String mediaId = item.getDescription().getMediaId();
- boolean mediaHasChanged = !TextUtils.equals(mediaId, mCurrentMediaId);
- if (mediaHasChanged) {
- mCurrentPosition = 0;
- mCurrentMediaId = mediaId;
- }
-
- if (mState == PlaybackState.STATE_PAUSED && !mediaHasChanged && mMediaPlayer != null) {
- configMediaPlayerState();
- } else {
- mState = PlaybackState.STATE_STOPPED;
- relaxResources(false); // release everything except MediaPlayer
- MediaMetadata track =
- mMusicProvider
- .getMusicByMediaId(MediaIDHelper.extractMusicIDFromMediaID(
- item.getDescription().getMediaId()))
- .getMetadata();
-
- String source = track.getString(MusicProvider.CUSTOM_METADATA_TRACK_SOURCE);
-
- try {
- createMediaPlayerIfNeeded();
-
- mState = PlaybackState.STATE_BUFFERING;
-
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mMediaPlayer.setDataSource(source);
-
- // 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!
- mMediaPlayer.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.
- // mWifiLock.acquire();
-
- if (mCallback != null) {
- mCallback.onPlaybackStatusChanged(mState);
- }
-
- } catch (IOException ex) {
- Log.e(TAG, ex + "Exception playing song");
- if (mCallback != null) {
- mCallback.onError(ex.getMessage());
- }
- }
- }
- }
-
- public void pause() {
- if (mState == PlaybackState.STATE_PLAYING) {
- // Pause media player and cancel the 'foreground service' state.
- if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
- mMediaPlayer.pause();
- mCurrentPosition = mMediaPlayer.getCurrentPosition();
- }
- // while paused, retain the MediaPlayer but give up audio focus
- relaxResources(false);
- giveUpAudioFocus();
- }
- mState = PlaybackState.STATE_PAUSED;
- if (mCallback != null) {
- mCallback.onPlaybackStatusChanged(mState);
- }
- unregisterAudioNoisyReceiver();
- }
-
- public void seekTo(int position) {
- Log.d(TAG, "seekTo called with " + position);
-
- if (mMediaPlayer == null) {
- // If we do not have a current media player, simply update the current position
- mCurrentPosition = position;
- } else {
- if (mMediaPlayer.isPlaying()) {
- mState = PlaybackState.STATE_BUFFERING;
- }
- mMediaPlayer.seekTo(position);
- if (mCallback != null) {
- mCallback.onPlaybackStatusChanged(mState);
- }
- }
- }
-
- public void setCallback(Callback callback) {
- this.mCallback = callback;
- }
-
- /**
- * Try to get the system audio focus.
- */
- private void tryToGetAudioFocus() {
- Log.d(TAG, "tryToGetAudioFocus");
- if (mAudioFocus != AUDIO_FOCUSED) {
- int result = mAudioManager.requestAudioFocus(
- this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
- if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- mAudioFocus = AUDIO_FOCUSED;
- }
- }
- }
-
- /**
- * Give up the audio focus.
- */
- private void giveUpAudioFocus() {
- Log.d(TAG, "giveUpAudioFocus");
- if (mAudioFocus == AUDIO_FOCUSED) {
- if (mAudioManager.abandonAudioFocus(this) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
- mAudioFocus = AUDIO_NO_FOCUS_NO_DUCK;
- }
- }
- }
-
- /**
- * 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.
- */
- private void configMediaPlayerState() {
- Log.d(TAG, "configMediaPlayerState. mAudioFocus=" + mAudioFocus);
- if (mAudioFocus == AUDIO_NO_FOCUS_NO_DUCK) {
- // If we don't have audio focus and can't duck, we have to pause,
- if (mState == PlaybackState.STATE_PLAYING) {
- pause();
- }
- } else { // we have audio focus:
- if (mAudioFocus == AUDIO_NO_FOCUS_CAN_DUCK) {
- mMediaPlayer.setVolume(VOLUME_DUCK, VOLUME_DUCK); // we'll be relatively quiet
- } else {
- if (mMediaPlayer != null) {
- mMediaPlayer.setVolume(VOLUME_NORMAL, VOLUME_NORMAL); // we can be loud again
- } // else do something for remote client.
- }
- // If we were playing when we lost focus, we need to resume playing.
- if (mPlayOnFocusGain) {
- if (mMediaPlayer != null && !mMediaPlayer.isPlaying()) {
- Log.d(TAG,
- "configMediaPlayerState startMediaPlayer. seeking to "
- + mCurrentPosition);
- if (mCurrentPosition == mMediaPlayer.getCurrentPosition()) {
- mMediaPlayer.start();
- mState = PlaybackState.STATE_PLAYING;
- } else {
- mMediaPlayer.seekTo(mCurrentPosition);
- mState = PlaybackState.STATE_BUFFERING;
- }
- }
- mPlayOnFocusGain = false;
- }
- }
- if (mCallback != null) {
- mCallback.onPlaybackStatusChanged(mState);
- }
- }
-
- /**
- * Called by AudioManager on audio focus changes.
- * Implementation of {@link android.media.AudioManager.OnAudioFocusChangeListener}
- */
- @Override
- public void onAudioFocusChange(int focusChange) {
- Log.d(TAG, "onAudioFocusChange. focusChange=" + focusChange);
- if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
- // We have gained focus:
- mAudioFocus = AUDIO_FOCUSED;
-
- } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS
- || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT
- || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
- // We have lost focus. If we can duck (low playback volume), we can keep playing.
- // Otherwise, we need to pause the playback.
- boolean canDuck = focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK;
- mAudioFocus = canDuck ? AUDIO_NO_FOCUS_CAN_DUCK : AUDIO_NO_FOCUS_NO_DUCK;
-
- // If we are playing, we need to reset media player by calling configMediaPlayerState
- // with mAudioFocus properly set.
- if (mState == PlaybackState.STATE_PLAYING && !canDuck) {
- // If we don't have audio focus and can't duck, we save the information that
- // we were playing, so that we can resume playback once we get the focus back.
- mPlayOnFocusGain = true;
- }
- } else {
- Log.e(TAG, "onAudioFocusChange: Ignoring unsupported focusChange: " + focusChange);
- }
- configMediaPlayerState();
- }
-
- /**
- * Called when MediaPlayer has completed a seek
- *
- * @see android.media.MediaPlayer.OnSeekCompleteListener
- */
- @Override
- public void onSeekComplete(MediaPlayer mp) {
- Log.d(TAG, "onSeekComplete from MediaPlayer:" + mp.getCurrentPosition());
- mCurrentPosition = mp.getCurrentPosition();
- if (mState == PlaybackState.STATE_BUFFERING) {
- mMediaPlayer.start();
- mState = PlaybackState.STATE_PLAYING;
- }
- if (mCallback != null) {
- mCallback.onPlaybackStatusChanged(mState);
- }
- }
-
- /**
- * Called when media player is done playing current song.
- *
- * @see android.media.MediaPlayer.OnCompletionListener
- */
- @Override
- public void onCompletion(MediaPlayer player) {
- Log.d(TAG, "onCompletion from MediaPlayer");
- // The media player finished playing the current song, so we go ahead
- // and start the next.
- if (mCallback != null) {
- mCallback.onCompletion();
- }
- }
-
- /**
- * Called when media player is done preparing.
- *
- * @see android.media.MediaPlayer.OnPreparedListener
- */
- @Override
- public void onPrepared(MediaPlayer player) {
- Log.d(TAG, "onPrepared from MediaPlayer");
- // The media player is done preparing. That means we can start playing if we
- // have audio focus.
- configMediaPlayerState();
- }
-
- /**
- * 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.
- *
- * @see android.media.MediaPlayer.OnErrorListener
- */
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
- Log.e(TAG, "Media player error: what=" + what + ", extra=" + extra);
- if (mCallback != null) {
- mCallback.onError("MediaPlayer error " + what + " (" + extra + ")");
- }
- return true; // true indicates we handled the error
- }
-
- /**
- * 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.
- */
- private void createMediaPlayerIfNeeded() {
- Log.d(TAG, "createMediaPlayerIfNeeded. needed? " + (mMediaPlayer == null));
- if (mMediaPlayer == null) {
- mMediaPlayer = 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.
- mMediaPlayer.setWakeMode(
- mService.getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
-
- // we want the media player to notify us when it's ready preparing,
- // and when it's done playing:
- mMediaPlayer.setOnPreparedListener(this);
- mMediaPlayer.setOnCompletionListener(this);
- mMediaPlayer.setOnErrorListener(this);
- mMediaPlayer.setOnSeekCompleteListener(this);
- } else {
- mMediaPlayer.reset();
- }
- }
-
- /**
- * Releases resources used by the service for playback. This includes the
- * "foreground service" status, the wake locks and possibly the MediaPlayer.
- *
- * @param releaseMediaPlayer Indicates whether the Media Player should also
- * be released or not
- */
- private void relaxResources(boolean releaseMediaPlayer) {
- Log.d(TAG, "relaxResources. releaseMediaPlayer=" + releaseMediaPlayer);
-
- mService.stopForeground(true);
-
- // stop and release the Media Player, if it's available
- if (releaseMediaPlayer && mMediaPlayer != null) {
- mMediaPlayer.reset();
- mMediaPlayer.release();
- mMediaPlayer = null;
- }
-
- // we can also release the Wifi lock, if we're holding it
- if (mWifiLock.isHeld()) {
- mWifiLock.release();
- }
- }
-
- private void registerAudioNoisyReceiver() {
- if (!mAudioNoisyReceiverRegistered) {
- mService.registerReceiver(mAudioNoisyReceiver, mAudioNoisyIntentFilter);
- mAudioNoisyReceiverRegistered = true;
- }
- }
-
- private void unregisterAudioNoisyReceiver() {
- if (mAudioNoisyReceiverRegistered) {
- mService.unregisterReceiver(mAudioNoisyReceiver);
- mAudioNoisyReceiverRegistered = false;
- }
- }
-
- public interface Callback {
- /**
- * On current music completed.
- */
- void onCompletion();
- /**
- * on Playback status changed
- * Implementations can use this callback to update
- * playback state on the media sessions.
- */
- void onPlaybackStatusChanged(int state);
-
- /**
- * @param error to be added to the PlaybackState
- */
- void onError(String error);
- }
-}
diff --git a/src/com/android/music/utils/QueueHelper.java b/src/com/android/music/utils/QueueHelper.java
deleted file mode 100644
index 7e3c2fd..0000000
--- a/src/com/android/music/utils/QueueHelper.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-
-import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST;
-import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_SEARCH;
-import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_SONG;
-import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST;
-import static com.android.music.utils.MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM;
-
-/**
- * Utility class to help on queue related tasks.
- */
-public class QueueHelper {
- private static final String TAG = LogHelper.makeLogTag(QueueHelper.class);
-
- public static List<MediaSession.QueueItem> getPlayingQueue(
- String mediaId, MusicProvider musicProvider) {
- // extract the browsing hierarchy from the media ID:
- String[] hierarchy = MediaIDHelper.getHierarchy(mediaId);
-
- if (hierarchy.length != 2) {
- LogHelper.e(TAG, "Could not build a playing queue for this mediaId: ", mediaId);
- return null;
- }
-
- String categoryType = hierarchy[0];
- String categoryValue = hierarchy[1];
- LogHelper.d(TAG, "Creating playing queue for ", categoryType, ", ", categoryValue);
-
- Iterable<MediaMetadata> tracks = null;
- // This sample only supports genre and by_search category types.
- switch (categoryType) {
- case MEDIA_ID_MUSICS_BY_SONG:
- tracks = musicProvider.getMusicList();
- break;
- case MEDIA_ID_MUSICS_BY_ALBUM:
- tracks = musicProvider.getMusicsByAlbum(categoryValue);
- break;
- case MEDIA_ID_MUSICS_BY_ARTIST:
- LogHelper.d(TAG, "Not supported");
- break;
- default:
- break;
- }
-
- if (tracks == null) {
- LogHelper.e(
- TAG, "Unrecognized category type: ", categoryType, " for mediaId ", mediaId);
- return null;
- }
-
- return convertToQueue(tracks, hierarchy[0], hierarchy[1]);
- }
-
- public static List<MediaSession.QueueItem> getPlayingQueueFromSearch(
- String query, MusicProvider musicProvider) {
- LogHelper.d(TAG, "Creating playing queue for musics from search ", query);
-
- return convertToQueue(musicProvider.searchMusic(query), MEDIA_ID_MUSICS_BY_SEARCH, query);
- }
-
- public static int getMusicIndexOnQueue(Iterable<MediaSession.QueueItem> queue, String mediaId) {
- int index = 0;
- for (MediaSession.QueueItem item : queue) {
- if (mediaId.equals(item.getDescription().getMediaId())) {
- return index;
- }
- index++;
- }
- return -1;
- }
-
- public static int getMusicIndexOnQueue(Iterable<MediaSession.QueueItem> queue, long queueId) {
- int index = 0;
- for (MediaSession.QueueItem item : queue) {
- if (queueId == item.getQueueId()) {
- return index;
- }
- index++;
- }
- return -1;
- }
-
- private static List<MediaSession.QueueItem> convertToQueue(
- Iterable<MediaMetadata> tracks, String... categories) {
- List<MediaSession.QueueItem> queue = new ArrayList<>();
- int count = 0;
- for (MediaMetadata track : tracks) {
- // We create a hierarchy-aware mediaID, so we know what the queue is about by looking
- // at the QueueItem media IDs.
- String hierarchyAwareMediaID =
- MediaIDHelper.createMediaID(track.getDescription().getMediaId(), categories);
- long duration = track.getLong(MediaMetadata.METADATA_KEY_DURATION);
- MediaDescription.Builder descriptionBuilder = new MediaDescription.Builder();
- MediaDescription description = track.getDescription();
- Bundle extras = description.getExtras();
- if (extras == null) {
- extras = new Bundle();
- }
- extras.putLong(MediaMetadata.METADATA_KEY_DURATION, duration);
- descriptionBuilder.setExtras(extras)
- .setMediaId(hierarchyAwareMediaID)
- .setTitle(description.getTitle())
- .setSubtitle(track.getString(MediaMetadata.METADATA_KEY_ARTIST))
- .setIconBitmap(description.getIconBitmap())
- .setIconUri(description.getIconUri())
- .setMediaUri(description.getMediaUri())
- .setDescription(description.getDescription());
-
- // We don't expect queues to change after created, so we use the item index as the
- // queueId. Any other number unique in the queue would work.
- MediaSession.QueueItem item =
- new MediaSession.QueueItem(descriptionBuilder.build(), count++);
- queue.add(item);
- }
- return queue;
- }
-
- /**
- * Create a random queue. For simplicity sake, instead of a random queue, we create a
- * queue using the first genre.
- *
- * @param musicProvider the provider used for fetching music.
- * @return list containing {@link android.media.session.MediaSession.QueueItem}'s
- */
- public static List<MediaSession.QueueItem> getRandomQueue(MusicProvider musicProvider) {
- Iterator<String> genres = musicProvider.getArtists().iterator();
- if (!genres.hasNext()) {
- return Collections.emptyList();
- }
- String genre = genres.next();
- Iterable<MediaMetadata> tracks = musicProvider.getMusicsByAlbum(genre);
-
- return convertToQueue(tracks, MEDIA_ID_MUSICS_BY_ARTIST, genre);
- }
-
- public static boolean isIndexPlayable(int index, List<MediaSession.QueueItem> queue) {
- return (queue != null && index >= 0 && index < queue.size());
- }
-}
diff --git a/src/com/android/music/utils/ResourceHelper.java b/src/com/android/music/utils/ResourceHelper.java
deleted file mode 100644
index d7773ff..0000000
--- a/src/com/android/music/utils/ResourceHelper.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-
-/**
- * Generic reusable methods to handle resources.
- */
-public class ResourceHelper {
- /**
- * Get a color value from a theme attribute.
- * @param context used for getting the color.
- * @param attribute theme attribute.
- * @param defaultColor default to use.
- * @return color value
- */
- public static int getThemeColor(Context context, int attribute, int defaultColor) {
- int themeColor = 0;
- String packageName = context.getPackageName();
- try {
- Context packageContext = context.createPackageContext(packageName, 0);
- ApplicationInfo applicationInfo =
- context.getPackageManager().getApplicationInfo(packageName, 0);
- packageContext.setTheme(applicationInfo.theme);
- Resources.Theme theme = packageContext.getTheme();
- TypedArray ta = theme.obtainStyledAttributes(new int[] {attribute});
- themeColor = ta.getColor(0, defaultColor);
- ta.recycle();
- } catch (PackageManager.NameNotFoundException e) {
- e.printStackTrace();
- }
- return themeColor;
- }
-}
diff --git a/src/com/android/music/utils/Song.java b/src/com/android/music/utils/Song.java
deleted file mode 100644
index 1260f03..0000000
--- a/src/com/android/music/utils/Song.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.utils;
-
-import android.media.MediaMetadata;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-/**
- * Holder class that encapsulates a MediaMetadata and allows the actual metadata to be modified
- * without requiring to rebuild the collections the metadata is in.
- */
-public class Song implements Parcelable {
- private MediaMetadata mMetadata;
- private long mSongId;
- private long mSortKey;
-
- public Song(long songId, MediaMetadata metadata, Long sortKey) {
- mMetadata = metadata;
- mSongId = songId;
- if (sortKey != null) {
- mSortKey = sortKey;
- }
- }
-
- public long getSongId() {
- return mSongId;
- }
- public long getSortKey() {
- return mSortKey;
- }
- public void setSortKey(long sortKey) {
- mSortKey = sortKey;
- }
-
- public MediaMetadata getMetadata() {
- return mMetadata;
- }
- public void setMetadata(MediaMetadata metadata) {
- mMetadata = metadata;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || o.getClass() != Song.class) {
- return false;
- }
-
- Song that = (Song) o;
-
- return mSongId == that.getSongId();
- }
-
- @Override
- public int hashCode() {
- return Long.hashCode(mSongId);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mSortKey);
- out.writeLong(mSongId);
- out.writeParcelable(mMetadata, flags);
- }
-
- public static final Parcelable.Creator<Song> CREATOR = new Parcelable.Creator<Song>() {
- public Song createFromParcel(Parcel in) {
- MediaMetadata metadata = in.readParcelable(null);
- long songId = in.readLong();
- long sortKey = in.readLong();
- return new Song(songId, metadata, sortKey);
- }
-
- public Song[] newArray(int size) {
- return new Song[size];
- }
- };
-}
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index d94233c..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit android.test.legacy
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := MusicTests
-
-LOCAL_INSTRUMENTATION_FOR := Music
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
deleted file mode 100644
index 7c1f055..0000000
--- a/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.android.music.tests">
-
- <application/>
-
- <instrumentation android:name="com.android.music.tests.MusicPlayerLaunchPerformance"
- android:targetPackage="com.google.android.music"
- android:label="Music Launch Performance">
- </instrumentation>
-
- <instrumentation android:name="com.android.music.tests.MusicPlayerFunctionalTestRunner"
- android:targetPackage="com.google.android.music"
- android:label="Music Player Functional Test">
- </instrumentation>
-
- <instrumentation android:name="com.android.music.tests.MusicPlayerStressTestRunner"
- android:targetPackage="com.google.android.music"
- android:label="Music Player Stress Test">
- </instrumentation>
-
-</manifest>
diff --git a/tests/src/com/android/music/MusicPlayerFunctionalTestRunner.java b/tests/src/com/android/music/MusicPlayerFunctionalTestRunner.java
deleted file mode 100644
index bacb7e2..0000000
--- a/tests/src/com/android/music/MusicPlayerFunctionalTestRunner.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.tests;
-
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-import com.android.music.tests.functional.TestSongs;
-import com.android.music.tests.functional.TestPlaylist;
-
-import junit.framework.TestSuite;
-
-
-/**
- * Instrumentation Test Runner for all Music Player tests.
- *
- * Precondition: Opened keyboard and wipe the userdata
- *
- * Running all tests:
- *
- * adb shell am instrument \
- * -w com.android.music.tests/.MusicPlayerFunctionalTestRunner
- */
-
-public class MusicPlayerFunctionalTestRunner extends InstrumentationTestRunner {
-
-
- @Override
- public TestSuite getAllTests() {
- TestSuite suite = new InstrumentationTestSuite(this);
- suite.addTestSuite(TestSongs.class);
- suite.addTestSuite(TestPlaylist.class);
- suite.addTestSuite(MusicPlayerStability.class);
- return suite;
- }
-
- @Override
- public ClassLoader getLoader() {
- return MusicPlayerFunctionalTestRunner.class.getClassLoader();
- }
-}
-
-
-
diff --git a/tests/src/com/android/music/MusicPlayerLaunchPerformance.java b/tests/src/com/android/music/MusicPlayerLaunchPerformance.java
deleted file mode 100644
index 80342ba..0000000
--- a/tests/src/com/android/music/MusicPlayerLaunchPerformance.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.tests;
-
-import android.app.Activity;
-import android.test.LaunchPerformanceBase;
-import android.os.Bundle;
-
-import java.util.Map;
-
-/**
- * Instrumentation class for Media Player launch performance testing.
- */
-public class MusicPlayerLaunchPerformance extends LaunchPerformanceBase {
-
- public static final String LOG_TAG = "MusicPlayerLaunchPerformance";
-
- public MusicPlayerLaunchPerformance() {
- super();
- }
-
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
-
- mIntent.setClassName(getTargetContext(), "com.android.music.MusicBrowserActivity");
- start();
- }
-
- /**
- * Calls LaunchApp and finish.
- */
- @Override
- public void onStart() {
- super.onStart();
- LaunchApp();
- finish(Activity.RESULT_OK, mResults);
- }
-}
diff --git a/tests/src/com/android/music/MusicPlayerNames.java b/tests/src/com/android/music/MusicPlayerNames.java
deleted file mode 100644
index 655d578..0000000
--- a/tests/src/com/android/music/MusicPlayerNames.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.tests;
-
-import android.os.Environment;
-
-/**
- *
- * This class has the names of the all the activity name and variables
- * in the instrumentation test.
- *
- */
-public class MusicPlayerNames {
-
- //Expected result of the sorted playlistname
- public static final String expectedPlaylistTitle[] = { "**1E?:|}{[]~~.,;'",
- "//><..", "0123456789",
- "0random@112", "MyPlaylist", "UPPERLETTER",
- "combination011", "loooooooog",
- "normal", "~!@#$%^&*()_+"
- };
-
- //Unsorted input playlist name
- public static final String unsortedPlaylistTitle[] = { "//><..","MyPlaylist",
- "0random@112", "UPPERLETTER","normal",
- "combination011", "0123456789",
- "~!@#$%^&*()_+","**1E?:|}{[]~~.,;'",
- "loooooooog"
- };
-
- public static final String DELETE_PLAYLIST_NAME = "testDeletPlaylist";
- public static final String ORIGINAL_PLAYLIST_NAME = "original_playlist_name";
- public static final String RENAMED_PLAYLIST_NAME = "rename_playlist_name";
-
- public static int NO_OF_PLAYLIST = 10;
- public static int WAIT_SHORT_TIME = 1000;
- public static int WAIT_LONG_TIME = 2000;
- public static int WAIT_VERY_LONG_TIME = 6000;
- public static int SKIP_WAIT_TIME = 500;
- public static int DEFAULT_PLAYLIST_LENGTH = 15;
- public static int NO_ALBUMS_TOBE_PLAYED = 50;
- public static int NO_SKIPPING_SONGS = 500;
-
- public static final String EXTERNAL_DIR =
- Environment.getExternalStorageDirectory().toString();
- public static final String DELETESONG = EXTERNAL_DIR + "/toBeDeleted.amr";
- public static final String GOLDENSONG = EXTERNAL_DIR + "/media_api/music/AMRNB.amr";
- public static final String TOBEDELETESONGNAME = "toBeDeleted";
-
- public static int EXPECTED_NO_RINGTONE = 1;
-}
diff --git a/tests/src/com/android/music/MusicPlayerStability.java b/tests/src/com/android/music/MusicPlayerStability.java
deleted file mode 100644
index d84d2f8..0000000
--- a/tests/src/com/android/music/MusicPlayerStability.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.music.tests;
-
-import android.app.Instrumentation;
-import com.android.music.TrackBrowserActivity;
-import android.view.KeyEvent;
-import android.widget.ListView;
-
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.LargeTest;
-
-/**
- * Junit / Instrumentation test case for the Music Player
- */
-
-public class MusicPlayerStability extends ActivityInstrumentationTestCase2 <TrackBrowserActivity>{
- private static String TAG = "musicplayerstability";
- private static int PLAY_TIME = 30000;
- private ListView mTrackList;
-
- public MusicPlayerStability() {
- super("com.android.music",TrackBrowserActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- getActivity();
- super.setUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- /**
- * Test case 1: This test case is for the power and general stability
- * measurment. We don't need to do the validation. This test case simply
- * play the mp3 for 30 seconds then stop.
- * The sdcard should have the target mp3 files.
- */
- @LargeTest
- public void testPlay30sMP3() throws Exception {
- // Launch the songs list. Pick the fisrt song and play
- try {
- Instrumentation inst = getInstrumentation();
- //Make sure the song list shown up
- Thread.sleep(2000);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- mTrackList = getActivity().getListView();
- int scrollCount = mTrackList.getMaxScrollAmount();
- //Make sure there is at least one song in the sdcard
- if (scrollCount != -1) {
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- } else {
- assertTrue("testPlayMP3", false);
- }
- Thread.sleep(PLAY_TIME);
- } catch (Exception e) {
- assertTrue("testPlayMP3", false);
- }
- }
-
- @LargeTest
- public void testLaunchMusicPlayer() throws Exception {
- // Launch music player and sleep for 30 seconds to capture
- // the music player power usage base line.
- try {
- Thread.sleep(PLAY_TIME);
- } catch (Exception e) {
- assertTrue("MusicPlayer Do Nothing", false);
- }
- assertTrue("MusicPlayer Do Nothing", true);
- }
-}
diff --git a/tests/src/com/android/music/MusicPlayerStressTestRunner.java b/tests/src/com/android/music/MusicPlayerStressTestRunner.java
deleted file mode 100644
index 269627d..0000000
--- a/tests/src/com/android/music/MusicPlayerStressTestRunner.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.music.tests;
-
-import com.android.music.tests.stress.AlbumsPlaybackStress;
-import com.android.music.tests.stress.MusicPlaybackStress;
-
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-
-import junit.framework.TestSuite;
-
-/**
- * Instrumentation Test Runner for all music player stress tests.
- *
- * Running all tests:
- *
- * adb shell am instrument \
- * -w com.android.music.tests/.MusicPlayerStressTestRunner
- */
-
-public class MusicPlayerStressTestRunner extends InstrumentationTestRunner {
-
- @Override
- public TestSuite getAllTests() {
- TestSuite suite = new InstrumentationTestSuite(this);
- //suite.addTestSuite(MusicPlaybackStress.class);
- suite.addTestSuite(AlbumsPlaybackStress.class);
- return suite;
- }
-
- @Override
- public ClassLoader getLoader() {
- return MusicPlayerStressTestRunner.class.getClassLoader();
- }
-}
-
diff --git a/tests/src/com/android/music/functional/TestPlaylist.java b/tests/src/com/android/music/functional/TestPlaylist.java
deleted file mode 100644
index e751eb1..0000000
--- a/tests/src/com/android/music/functional/TestPlaylist.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.tests.functional;
-
-import android.app.Activity;
-import android.content.*;
-import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.content.Intent;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.provider.MediaStore;
-import android.content.ContentResolver;
-import android.database.Cursor;
-
-import com.android.music.MusicUtils;
-import com.android.music.PlaylistBrowserActivity;
-import com.android.music.TrackBrowserActivity;
-
-import com.android.music.tests.MusicPlayerNames;
-import com.android.music.tests.functional.TestSongs;
-
-/**
- * Junit / Instrumentation test case for the PlaylistBrowserActivity
- * This test case need to run in the landscape mode and opened keyboard
- */
-public class TestPlaylist extends ActivityInstrumentationTestCase<PlaylistBrowserActivity> {
- private static String TAG = "musicplayertests";
-
- public TestPlaylist() {
- super("com.android.music", PlaylistBrowserActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- private void clearSearchString(int length) {
- Instrumentation inst = getInstrumentation();
- for (int j = 0; j < length; j++) {
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DEL);
- }
- }
-
- /**
- * Remove playlist
- */
- public void deletePlaylist(String playlistname) throws Exception {
- Instrumentation inst = getInstrumentation();
- inst.sendStringSync(playlistname);
- Thread.sleep(MusicPlayerNames.WAIT_SHORT_TIME);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.invokeContextMenuAction(getActivity(), 0 + 1, 0);
- Thread.sleep(MusicPlayerNames.WAIT_SHORT_TIME);
- clearSearchString(playlistname.length());
- }
-
- /**
- * Start the trackBrowserActivity and add the new playlist
- */
- public void addNewPlaylist(String playListName) throws Exception {
- Instrumentation inst = getInstrumentation();
- Activity trackBrowserActivity;
- ActivityMonitor trackBrowserMon =
- inst.addMonitor("com.android.music.TrackBrowserActivity", null, false);
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_PICK);
- intent.setClassName("com.android.music", "com.android.music.TrackBrowserActivity");
- getActivity().startActivity(intent);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- trackBrowserActivity = trackBrowserMon.waitForActivityWithTimeout(2000);
- inst.invokeContextMenuAction(trackBrowserActivity, 0, 0);
- Thread.sleep(MusicPlayerNames.WAIT_SHORT_TIME);
- //Remove the default playlist name
- clearSearchString(MusicPlayerNames.DEFAULT_PLAYLIST_LENGTH);
- inst.sendStringSync(playListName);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- trackBrowserActivity.finish();
- clearSearchString(playListName.length());
-
- }
-
- /**
- * Rename playlist
- */
- public void renamePlaylist(String oldPlaylistName, String newPlaylistName) throws Exception {
- Instrumentation inst = getInstrumentation();
- inst.sendStringSync(oldPlaylistName);
- Thread.sleep(MusicPlayerNames.WAIT_SHORT_TIME);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.invokeContextMenuAction(getActivity(), 0 + 3, 0);
- Thread.sleep(MusicPlayerNames.WAIT_SHORT_TIME);
- //Remove the old playlist name
- clearSearchString(oldPlaylistName.length());
- inst.sendStringSync(newPlaylistName);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- clearSearchString(oldPlaylistName.length());
- }
-
- public boolean verifyPlaylist(String playlistname) throws Exception {
- Cursor mCursor;
- boolean isEmptyPlaylist = true;
- String[] cols = new String[] {MediaStore.Audio.Playlists.NAME};
- ContentResolver resolver = getActivity().getContentResolver();
- if (resolver == null) {
- System.out.println("resolver = null");
- assertNull(TAG, resolver);
- } else {
- String whereclause = MediaStore.Audio.Playlists.NAME + " = '" + playlistname + "'";
- mCursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
- cols, whereclause, null,
- MediaStore.Audio.Playlists.NAME);
- isEmptyPlaylist = mCursor.moveToFirst();
- }
- return isEmptyPlaylist;
- }
-
- /**
- * Test case 1: Add a playlist and delet the playlist just added.
- * Verification: The mediastore playlist should be empty
- */
- @LargeTest
- public void testDeletePlaylist() throws Exception {
- boolean isEmptyPlaylist = true;
- addNewPlaylist(MusicPlayerNames.DELETE_PLAYLIST_NAME);
- deletePlaylist(MusicPlayerNames.DELETE_PLAYLIST_NAME);
- isEmptyPlaylist = verifyPlaylist(MusicPlayerNames.DELETE_PLAYLIST_NAME);
- assertFalse("testDeletePlaylist", isEmptyPlaylist);
- }
-
- /**
- * Test case 2: Add playlist and rename the playlist just added.
- * Verification: The mediastore playlist should contain the updated name.
- */
- @LargeTest
- public void testRenamePlaylist() throws Exception {
- boolean isEmptyPlaylist = true;
- addNewPlaylist(MusicPlayerNames.ORIGINAL_PLAYLIST_NAME);
- renamePlaylist(
- MusicPlayerNames.ORIGINAL_PLAYLIST_NAME, MusicPlayerNames.RENAMED_PLAYLIST_NAME);
- isEmptyPlaylist = verifyPlaylist(MusicPlayerNames.RENAMED_PLAYLIST_NAME);
- deletePlaylist(MusicPlayerNames.RENAMED_PLAYLIST_NAME);
- assertTrue("testDeletePlaylist", isEmptyPlaylist);
- }
-}
diff --git a/tests/src/com/android/music/functional/TestSongs.java b/tests/src/com/android/music/functional/TestSongs.java
deleted file mode 100644
index 8bb2875..0000000
--- a/tests/src/com/android/music/functional/TestSongs.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.music.tests.functional;
-
-import android.app.Activity;
-import android.content.*;
-import android.app.Instrumentation;
-import android.content.Intent;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.content.ContentResolver;
-import android.content.pm.ActivityInfo;
-import android.database.Cursor;
-import android.content.Intent;
-import android.content.BroadcastReceiver;
-import android.content.IntentFilter;
-
-import com.android.music.TrackBrowserActivity;
-import com.android.music.MusicUtils;
-
-import com.android.music.tests.MusicPlayerNames;
-
-import java.io.*;
-
-/**
- * Junit / Instrumentation test case for the TrackBrowserActivity
- */
-public class TestSongs extends ActivityInstrumentationTestCase<TrackBrowserActivity> {
- private static String TAG = "musicplayertests";
-
- public TestSongs() {
- super("com.android.music", TrackBrowserActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- /**
- * Add 10 new playlists with unsorted title order
- */
- public void addNewPlaylist() throws Exception {
- Instrumentation inst = getInstrumentation();
- for (int i = 0; i < MusicPlayerNames.NO_OF_PLAYLIST; i++) {
- inst.invokeContextMenuAction(getActivity(), 0, 0);
- Thread.sleep(MusicPlayerNames.WAIT_SHORT_TIME);
- // Remove the default playlist name
- for (int j = 0; j < MusicPlayerNames.DEFAULT_PLAYLIST_LENGTH; j++) {
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DEL);
- }
- inst.sendStringSync(MusicPlayerNames.unsortedPlaylistTitle[i]);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- }
- }
-
- private void copy(File src, File dst) throws IOException {
- InputStream in = new FileInputStream(src);
- OutputStream out = new FileOutputStream(dst);
-
- // Transfer bytes from in to out
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0) {
- out.write(buf, 0, len);
- }
- in.close();
- out.close();
- Log.v(TAG, "Copy file");
- }
-
- // Rescan the sdcard after copy the file
- private void rescanSdcard() throws Exception {
- Intent scanIntent = new Intent(Intent.ACTION_MEDIA_MOUNTED,
- Uri.parse("file://" + Environment.getExternalStorageDirectory()));
- Log.v(TAG, "start the intent");
- IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
- intentFilter.addDataScheme("file");
- getActivity().sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
- Uri.parse("file://" + Environment.getExternalStorageDirectory())));
- Thread.sleep(MusicPlayerNames.WAIT_VERY_LONG_TIME);
- }
-
- /**
- * Test case 1: tests the new playlist added with sorted order.
- * Verification: The new playlist title should be sorted in alphabetical order
- */
- @LargeTest
- public void testAddPlaylist() throws Exception {
- Cursor mCursor;
- addNewPlaylist();
-
- // Verify the new playlist is created, check the playlist table
- String[] cols = new String[] {MediaStore.Audio.Playlists.NAME};
- ContentResolver resolver = getActivity().getContentResolver();
- if (resolver == null) {
- System.out.println("resolver = null");
- } else {
- String whereclause = MediaStore.Audio.Playlists.NAME + " != ''";
- mCursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI, cols,
- whereclause, null, MediaStore.Audio.Playlists.NAME);
- // Check the new playlist
- mCursor.moveToFirst();
-
- for (int j = 0; j < 10; j++) {
- assertEquals("New sorted Playlist title:",
- MusicPlayerNames.expectedPlaylistTitle[j], mCursor.getString(0));
- mCursor.moveToNext();
- }
- }
- }
-
- /**
- * Test case 2: Set a song as ringtone
- * Test case precondition: The testing device should wipe data before
- * run the test case.
- * Verification: The count of audio.media.is_ringtone equal to 1.
- */
- @LargeTest
- public void testSetRingtone() throws Exception {
- Cursor mCursor;
- Instrumentation inst = getInstrumentation();
- inst.invokeContextMenuAction(getActivity(), 0, 0);
- // This only check if there only 1 ringtone set in music player
- ContentResolver resolver = getActivity().getContentResolver();
- if (resolver == null) {
- System.out.println("resolver = null");
- } else {
- String whereclause = MediaStore.Audio.Media.IS_RINGTONE + " = 1";
- mCursor = resolver.query(
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, whereclause, null, null);
- // Check the new playlist
- mCursor.moveToFirst();
- int isRingtoneSet = mCursor.getCount();
- assertEquals(TAG, MusicPlayerNames.EXPECTED_NO_RINGTONE, isRingtoneSet);
- }
- }
-
- /**
- * Test case 3: Delete a song
- * Test case precondition: Copy a song and rescan the sdcard
- * Verification: The song is deleted from the sdcard and mediastore
- */
- @LargeTest
- public void testDeleteSong() throws Exception {
- Instrumentation inst = getInstrumentation();
- Cursor mCursor;
-
- // Copy a song from the golden directory
- Log.v(TAG, "Copy a temp file to the sdcard");
- File goldenfile = new File(MusicPlayerNames.GOLDENSONG);
- File toBeDeleteSong = new File(MusicPlayerNames.DELETESONG);
- copy(goldenfile, toBeDeleteSong);
- rescanSdcard();
-
- // Delete the file from music player
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- inst.sendStringSync(MusicPlayerNames.TOBEDELETESONGNAME);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- inst.invokeContextMenuAction(getActivity(), 0, 0);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
-
- // Clear the search string
- for (int j = 0; j < MusicPlayerNames.TOBEDELETESONGNAME.length(); j++) {
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DEL);
- }
-
- // Verfiy the item is removed from sdcard
- File checkDeletedFile = new File(MusicPlayerNames.DELETESONG);
- assertFalse(TAG, checkDeletedFile.exists());
-
- ContentResolver resolver = getActivity().getContentResolver();
- if (resolver == null) {
- System.out.println("resolver = null");
- } else {
- String whereclause = MediaStore.Audio.Media.DISPLAY_NAME + " = '"
- + MusicPlayerNames.TOBEDELETESONGNAME + "'";
- mCursor = resolver.query(
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, whereclause, null, null);
- boolean isEmptyCursor = mCursor.moveToFirst();
- assertFalse(TAG, isEmptyCursor);
- }
- }
-}
diff --git a/tests/src/com/android/music/stress/AlbumsPlaybackStress.java b/tests/src/com/android/music/stress/AlbumsPlaybackStress.java
deleted file mode 100644
index 46e1d9f..0000000
--- a/tests/src/com/android/music/stress/AlbumsPlaybackStress.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.music.tests.stress;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.util.Log;
-
-import com.android.music.AlbumBrowserActivity;
-import com.android.music.tests.MusicPlayerNames;
-
-public class AlbumsPlaybackStress extends ActivityInstrumentationTestCase <AlbumBrowserActivity>{
-
- private Activity browseActivity;
- private String[] testing;
- private String TAG = "AlbumsPlaybackStress";
-
- public AlbumsPlaybackStress() {
- super("com.android.music",AlbumBrowserActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- /*
- * Test case: Keeps launching music playback from Albums and then go
- * back to the album screen
- * Verification: Check if it is in low memory
- * The test depends on the test media in the sdcard
- */
- @LargeTest
- public void testAlbumPlay() {
- Instrumentation inst = getInstrumentation();
- try{
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_RIGHT);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_RIGHT);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- for(int i=0; i< MusicPlayerNames.NO_ALBUMS_TOBE_PLAYED; i++){
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
- }
- }catch (Exception e){
- Log.v(TAG, e.toString());
- }
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK);
-
- //Verification: check if it is in low memory
- ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
- ((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(mi);
- assertFalse(TAG, mi.lowMemory);
-
-
- }
-}
diff --git a/tests/src/com/android/music/stress/MusicPlaybackStress.java b/tests/src/com/android/music/stress/MusicPlaybackStress.java
deleted file mode 100644
index 10afd9d..0000000
--- a/tests/src/com/android/music/stress/MusicPlaybackStress.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.music.tests.stress;
-
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.Instrumentation;
-import android.app.Instrumentation.ActivityMonitor;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.KeyEvent;
-import android.util.Log;
-import android.content.Context;
-
-
-import com.android.music.MusicBrowserActivity;
-import com.android.music.MusicUtils;
-import com.android.music.TrackBrowserActivity;
-import com.android.music.tests.MusicPlayerNames;
-
-public class MusicPlaybackStress extends ActivityInstrumentationTestCase<TrackBrowserActivity> {
- private static String TAG = "mediaplayertests";
-
- public MusicPlaybackStress() {
- super("com.android.music", TrackBrowserActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- @LargeTest
- public void testPlayAllSongs() {
- Activity mediaPlaybackActivity;
- try {
- Instrumentation inst = getInstrumentation();
- ActivityMonitor mediaPlaybackMon =
- inst.addMonitor("com.android.music.MediaPlaybackActivity", null, false);
- inst.invokeMenuActionSync(getActivity(), 0 + 3, 0);
- Thread.sleep(MusicPlayerNames.WAIT_LONG_TIME);
- mediaPlaybackActivity = mediaPlaybackMon.waitForActivityWithTimeout(2000);
- for (int i = 0; i < MusicPlayerNames.NO_SKIPPING_SONGS; i++) {
- Thread.sleep(MusicPlayerNames.SKIP_WAIT_TIME);
- if (i == 0) {
- // Set the repeat all
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_RIGHT);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP);
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
-
- // Set focus on the next button
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
- }
- inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
- }
- mediaPlaybackActivity.finish();
- } catch (Exception e) {
- Log.e(TAG, e.toString());
- }
- // Verification: check if it is in low memory
- ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
- ((ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE))
- .getMemoryInfo(mi);
- assertFalse(TAG, mi.lowMemory);
- }
-}