• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.android.car.media.drawer;
17 
18 import android.graphics.PorterDuff;
19 import android.graphics.drawable.Drawable;
20 import android.media.browse.MediaBrowser;
21 import android.media.session.MediaController;
22 import android.media.session.MediaSession;
23 import android.util.Log;
24 
25 import com.android.car.app.CarDrawerActivity;
26 import com.android.car.app.DrawerItemViewHolder;
27 import com.android.car.media.MediaPlaybackModel;
28 import com.android.car.media.R;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * {@link MediaItemsFetcher} implementation that fetches items from a specific {@link MediaBrowser}
35  * node.
36  * <p>
37  * It optionally supports surfacing the Media app's queue as the last item.
38  */
39 class MediaBrowserItemsFetcher implements MediaItemsFetcher {
40     private static final String TAG = "Media.BrowserFetcher";
41 
42     private final CarDrawerActivity mActivity;
43     private final MediaPlaybackModel mMediaPlaybackModel;
44     private final String mMediaId;
45     private final boolean mShowQueueItem;
46     private ItemsUpdatedCallback mCallback;
47     private List<MediaBrowser.MediaItem> mItems = new ArrayList<>();
48     private boolean mQueueAvailable;
49 
MediaBrowserItemsFetcher(CarDrawerActivity activity, MediaPlaybackModel model, String mediaId, boolean showQueueItem)50     MediaBrowserItemsFetcher(CarDrawerActivity activity, MediaPlaybackModel model, String mediaId,
51             boolean showQueueItem) {
52         mActivity = activity;
53         mMediaPlaybackModel = model;
54         mMediaId = mediaId;
55         mShowQueueItem = showQueueItem;
56     }
57 
58     @Override
start(ItemsUpdatedCallback callback)59     public void start(ItemsUpdatedCallback callback) {
60         mCallback = callback;
61         updateQueueAvailability();
62         mMediaPlaybackModel.getMediaBrowser().subscribe(mMediaId, mSubscriptionCallback);
63         mMediaPlaybackModel.addListener(mModelListener);
64     }
65 
66     private final MediaPlaybackModel.Listener mModelListener =
67             new MediaPlaybackModel.AbstractListener() {
68         @Override
69         public void onQueueChanged(List<MediaSession.QueueItem> queue) {
70             updateQueueAvailability();
71         }
72         @Override
73         public void onSessionDestroyed(CharSequence destroyedMediaClientName) {
74             updateQueueAvailability();
75         }
76     };
77 
78     private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
79         new MediaBrowser.SubscriptionCallback() {
80             @Override
81             public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
82                 mItems.clear();
83                 mItems.addAll(children);
84                 mCallback.onItemsUpdated();
85             }
86 
87             @Override
88             public void onError(String parentId) {
89                 Log.e(TAG, "Error loading children of: " + mMediaId);
90                 mItems.clear();
91                 mCallback.onItemsUpdated();
92             }
93         };
94 
updateQueueAvailability()95     private void updateQueueAvailability() {
96         if (mShowQueueItem && !mMediaPlaybackModel.getQueue().isEmpty()) {
97             mQueueAvailable = true;
98         }
99     }
100 
101     @Override
getItemCount()102     public int getItemCount() {
103         int size = mItems.size();
104         if (mQueueAvailable) {
105             size++;
106         }
107         return size;
108     }
109 
110     @Override
populateViewHolder(DrawerItemViewHolder holder, int position)111     public void populateViewHolder(DrawerItemViewHolder holder, int position) {
112         if (mQueueAvailable && position == mItems.size()) {
113             holder.getTitle().setText(mMediaPlaybackModel.getQueueTitle());
114             return;
115         }
116         MediaBrowser.MediaItem item = mItems.get(position);
117         MediaItemsFetcher.populateViewHolderFrom(holder, item.getDescription());
118 
119         // TODO(sriniv): Once we use smallLayout, text and rightIcon fields may be unavailable.
120         // Related to b/36573125.
121         if (item.isBrowsable()) {
122             int iconColor = mActivity.getColor(R.color.car_tint);
123             Drawable drawable = mActivity.getDrawable(R.drawable.ic_chevron_right);
124             drawable.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
125             holder.getRightIcon().setImageDrawable(drawable);
126         } else {
127             holder.getRightIcon().setImageDrawable(null);
128         }
129     }
130 
131     @Override
onItemClick(int position)132     public void onItemClick(int position) {
133         if (mQueueAvailable && position == mItems.size()) {
134             MediaItemsFetcher fetcher = new MediaQueueItemsFetcher(mActivity, mMediaPlaybackModel);
135             setupAdapterAndSwitch(fetcher, mMediaPlaybackModel.getQueueTitle());
136             return;
137         }
138 
139         MediaBrowser.MediaItem item = mItems.get(position);
140         if (item.isBrowsable()) {
141             MediaItemsFetcher fetcher = new MediaBrowserItemsFetcher(
142                     mActivity, mMediaPlaybackModel, item.getMediaId(), false /* showQueueItem */);
143             setupAdapterAndSwitch(fetcher, item.getDescription().getTitle());
144         } else if (item.isPlayable()) {
145             MediaController.TransportControls controls = mMediaPlaybackModel.getTransportControls();
146             if (controls != null) {
147                 controls.pause();
148                 controls.playFromMediaId(item.getMediaId(), item.getDescription().getExtras());
149             }
150             mActivity.closeDrawer();
151         } else {
152             Log.w(TAG, "Unknown item type; don't know how to handle!");
153         }
154     }
155 
setupAdapterAndSwitch(MediaItemsFetcher fetcher, CharSequence title)156     private void setupAdapterAndSwitch(MediaItemsFetcher fetcher, CharSequence title) {
157         MediaDrawerAdapter subAdapter = new MediaDrawerAdapter(mActivity, false /* smallLayout */);
158         subAdapter.setFetcher(fetcher);
159         subAdapter.setTitle(title);
160         mActivity.switchToAdapter(subAdapter);
161     }
162 
163     @Override
cleanup()164     public void cleanup() {
165         mMediaPlaybackModel.removeListener(mModelListener);
166         mMediaPlaybackModel.getMediaBrowser().unsubscribe(mMediaId);
167         mCallback = null;
168     }
169 }