• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Activity;
20 import android.app.ListActivity;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.graphics.Color;
25 import android.graphics.drawable.Drawable;
26 import android.media.AudioManager;
27 import android.media.MediaDescription;
28 import android.media.MediaMetadata;
29 import android.media.browse.MediaBrowser;
30 import android.media.session.MediaController;
31 import android.media.session.MediaSession;
32 import android.os.Bundle;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.view.Window;
38 import android.widget.*;
39 import com.android.music.utils.LogHelper;
40 import com.android.music.utils.MediaIDHelper;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 /*
46 This activity shows when there is a need for
47  1. Songs tab [withtab = true]
48  2. Browse songs within an album [withtab = false]
49  3. Browse songs within a playlist [withtab = false]
50  4. Browse songs within now playing queue [withtab = false]
51  */
52 public class TrackBrowserActivity extends ListActivity {
53     private static final String TAG = LogHelper.makeLogTag(TrackBrowserActivity.class);
54     private static final MediaBrowser.MediaItem DEFAULT_PARENT_ITEM =
55             new MediaBrowser.MediaItem(new MediaDescription.Builder()
56                                                .setMediaId(MediaIDHelper.MEDIA_ID_MUSICS_BY_SONG)
57                                                .setTitle("Songs")
58                                                .build(),
59                     MediaBrowser.MediaItem.FLAG_BROWSABLE);
60 
61     // Underlining ListView of this Activity
62     private ListView mTrackList;
63     // The mediaId to be used for subscribing for children using the MediaBrowser.
64     private MediaBrowser.MediaItem mParentItem;
65     private MediaBrowser mMediaBrowser;
66     private TrackBrowseAdapter mBrowseListAdapter;
67     private boolean mWithTabs;
68 
69     /**
70      * Called when the activity is first created.
71      */
72     @Override
onCreate(Bundle icicle)73     public void onCreate(Bundle icicle) {
74         Log.d(TAG, "onCreate()");
75         super.onCreate(icicle);
76         // Process past states
77         Intent intent = getIntent();
78         if (icicle != null) {
79             LogHelper.d(TAG, "Launch by saved instance state");
80             mParentItem = icicle.getParcelable(MusicUtils.TAG_PARENT_ITEM);
81             mWithTabs = icicle.getBoolean(MusicUtils.TAG_WITH_TABS);
82             MusicUtils.updateNowPlaying(this);
83         } else if (intent != null) {
84             LogHelper.d(TAG, "Launch by intent");
85             mParentItem = intent.getParcelableExtra(MusicUtils.TAG_PARENT_ITEM);
86             mWithTabs = intent.getBooleanExtra(MusicUtils.TAG_WITH_TABS, false);
87         }
88         if (mParentItem == null) {
89             LogHelper.d(TAG, "Launch by default parameters");
90             mParentItem = DEFAULT_PARENT_ITEM;
91             mWithTabs = true;
92         }
93         if (mWithTabs) {
94             requestWindowFeature(Window.FEATURE_NO_TITLE);
95         }
96         setTitle(mParentItem.getDescription().getTitle());
97         setVolumeControlStream(AudioManager.STREAM_MUSIC);
98 
99         // Init layout
100         LogHelper.d(TAG, "init layout");
101         setContentView(R.layout.media_picker_activity);
102         MusicUtils.updateButtonBar(this, R.id.songtab);
103 
104         // Init the ListView
105         Log.d(TAG, "Creating ListView");
106         mTrackList = getListView();
107         mTrackList.setCacheColorHint(0);
108         mTrackList.setTextFilterEnabled(true);
109         mBrowseListAdapter = (TrackBrowseAdapter) getLastNonConfigurationInstance();
110         if (mBrowseListAdapter == null) {
111             mBrowseListAdapter = new TrackBrowseAdapter(this, R.layout.track_list_item);
112         }
113         setListAdapter(mBrowseListAdapter);
114         // don't set the album art until after the view has been layed out
115         mTrackList.post(new Runnable() {
116             public void run() {
117                 mTrackList.setBackgroundColor(Color.WHITE);
118                 mTrackList.setCacheColorHint(0);
119             }
120         });
121 
122         // Create media browser
123         Log.d(TAG, "Creating MediaBrowser");
124         mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class),
125                 mConnectionCallback, null);
126     }
127 
128     @Override
onStart()129     public void onStart() {
130         Log.d(TAG, "onStart()");
131         super.onStart();
132         mMediaBrowser.connect();
133     }
134 
135     @Override
onStop()136     public void onStop() {
137         Log.d(TAG, "onStop()");
138         super.onStop();
139         mMediaBrowser.disconnect();
140     }
141 
142     @Override
onDestroy()143     public void onDestroy() {
144         Log.d(TAG, "onDestroy()");
145         ListView lv = getListView();
146         // Because we pass the adapter to the next activity, we need to make
147         // sure it doesn't keep a reference to this activity. We can do this
148         // by clearing its DatasetObservers, which setListAdapter(null) does.
149         setListAdapter(null);
150         mBrowseListAdapter = null;
151         super.onDestroy();
152     }
153 
154     @Override
onResume()155     public void onResume() {
156         Log.d(TAG, "onResume()");
157         super.onResume();
158     }
159 
160     @Override
onPause()161     public void onPause() {
162         Log.d(TAG, "onPause()");
163         super.onPause();
164     }
165 
166     @Override
onSaveInstanceState(Bundle outcicle)167     public void onSaveInstanceState(Bundle outcicle) {
168         outcicle.putParcelable(MusicUtils.TAG_PARENT_ITEM, mParentItem);
169         outcicle.putBoolean(MusicUtils.TAG_WITH_TABS, mWithTabs);
170         super.onSaveInstanceState(outcicle);
171     }
172 
173     private MediaBrowser.SubscriptionCallback mSubscriptionCallback =
174             new MediaBrowser.SubscriptionCallback() {
175 
176                 @Override
177                 public void onChildrenLoaded(
178                         String parentId, List<MediaBrowser.MediaItem> children) {
179                     mBrowseListAdapter.clear();
180                     mBrowseListAdapter.notifyDataSetInvalidated();
181                     for (MediaBrowser.MediaItem item : children) {
182                         mBrowseListAdapter.add(item);
183                     }
184                     mBrowseListAdapter.notifyDataSetChanged();
185                 }
186 
187                 @Override
188                 public void onError(String id) {
189                     Toast.makeText(getApplicationContext(), R.string.error_loading_media,
190                                  Toast.LENGTH_LONG)
191                             .show();
192                 }
193             };
194 
195     private MediaBrowser.ConnectionCallback mConnectionCallback =
196             new MediaBrowser.ConnectionCallback() {
197                 @Override
198                 public void onConnected() {
199                     Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
200                     mMediaBrowser.subscribe(mParentItem.getMediaId(), mSubscriptionCallback);
201                     if (mMediaBrowser.getSessionToken() == null) {
202                         throw new IllegalArgumentException("No Session token");
203                     }
204                     MediaController mediaController = new MediaController(
205                             TrackBrowserActivity.this, mMediaBrowser.getSessionToken());
206                     mediaController.registerCallback(mMediaControllerCallback);
207                     TrackBrowserActivity.this.setMediaController(mediaController);
208                     if (mediaController.getMetadata() != null && mWithTabs) {
209                         MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
210                     }
211                 }
212 
213                 @Override
214                 public void onConnectionFailed() {
215                     Log.d(TAG, "onConnectionFailed");
216                 }
217 
218                 @Override
219                 public void onConnectionSuspended() {
220                     Log.d(TAG, "onConnectionSuspended");
221                     TrackBrowserActivity.this.setMediaController(null);
222                 }
223             };
224 
225     private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
226         @Override
227         public void onMetadataChanged(MediaMetadata metadata) {
228             super.onMetadataChanged(metadata);
229             if (mWithTabs) {
230                 MusicUtils.updateNowPlaying(TrackBrowserActivity.this);
231             }
232             if (mBrowseListAdapter != null) {
233                 mBrowseListAdapter.notifyDataSetChanged();
234             }
235         }
236     };
237 
238     // An adapter for showing the list of browsed MediaItem's
239     private static class TrackBrowseAdapter extends ArrayAdapter<MediaBrowser.MediaItem> {
240         private int mLayoutId;
241         private final Drawable mNowPlayingOverlay;
242         private Activity mActivity;
243 
244         static class ViewHolder {
245             TextView line1;
246             TextView line2;
247             TextView duration;
248             ImageView play_indicator;
249         }
250 
TrackBrowseAdapter(Activity activity, int layout)251         TrackBrowseAdapter(Activity activity, int layout) {
252             super(activity, layout, new ArrayList<>());
253             mLayoutId = layout;
254             mNowPlayingOverlay = activity.getResources().getDrawable(
255                     R.drawable.indicator_ic_mp_playing_list, activity.getTheme());
256             mActivity = activity;
257         }
258 
259         @Override
getView(int position, View convertView, ViewGroup parent)260         public View getView(int position, View convertView, ViewGroup parent) {
261             Log.d(TAG, "getView()");
262             if (convertView == null) {
263                 convertView = LayoutInflater.from(getContext()).inflate(mLayoutId, parent, false);
264                 ImageView iv = (ImageView) convertView.findViewById(R.id.icon);
265                 iv.setVisibility(View.GONE);
266                 ViewHolder vh = new ViewHolder();
267                 vh.line1 = (TextView) convertView.findViewById(R.id.line1);
268                 vh.line2 = (TextView) convertView.findViewById(R.id.line2);
269                 vh.duration = (TextView) convertView.findViewById(R.id.duration);
270                 vh.play_indicator = (ImageView) convertView.findViewById(R.id.play_indicator);
271                 convertView.setTag(vh);
272             }
273             ViewHolder holder = (ViewHolder) convertView.getTag();
274             MediaBrowser.MediaItem item = getItem(position);
275             Log.d(TAG, "title: " + item.getDescription().getTitle());
276             holder.line1.setText(item.getDescription().getTitle());
277             Log.d(TAG, "artist: " + item.getDescription().getSubtitle());
278             holder.line2.setText(item.getDescription().getSubtitle());
279             long duration =
280                     item.getDescription().getExtras().getLong(MediaMetadata.METADATA_KEY_DURATION);
281             LogHelper.d(TAG, "duration: ", duration);
282             holder.duration.setText(MusicUtils.makeTimeString(getContext(), duration / 1000));
283             MediaController mediaController = mActivity.getMediaController();
284             if (mediaController == null) {
285                 holder.play_indicator.setImageDrawable(null);
286                 return convertView;
287             }
288             MediaMetadata metadata = mediaController.getMetadata();
289             if (metadata == null) {
290                 holder.play_indicator.setImageDrawable(null);
291                 return convertView;
292             }
293             if (item.getDescription().getMediaId().endsWith(
294                         metadata.getString(MediaMetadata.METADATA_KEY_MEDIA_ID))) {
295                 holder.play_indicator.setImageDrawable(mNowPlayingOverlay);
296             } else {
297                 holder.play_indicator.setImageDrawable(null);
298             }
299             return convertView;
300         }
301     }
302 
303     @Override
onRetainNonConfigurationInstance()304     public Object onRetainNonConfigurationInstance() {
305         TrackBrowseAdapter a = mBrowseListAdapter;
306         return a;
307     }
308 
309     @Override
onListItemClick(ListView l, View v, int position, long id)310     protected void onListItemClick(ListView l, View v, int position, long id) {
311         Log.d(TAG, "onListItemClick at position " + position + ", id " + id);
312         MediaBrowser.MediaItem item = mBrowseListAdapter.getItem(position);
313         if (item.isPlayable()) {
314             getMediaController().getTransportControls().playFromMediaId(item.getMediaId(), null);
315         }
316     }
317 }
318