Home | History | Annotate | Download | only in mediabrowserservice
      1 /*
      2  * Copyright (C) 2014 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 package com.example.android.mediabrowserservice;
     17 
     18 import android.content.ComponentName;
     19 import android.content.Context;
     20 import android.os.Bundle;
     21 import android.os.RemoteException;
     22 import android.support.annotation.NonNull;
     23 import android.support.annotation.Nullable;
     24 import android.support.v4.app.Fragment;
     25 import android.support.v4.media.MediaBrowserCompat;
     26 import android.support.v4.media.MediaMetadataCompat;
     27 import android.support.v4.media.session.MediaControllerCompat;
     28 import android.support.v4.media.session.PlaybackStateCompat;
     29 import android.util.Log;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.AdapterView;
     34 import android.widget.ArrayAdapter;
     35 import android.widget.ImageView;
     36 import android.widget.ListView;
     37 import android.widget.TextView;
     38 import android.widget.Toast;
     39 
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 
     43 /**
     44  * A Fragment that lists all the various browsable queues available
     45  * from a {@link android.service.media.MediaBrowserService}.
     46  * <p/>
     47  * It uses a {@link MediaBrowserCompat} to connect to the {@link MusicService}. Once connected,
     48  * the fragment subscribes to get all the children. All {@link MediaBrowserCompat.MediaItem}'s
     49  * that can be browsed are shown in a ListView.
     50  */
     51 public class BrowseFragment extends Fragment {
     52 
     53     private static final String TAG = BrowseFragment.class.getSimpleName();
     54 
     55     public static final String ARG_MEDIA_ID = "media_id";
     56 
     57     /**
     58      * Interface between BrowseFragment and MusicPlayerActivity.
     59      */
     60     public interface FragmentDataHelper {
     61         void onMediaItemSelected(MediaBrowserCompat.MediaItem item, boolean isPlaying);
     62     }
     63 
     64     // The mediaId to be used for subscribing for children using the MediaBrowser.
     65     private String mMediaId;
     66 
     67     private MediaBrowserCompat mMediaBrowser;
     68     private BrowseAdapter mBrowserAdapter;
     69 
     70     private MediaBrowserCompat.SubscriptionCallback mSubscriptionCallback =
     71             new MediaBrowserCompat.SubscriptionCallback() {
     72 
     73                 @Override
     74                 public void onChildrenLoaded(String parentId,
     75                                              List<MediaBrowserCompat.MediaItem> children) {
     76                     mBrowserAdapter.clear();
     77                     mBrowserAdapter.notifyDataSetInvalidated();
     78                     for (MediaBrowserCompat.MediaItem item : children) {
     79                         mBrowserAdapter.add(item);
     80                     }
     81                     mBrowserAdapter.notifyDataSetChanged();
     82                 }
     83 
     84                 @Override
     85                 public void onError(String id) {
     86                     Toast.makeText(getActivity(), R.string.error_loading_media,
     87                             Toast.LENGTH_LONG).show();
     88                 }
     89             };
     90 
     91     private MediaBrowserCompat.ConnectionCallback mConnectionCallback =
     92             new MediaBrowserCompat.ConnectionCallback() {
     93                 @Override
     94                 public void onConnected() {
     95                     Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
     96 
     97                     if (mMediaId == null) {
     98                         mMediaId = mMediaBrowser.getRoot();
     99                     }
    100                     mMediaBrowser.subscribe(mMediaId, mSubscriptionCallback);
    101                     try {
    102                         MediaControllerCompat mediaController =
    103                                 new MediaControllerCompat(getActivity(),
    104                                         mMediaBrowser.getSessionToken());
    105                         MediaControllerCompat.setMediaController(getActivity(), mediaController);
    106 
    107                         // Register a Callback to stay in sync
    108                         mediaController.registerCallback(mControllerCallback);
    109                     } catch (RemoteException e) {
    110                         Log.e(TAG, "Failed to connect to MediaController", e);
    111                     }
    112                 }
    113 
    114                 @Override
    115                 public void onConnectionFailed() {
    116                     Log.e(TAG, "onConnectionFailed");
    117                 }
    118 
    119                 @Override
    120                 public void onConnectionSuspended() {
    121                     Log.d(TAG, "onConnectionSuspended");
    122                     MediaControllerCompat mediaController = MediaControllerCompat
    123                             .getMediaController(getActivity());
    124                     if (mediaController != null) {
    125                         mediaController.unregisterCallback(mControllerCallback);
    126                         MediaControllerCompat.setMediaController(getActivity(), null);
    127                     }
    128                 }
    129             };
    130 
    131     private MediaControllerCompat.Callback mControllerCallback =
    132             new MediaControllerCompat.Callback() {
    133                 @Override
    134                 public void onMetadataChanged(MediaMetadataCompat metadata) {
    135                     if (metadata != null) {
    136                         mBrowserAdapter.setCurrentMediaMetadata(metadata);
    137                     }
    138                 }
    139 
    140                 @Override
    141                 public void onPlaybackStateChanged(PlaybackStateCompat state) {
    142                     mBrowserAdapter.setPlaybackState(state);
    143                     mBrowserAdapter.notifyDataSetChanged();
    144                 }
    145             };
    146 
    147     public static BrowseFragment newInstance(String mediaId) {
    148         Bundle args = new Bundle();
    149         args.putString(ARG_MEDIA_ID, mediaId);
    150         BrowseFragment fragment = new BrowseFragment();
    151         fragment.setArguments(args);
    152         return fragment;
    153     }
    154 
    155     @Override
    156     public View onCreateView(LayoutInflater inflater, ViewGroup container,
    157                              Bundle savedInstanceState) {
    158         View rootView = inflater.inflate(R.layout.fragment_list, container, false);
    159 
    160         mBrowserAdapter = new BrowseAdapter(getActivity());
    161 
    162         ListView listView = (ListView) rootView.findViewById(R.id.list_view);
    163         listView.setAdapter(mBrowserAdapter);
    164         listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    165             @Override
    166             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    167                 MediaBrowserCompat.MediaItem item = mBrowserAdapter.getItem(position);
    168                 boolean isPlaying = item.getMediaId().equals(mBrowserAdapter.getPlayingMediaId());
    169                 try {
    170                     FragmentDataHelper listener = (FragmentDataHelper) getActivity();
    171                     listener.onMediaItemSelected(item, isPlaying);
    172                 } catch (ClassCastException ex) {
    173                     Log.e(TAG, "Exception trying to cast to FragmentDataHelper", ex);
    174                 }
    175             }
    176         });
    177 
    178         Bundle args = getArguments();
    179         mMediaId = args.getString(ARG_MEDIA_ID, null);
    180 
    181         mMediaBrowser = new MediaBrowserCompat(getActivity(),
    182                 new ComponentName(getActivity(), MusicService.class),
    183                 mConnectionCallback, null);
    184 
    185         return rootView;
    186     }
    187 
    188     @Override
    189     public void onStart() {
    190         super.onStart();
    191         mMediaBrowser.connect();
    192     }
    193 
    194     @Override
    195     public void onStop() {
    196         super.onStop();
    197         mMediaBrowser.disconnect();
    198     }
    199 
    200     // An adapter for showing the list of browsed MediaItem's
    201     private static class BrowseAdapter extends ArrayAdapter<MediaBrowserCompat.MediaItem> {
    202         private String mCurrentMediaId;
    203         private PlaybackStateCompat mPlaybackState;
    204 
    205         public BrowseAdapter(Context context) {
    206             super(context, R.layout.media_list_item, new ArrayList<MediaBrowserCompat.MediaItem>());
    207         }
    208 
    209         @Nullable
    210         public String getPlayingMediaId() {
    211             boolean isPlaying = mPlaybackState != null
    212                     && mPlaybackState.getState() == PlaybackStateCompat.STATE_PLAYING;
    213             return isPlaying ? mCurrentMediaId : null;
    214         }
    215 
    216         private void setCurrentMediaMetadata(MediaMetadataCompat mediaMetadata) {
    217             mCurrentMediaId = mediaMetadata != null
    218                     ? mediaMetadata.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID)
    219                     : null;
    220         }
    221 
    222         private void setPlaybackState(PlaybackStateCompat playbackState) {
    223             mPlaybackState = playbackState;
    224         }
    225 
    226         static class ViewHolder {
    227             ImageView mImageView;
    228             TextView mTitleView;
    229             TextView mDescriptionView;
    230         }
    231 
    232         @NonNull
    233         @Override
    234         public View getView(int position, View convertView, @NonNull ViewGroup parent) {
    235 
    236             ViewHolder holder;
    237 
    238             if (convertView == null) {
    239                 convertView = LayoutInflater.from(getContext())
    240                         .inflate(R.layout.media_list_item, parent, false);
    241                 holder = new ViewHolder();
    242                 holder.mImageView = (ImageView) convertView.findViewById(R.id.play_eq);
    243                 holder.mImageView.setVisibility(View.GONE);
    244                 holder.mTitleView = (TextView) convertView.findViewById(R.id.title);
    245                 holder.mDescriptionView = (TextView) convertView.findViewById(R.id.description);
    246                 convertView.setTag(holder);
    247             } else {
    248                 holder = (ViewHolder) convertView.getTag();
    249             }
    250 
    251             MediaBrowserCompat.MediaItem item = getItem(position);
    252             holder.mTitleView.setText(item.getDescription().getTitle());
    253             holder.mDescriptionView.setText(item.getDescription().getDescription());
    254             if (item.isPlayable()) {
    255                 int playRes = item.getMediaId().equals(getPlayingMediaId())
    256                         ? R.drawable.ic_equalizer_white_24dp
    257                         : R.drawable.ic_play_arrow_white_24dp;
    258                 holder.mImageView.setImageDrawable(getContext().getResources()
    259                         .getDrawable(playRes));
    260                 holder.mImageView.setVisibility(View.VISIBLE);
    261             }
    262             return convertView;
    263         }
    264 
    265     }
    266 }
    267