1*90c8c64dSAndroid Build Coastguard Worker /*
2*90c8c64dSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker  *
4*90c8c64dSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker  *
8*90c8c64dSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker  *
10*90c8c64dSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker  * limitations under the License.
15*90c8c64dSAndroid Build Coastguard Worker  */
16*90c8c64dSAndroid Build Coastguard Worker package com.example.android.mediabrowserservice;
17*90c8c64dSAndroid Build Coastguard Worker 
18*90c8c64dSAndroid Build Coastguard Worker import android.app.Fragment;
19*90c8c64dSAndroid Build Coastguard Worker import android.content.ComponentName;
20*90c8c64dSAndroid Build Coastguard Worker import android.content.Context;
21*90c8c64dSAndroid Build Coastguard Worker import android.media.browse.MediaBrowser;
22*90c8c64dSAndroid Build Coastguard Worker import android.media.session.MediaController;
23*90c8c64dSAndroid Build Coastguard Worker import android.os.Bundle;
24*90c8c64dSAndroid Build Coastguard Worker import android.util.Log;
25*90c8c64dSAndroid Build Coastguard Worker import android.view.LayoutInflater;
26*90c8c64dSAndroid Build Coastguard Worker import android.view.View;
27*90c8c64dSAndroid Build Coastguard Worker import android.view.ViewGroup;
28*90c8c64dSAndroid Build Coastguard Worker import android.widget.AdapterView;
29*90c8c64dSAndroid Build Coastguard Worker import android.widget.ArrayAdapter;
30*90c8c64dSAndroid Build Coastguard Worker import android.widget.ImageView;
31*90c8c64dSAndroid Build Coastguard Worker import android.widget.ListView;
32*90c8c64dSAndroid Build Coastguard Worker import android.widget.TextView;
33*90c8c64dSAndroid Build Coastguard Worker import android.widget.Toast;
34*90c8c64dSAndroid Build Coastguard Worker 
35*90c8c64dSAndroid Build Coastguard Worker import com.example.android.mediabrowserservice.utils.LogHelper;
36*90c8c64dSAndroid Build Coastguard Worker 
37*90c8c64dSAndroid Build Coastguard Worker import java.util.ArrayList;
38*90c8c64dSAndroid Build Coastguard Worker import java.util.List;
39*90c8c64dSAndroid Build Coastguard Worker 
40*90c8c64dSAndroid Build Coastguard Worker /**
41*90c8c64dSAndroid Build Coastguard Worker  * A Fragment that lists all the various browsable queues available
42*90c8c64dSAndroid Build Coastguard Worker  * from a {@link android.service.media.MediaBrowserService}.
43*90c8c64dSAndroid Build Coastguard Worker  * <p/>
44*90c8c64dSAndroid Build Coastguard Worker  * It uses a {@link MediaBrowser} to connect to the {@link MusicService}. Once connected,
45*90c8c64dSAndroid Build Coastguard Worker  * the fragment subscribes to get all the children. All {@link MediaBrowser.MediaItem}'s
46*90c8c64dSAndroid Build Coastguard Worker  * that can be browsed are shown in a ListView.
47*90c8c64dSAndroid Build Coastguard Worker  */
48*90c8c64dSAndroid Build Coastguard Worker public class BrowseFragment extends Fragment {
49*90c8c64dSAndroid Build Coastguard Worker 
50*90c8c64dSAndroid Build Coastguard Worker     private static final String TAG = LogHelper.makeLogTag(BrowseFragment.class.getSimpleName());
51*90c8c64dSAndroid Build Coastguard Worker 
52*90c8c64dSAndroid Build Coastguard Worker     public static final String ARG_MEDIA_ID = "media_id";
53*90c8c64dSAndroid Build Coastguard Worker 
54*90c8c64dSAndroid Build Coastguard Worker     public static interface FragmentDataHelper {
onMediaItemSelected(MediaBrowser.MediaItem item)55*90c8c64dSAndroid Build Coastguard Worker         void onMediaItemSelected(MediaBrowser.MediaItem item);
56*90c8c64dSAndroid Build Coastguard Worker     }
57*90c8c64dSAndroid Build Coastguard Worker 
58*90c8c64dSAndroid Build Coastguard Worker     // The mediaId to be used for subscribing for children using the MediaBrowser.
59*90c8c64dSAndroid Build Coastguard Worker     private String mMediaId;
60*90c8c64dSAndroid Build Coastguard Worker 
61*90c8c64dSAndroid Build Coastguard Worker     private MediaBrowser mMediaBrowser;
62*90c8c64dSAndroid Build Coastguard Worker     private BrowseAdapter mBrowserAdapter;
63*90c8c64dSAndroid Build Coastguard Worker 
64*90c8c64dSAndroid Build Coastguard Worker     private MediaBrowser.SubscriptionCallback mSubscriptionCallback = new MediaBrowser.SubscriptionCallback() {
65*90c8c64dSAndroid Build Coastguard Worker 
66*90c8c64dSAndroid Build Coastguard Worker         @Override
67*90c8c64dSAndroid Build Coastguard Worker         public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
68*90c8c64dSAndroid Build Coastguard Worker             mBrowserAdapter.clear();
69*90c8c64dSAndroid Build Coastguard Worker             mBrowserAdapter.notifyDataSetInvalidated();
70*90c8c64dSAndroid Build Coastguard Worker             for (MediaBrowser.MediaItem item : children) {
71*90c8c64dSAndroid Build Coastguard Worker                 mBrowserAdapter.add(item);
72*90c8c64dSAndroid Build Coastguard Worker             }
73*90c8c64dSAndroid Build Coastguard Worker             mBrowserAdapter.notifyDataSetChanged();
74*90c8c64dSAndroid Build Coastguard Worker         }
75*90c8c64dSAndroid Build Coastguard Worker 
76*90c8c64dSAndroid Build Coastguard Worker         @Override
77*90c8c64dSAndroid Build Coastguard Worker         public void onError(String id) {
78*90c8c64dSAndroid Build Coastguard Worker             Toast.makeText(getActivity(), R.string.error_loading_media,
79*90c8c64dSAndroid Build Coastguard Worker                     Toast.LENGTH_LONG).show();
80*90c8c64dSAndroid Build Coastguard Worker         }
81*90c8c64dSAndroid Build Coastguard Worker     };
82*90c8c64dSAndroid Build Coastguard Worker 
83*90c8c64dSAndroid Build Coastguard Worker     private MediaBrowser.ConnectionCallback mConnectionCallback =
84*90c8c64dSAndroid Build Coastguard Worker             new MediaBrowser.ConnectionCallback() {
85*90c8c64dSAndroid Build Coastguard Worker         @Override
86*90c8c64dSAndroid Build Coastguard Worker         public void onConnected() {
87*90c8c64dSAndroid Build Coastguard Worker             LogHelper.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken());
88*90c8c64dSAndroid Build Coastguard Worker 
89*90c8c64dSAndroid Build Coastguard Worker             if (mMediaId == null) {
90*90c8c64dSAndroid Build Coastguard Worker                 mMediaId = mMediaBrowser.getRoot();
91*90c8c64dSAndroid Build Coastguard Worker             }
92*90c8c64dSAndroid Build Coastguard Worker             mMediaBrowser.subscribe(mMediaId, mSubscriptionCallback);
93*90c8c64dSAndroid Build Coastguard Worker             if (mMediaBrowser.getSessionToken() == null) {
94*90c8c64dSAndroid Build Coastguard Worker                 throw new IllegalArgumentException("No Session token");
95*90c8c64dSAndroid Build Coastguard Worker             }
96*90c8c64dSAndroid Build Coastguard Worker             MediaController mediaController = new MediaController(getActivity(),
97*90c8c64dSAndroid Build Coastguard Worker                     mMediaBrowser.getSessionToken());
98*90c8c64dSAndroid Build Coastguard Worker             getActivity().setMediaController(mediaController);
99*90c8c64dSAndroid Build Coastguard Worker         }
100*90c8c64dSAndroid Build Coastguard Worker 
101*90c8c64dSAndroid Build Coastguard Worker         @Override
102*90c8c64dSAndroid Build Coastguard Worker         public void onConnectionFailed() {
103*90c8c64dSAndroid Build Coastguard Worker             LogHelper.d(TAG, "onConnectionFailed");
104*90c8c64dSAndroid Build Coastguard Worker         }
105*90c8c64dSAndroid Build Coastguard Worker 
106*90c8c64dSAndroid Build Coastguard Worker         @Override
107*90c8c64dSAndroid Build Coastguard Worker         public void onConnectionSuspended() {
108*90c8c64dSAndroid Build Coastguard Worker             LogHelper.d(TAG, "onConnectionSuspended");
109*90c8c64dSAndroid Build Coastguard Worker             getActivity().setMediaController(null);
110*90c8c64dSAndroid Build Coastguard Worker         }
111*90c8c64dSAndroid Build Coastguard Worker     };
112*90c8c64dSAndroid Build Coastguard Worker 
newInstance(String mediaId)113*90c8c64dSAndroid Build Coastguard Worker     public static BrowseFragment newInstance(String mediaId) {
114*90c8c64dSAndroid Build Coastguard Worker         Bundle args = new Bundle();
115*90c8c64dSAndroid Build Coastguard Worker         args.putString(ARG_MEDIA_ID, mediaId);
116*90c8c64dSAndroid Build Coastguard Worker         BrowseFragment fragment = new BrowseFragment();
117*90c8c64dSAndroid Build Coastguard Worker         fragment.setArguments(args);
118*90c8c64dSAndroid Build Coastguard Worker         return fragment;
119*90c8c64dSAndroid Build Coastguard Worker     }
120*90c8c64dSAndroid Build Coastguard Worker 
121*90c8c64dSAndroid Build Coastguard Worker     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)122*90c8c64dSAndroid Build Coastguard Worker     public View onCreateView(LayoutInflater inflater, ViewGroup container,
123*90c8c64dSAndroid Build Coastguard Worker                              Bundle savedInstanceState) {
124*90c8c64dSAndroid Build Coastguard Worker         View rootView = inflater.inflate(R.layout.fragment_list, container, false);
125*90c8c64dSAndroid Build Coastguard Worker 
126*90c8c64dSAndroid Build Coastguard Worker         mBrowserAdapter = new BrowseAdapter(getActivity());
127*90c8c64dSAndroid Build Coastguard Worker 
128*90c8c64dSAndroid Build Coastguard Worker         View controls = rootView.findViewById(R.id.controls);
129*90c8c64dSAndroid Build Coastguard Worker         controls.setVisibility(View.GONE);
130*90c8c64dSAndroid Build Coastguard Worker 
131*90c8c64dSAndroid Build Coastguard Worker         ListView listView = (ListView) rootView.findViewById(R.id.list_view);
132*90c8c64dSAndroid Build Coastguard Worker         listView.setAdapter(mBrowserAdapter);
133*90c8c64dSAndroid Build Coastguard Worker         listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
134*90c8c64dSAndroid Build Coastguard Worker             @Override
135*90c8c64dSAndroid Build Coastguard Worker             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
136*90c8c64dSAndroid Build Coastguard Worker                 MediaBrowser.MediaItem item = mBrowserAdapter.getItem(position);
137*90c8c64dSAndroid Build Coastguard Worker                 try {
138*90c8c64dSAndroid Build Coastguard Worker                     FragmentDataHelper listener = (FragmentDataHelper) getActivity();
139*90c8c64dSAndroid Build Coastguard Worker                     listener.onMediaItemSelected(item);
140*90c8c64dSAndroid Build Coastguard Worker                 } catch (ClassCastException ex) {
141*90c8c64dSAndroid Build Coastguard Worker                     Log.e(TAG, "Exception trying to cast to FragmentDataHelper", ex);
142*90c8c64dSAndroid Build Coastguard Worker                 }
143*90c8c64dSAndroid Build Coastguard Worker             }
144*90c8c64dSAndroid Build Coastguard Worker         });
145*90c8c64dSAndroid Build Coastguard Worker 
146*90c8c64dSAndroid Build Coastguard Worker         Bundle args = getArguments();
147*90c8c64dSAndroid Build Coastguard Worker         mMediaId = args.getString(ARG_MEDIA_ID, null);
148*90c8c64dSAndroid Build Coastguard Worker 
149*90c8c64dSAndroid Build Coastguard Worker         mMediaBrowser = new MediaBrowser(getActivity(),
150*90c8c64dSAndroid Build Coastguard Worker                 new ComponentName(getActivity(), MusicService.class),
151*90c8c64dSAndroid Build Coastguard Worker                 mConnectionCallback, null);
152*90c8c64dSAndroid Build Coastguard Worker 
153*90c8c64dSAndroid Build Coastguard Worker         return rootView;
154*90c8c64dSAndroid Build Coastguard Worker     }
155*90c8c64dSAndroid Build Coastguard Worker 
156*90c8c64dSAndroid Build Coastguard Worker     @Override
onStart()157*90c8c64dSAndroid Build Coastguard Worker     public void onStart() {
158*90c8c64dSAndroid Build Coastguard Worker         super.onStart();
159*90c8c64dSAndroid Build Coastguard Worker         mMediaBrowser.connect();
160*90c8c64dSAndroid Build Coastguard Worker     }
161*90c8c64dSAndroid Build Coastguard Worker 
162*90c8c64dSAndroid Build Coastguard Worker     @Override
onStop()163*90c8c64dSAndroid Build Coastguard Worker     public void onStop() {
164*90c8c64dSAndroid Build Coastguard Worker         super.onStop();
165*90c8c64dSAndroid Build Coastguard Worker         mMediaBrowser.disconnect();
166*90c8c64dSAndroid Build Coastguard Worker     }
167*90c8c64dSAndroid Build Coastguard Worker 
168*90c8c64dSAndroid Build Coastguard Worker     // An adapter for showing the list of browsed MediaItem's
169*90c8c64dSAndroid Build Coastguard Worker     private static class BrowseAdapter extends ArrayAdapter<MediaBrowser.MediaItem> {
170*90c8c64dSAndroid Build Coastguard Worker 
BrowseAdapter(Context context)171*90c8c64dSAndroid Build Coastguard Worker         public BrowseAdapter(Context context) {
172*90c8c64dSAndroid Build Coastguard Worker             super(context, R.layout.media_list_item, new ArrayList<MediaBrowser.MediaItem>());
173*90c8c64dSAndroid Build Coastguard Worker         }
174*90c8c64dSAndroid Build Coastguard Worker 
175*90c8c64dSAndroid Build Coastguard Worker         static class ViewHolder {
176*90c8c64dSAndroid Build Coastguard Worker             ImageView mImageView;
177*90c8c64dSAndroid Build Coastguard Worker             TextView mTitleView;
178*90c8c64dSAndroid Build Coastguard Worker             TextView mDescriptionView;
179*90c8c64dSAndroid Build Coastguard Worker         }
180*90c8c64dSAndroid Build Coastguard Worker 
181*90c8c64dSAndroid Build Coastguard Worker         @Override
getView(int position, View convertView, ViewGroup parent)182*90c8c64dSAndroid Build Coastguard Worker         public View getView(int position, View convertView, ViewGroup parent) {
183*90c8c64dSAndroid Build Coastguard Worker 
184*90c8c64dSAndroid Build Coastguard Worker             ViewHolder holder;
185*90c8c64dSAndroid Build Coastguard Worker 
186*90c8c64dSAndroid Build Coastguard Worker             if (convertView == null) {
187*90c8c64dSAndroid Build Coastguard Worker                 convertView = LayoutInflater.from(getContext())
188*90c8c64dSAndroid Build Coastguard Worker                         .inflate(R.layout.media_list_item, parent, false);
189*90c8c64dSAndroid Build Coastguard Worker                 holder = new ViewHolder();
190*90c8c64dSAndroid Build Coastguard Worker                 holder.mImageView = (ImageView) convertView.findViewById(R.id.play_eq);
191*90c8c64dSAndroid Build Coastguard Worker                 holder.mImageView.setVisibility(View.GONE);
192*90c8c64dSAndroid Build Coastguard Worker                 holder.mTitleView = (TextView) convertView.findViewById(R.id.title);
193*90c8c64dSAndroid Build Coastguard Worker                 holder.mDescriptionView = (TextView) convertView.findViewById(R.id.description);
194*90c8c64dSAndroid Build Coastguard Worker                 convertView.setTag(holder);
195*90c8c64dSAndroid Build Coastguard Worker             } else {
196*90c8c64dSAndroid Build Coastguard Worker                 holder = (ViewHolder) convertView.getTag();
197*90c8c64dSAndroid Build Coastguard Worker             }
198*90c8c64dSAndroid Build Coastguard Worker 
199*90c8c64dSAndroid Build Coastguard Worker             MediaBrowser.MediaItem item = getItem(position);
200*90c8c64dSAndroid Build Coastguard Worker             holder.mTitleView.setText(item.getDescription().getTitle());
201*90c8c64dSAndroid Build Coastguard Worker             holder.mDescriptionView.setText(item.getDescription().getDescription());
202*90c8c64dSAndroid Build Coastguard Worker             if (item.isPlayable()) {
203*90c8c64dSAndroid Build Coastguard Worker                 holder.mImageView.setImageDrawable(
204*90c8c64dSAndroid Build Coastguard Worker                         getContext().getDrawable(R.drawable.ic_play_arrow_white_24dp));
205*90c8c64dSAndroid Build Coastguard Worker                 holder.mImageView.setVisibility(View.VISIBLE);
206*90c8c64dSAndroid Build Coastguard Worker             }
207*90c8c64dSAndroid Build Coastguard Worker             return convertView;
208*90c8c64dSAndroid Build Coastguard Worker         }
209*90c8c64dSAndroid Build Coastguard Worker     }
210*90c8c64dSAndroid Build Coastguard Worker }
211