1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.music; 18 19 import android.app.ListActivity; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.graphics.Bitmap; 25 import android.graphics.BitmapFactory; 26 import android.graphics.drawable.BitmapDrawable; 27 import android.graphics.drawable.Drawable; 28 import android.media.AudioManager; 29 import android.media.MediaDescription; 30 import android.media.MediaMetadata; 31 import android.media.browse.MediaBrowser; 32 import android.media.session.MediaController; 33 import android.media.session.MediaSession; 34 import android.media.session.PlaybackState; 35 import android.net.Uri; 36 import android.os.Bundle; 37 import android.util.Log; 38 import android.view.LayoutInflater; 39 import android.view.View; 40 import android.view.ViewGroup; 41 import android.view.Window; 42 import android.widget.*; 43 import com.android.music.utils.LogHelper; 44 import com.android.music.utils.MediaIDHelper; 45 import com.android.music.utils.Playback; 46 47 import java.util.ArrayList; 48 import java.util.List; 49 50 /* 51 This activity is the albums browsing tab 52 */ 53 public class AlbumBrowserActivity extends ListActivity { 54 private static final String TAG = LogHelper.makeLogTag(AlbumBrowserActivity.class); 55 private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM = 56 new MediaBrowser.MediaItem(new MediaDescription.Builder() 57 .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM) 58 .build(), 59 MediaBrowser.MediaItem.FLAG_BROWSABLE); 60 61 private ListView mAlbumList; 62 private AlbumBrowseAdapter mBrowseListAdapter; 63 private MediaBrowser mMediaBrowser; 64 private MediaBrowser.MediaItem mParentItem; 65 66 /** Called when the activity is first created. */ 67 @Override 68 public void onCreate(Bundle icicle) { 69 Log.d(TAG, "onCreate()"); 70 super.onCreate(icicle); 71 if (icicle != null) { 72 mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM); 73 } else if (getIntent() != null) { 74 mParentItem = getIntent().getExtras().getParcelable(MusicUtils.TAG_PARENT_ITEM); 75 } 76 if (mParentItem == null) { 77 mParentItem = DEFAULT_PARENT_ITEM; 78 } 79 requestWindowFeature(Window.FEATURE_NO_TITLE); 80 setVolumeControlStream(AudioManager.STREAM_MUSIC); 81 82 setContentView(R.layout.media_picker_activity); 83 MusicUtils.updateButtonBar(this, R.id.albumtab); 84 mAlbumList = getListView(); 85 mAlbumList.setOnCreateContextMenuListener(this); 86 mAlbumList.setTextFilterEnabled(true); 87 88 mBrowseListAdapter = (AlbumBrowseAdapter) getLastNonConfigurationInstance(); 89 if (mBrowseListAdapter == null) { 90 // Log.i("@@@", "starting query"); 91 mBrowseListAdapter = new AlbumBrowseAdapter(this, R.layout.track_list_item); 92 setTitle(R.string.working_albums); 93 } 94 setListAdapter(mBrowseListAdapter); 95 Log.d(TAG, "Creating MediaBrowser"); 96 mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class), 97 mConnectionCallback, null); 98 } 99 100 @Override 101 public void onDestroy() { 102 Log.d(TAG, "onDestroy()"); 103 ListView lv = getListView(); 104 // Because we pass the adapter to the next activity, we need to make 105 // sure it doesn't keep a reference to this activity. We can do this 106 // by clearing its DatasetObservers, which setListAdapter(null) does. 107 setListAdapter(null); 108 mBrowseListAdapter = null; 109 super.onDestroy(); 110 } 111 112 @Override 113 public void onResume() { 114 Log.d(TAG, "onResume()"); 115 super.onResume(); 116 } 117 118 @Override 119 public void onStart() { 120 Log.d(TAG, "onStart()"); 121 super.onStart(); 122 mMediaBrowser.connect(); 123 } 124 125 @Override 126 public void onStop() { 127 Log.d(TAG, "onStop()"); 128 super.onStop(); 129 mMediaBrowser.disconnect(); 130 } 131 132 @Override 133 public void onPause() { 134 Log.d(TAG, "onPause()"); 135 super.onPause(); 136 } 137 138 @Override 139 public void onSaveInstanceState(Bundle outcicle) { 140 outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem); 141 super.onSaveInstanceState(outcicle); 142 } 143 144 private void setTitle() { 145 CharSequence fancyName = ""; 146 setTitle(R.string.albums_title); 147 } 148 149 private MediaBrowser.SubscriptionCallback mSubscriptionCallback = 150 new MediaBrowser.SubscriptionCallback() { 151 152 @Override 153 public void onChildrenLoaded( 154 String parentId, List<MediaBrowser.MediaItem> children) { 155 mBrowseListAdapter.clear(); 156 mBrowseListAdapter.notifyDataSetInvalidated(); 157 for (MediaBrowser.MediaItem item : children) { 158 mBrowseListAdapter.add(item); 159 } 160 mBrowseListAdapter.notifyDataSetChanged(); 161 } 162 163 @Override 164 public void onError(String id) { 165 Toast.makeText(getApplicationContext(), R.string.error_loading_media, 166 Toast.LENGTH_LONG) 167 .show(); 168 } 169 }; 170 171 private MediaBrowser.ConnectionCallback mConnectionCallback = 172 new MediaBrowser.ConnectionCallback() { 173 @Override 174 public void onConnected() { 175 Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken()); 176 mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback); 177 if (mMediaBrowser.getSessionToken() == null) { 178 throw new IllegalArgumentException("No Session token"); 179 } 180 MediaController mediaController = new MediaController( 181 AlbumBrowserActivity.this, mMediaBrowser.getSessionToken()); 182 mediaController.registerCallback(mMediaControllerCallback); 183 AlbumBrowserActivity.this.setMediaController(mediaController); 184 if (mediaController.getMetadata() != null) { 185 MusicUtils.updateNowPlaying(AlbumBrowserActivity.this); 186 } 187 } 188 189 @Override 190 public void onConnectionFailed() { 191 Log.d(TAG, "onConnectionFailed"); 192 } 193 194 @Override 195 public void onConnectionSuspended() { 196 Log.d(TAG, "onConnectionSuspended"); 197 AlbumBrowserActivity.this.setMediaController(null); 198 } 199 }; 200 201 private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { 202 @Override 203 public void onMetadataChanged(MediaMetadata metadata) { 204 super.onMetadataChanged(metadata); 205 MusicUtils.updateNowPlaying(AlbumBrowserActivity.this); 206 if (mBrowseListAdapter != null) { 207 mBrowseListAdapter.notifyDataSetChanged(); 208 } 209 } 210 }; 211 212 // An adapter for showing the list of browsed MediaItem's 213 private class AlbumBrowseAdapter extends ArrayAdapter<MediaBrowser.MediaItem> { 214 private final Drawable mNowPlayingOverlay; 215 private final BitmapDrawable mDefaultAlbumIcon; 216 private int mLayoutId; 217 218 private class ViewHolder { 219 TextView line1; 220 TextView line2; 221 ImageView play_indicator; 222 ImageView icon; 223 } 224 225 AlbumBrowseAdapter(Context context, int layout) { 226 super(context, layout, new ArrayList<>()); 227 mNowPlayingOverlay = context.getResources().getDrawable( 228 R.drawable.indicator_ic_mp_playing_list, context.getTheme()); 229 Bitmap b = BitmapFactory.decodeResource( 230 context.getResources(), R.drawable.albumart_mp_unknown_list); 231 mDefaultAlbumIcon = new BitmapDrawable(context.getResources(), b); 232 // no filter or dither, it's a lot faster and we can't tell the difference 233 mDefaultAlbumIcon.setFilterBitmap(false); 234 mDefaultAlbumIcon.setDither(false); 235 mLayoutId = layout; 236 } 237 238 @Override 239 public View getView(int position, View convertView, ViewGroup parent) { 240 Log.d(TAG, "getView()"); 241 if (convertView == null) { 242 convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false); 243 ViewHolder vh = new ViewHolder(); 244 vh.line1 = (TextView) convertView.findViewById(R.id.line1); 245 vh.line2 = (TextView) convertView.findViewById(R.id.line2); 246 vh.play_indicator = (ImageView) convertView.findViewById(R.id.play_indicator); 247 vh.icon = (ImageView) convertView.findViewById(R.id.icon); 248 vh.icon.setBackground(mDefaultAlbumIcon); 249 vh.icon.setPadding(0, 0, 1, 0); 250 vh.icon.setVisibility(View.VISIBLE); 251 convertView.setTag(vh); 252 } 253 ViewHolder vh = (ViewHolder) convertView.getTag(); 254 MediaBrowser.MediaItem item = getItem(position); 255 Log.d(TAG, "Album: " + item.getDescription().getTitle()); 256 vh.line1.setText(item.getDescription().getTitle()); 257 Log.d(TAG, "Artist: " + item.getDescription().getSubtitle()); 258 vh.line2.setText(item.getDescription().getSubtitle()); 259 Bitmap albumArt = item.getDescription().getIconBitmap(); 260 LogHelper.d(TAG, "looking for album art"); 261 if (albumArt != null) { 262 vh.icon.setImageDrawable(MusicUtils.getDrawableBitmap(albumArt, mDefaultAlbumIcon)); 263 } else { 264 vh.icon.setImageDrawable(mDefaultAlbumIcon); 265 } 266 MediaController mediaController = AlbumBrowserActivity.this.getMediaController(); 267 if (mediaController == null) { 268 vh.play_indicator.setImageDrawable(null); 269 return convertView; 270 } 271 MediaMetadata metadata = mediaController.getMetadata(); 272 if (metadata == null) { 273 vh.play_indicator.setImageDrawable(null); 274 return convertView; 275 } 276 if (metadata.getString(MediaMetadata.METADATA_KEY_ALBUM) 277 .equals(item.getDescription().getTitle())) { 278 vh.play_indicator.setImageDrawable(mNowPlayingOverlay); 279 } else { 280 vh.play_indicator.setImageDrawable(null); 281 } 282 return convertView; 283 } 284 } 285 286 @Override 287 protected void onListItemClick(ListView l, View v, int position, long id) { 288 Log.d(TAG, "onListItemClick at position " + position + ", id " + id); 289 MediaBrowser.MediaItem item = mBrowseListAdapter.getItem(position); 290 if (item.isBrowsable()) { 291 Intent intent = new Intent(Intent.ACTION_PICK); 292 intent.setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track"); 293 intent.putExtra(MusicUtils.TAG_PARENT_ITEM, item); 294 intent.putExtra(MusicUtils.TAG_WITH_TABS, false); 295 startActivity(intent); 296 } 297 } 298 } 299