• 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.content.Context;
19 import android.graphics.PorterDuff;
20 import android.graphics.drawable.Drawable;
21 import android.media.session.MediaController;
22 import android.media.session.MediaSession;
23 import android.media.session.PlaybackState;
24 import android.os.Handler;
25 import android.support.annotation.Nullable;
26 
27 import com.android.car.media.MediaPlaybackModel;
28 import com.android.car.media.R;
29 
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.List;
33 
34 import androidx.car.drawer.DrawerItemViewHolder;
35 
36 /**
37  * {@link MediaItemsFetcher} implementation that fetches items from the {@link MediaController}'s
38  * currently playing queue.
39  */
40 class MediaQueueItemsFetcher implements MediaItemsFetcher {
41     private final Handler mHandler = new Handler();
42     private final Context mContext;
43     private final MediaItemOnClickListener mClickListener;
44     private MediaPlaybackModel mMediaPlaybackModel;
45     private ItemsUpdatedCallback mCallback;
46     private List<MediaSession.QueueItem> mItems = new ArrayList<>();
47 
MediaQueueItemsFetcher(Context context, MediaPlaybackModel model, MediaItemOnClickListener listener)48     MediaQueueItemsFetcher(Context context, MediaPlaybackModel model,
49             MediaItemOnClickListener listener) {
50         mContext = context;
51         mMediaPlaybackModel = model;
52         mClickListener = listener;
53     }
54 
55     @Override
start(ItemsUpdatedCallback callback)56     public void start(ItemsUpdatedCallback callback) {
57         mCallback = callback;
58         if (mMediaPlaybackModel != null) {
59             mMediaPlaybackModel.addListener(mListener);
60             updateItemsFrom(mMediaPlaybackModel.getQueue());
61         }
62         // Inform client of current items. Invoke async to avoid re-entrancy issues.
63         mHandler.post(mCallback::onItemsUpdated);
64     }
65 
66     @Override
getItemCount()67     public int getItemCount() {
68         return mItems.size();
69     }
70 
71     @Override
usesSmallLayout(int position)72     public boolean usesSmallLayout(int position) {
73         return MediaItemsFetcher.usesSmallLayout(mItems.get(position).getDescription());
74     }
75 
76     @Override
populateViewHolder(DrawerItemViewHolder holder, int position)77     public void populateViewHolder(DrawerItemViewHolder holder, int position) {
78         MediaSession.QueueItem item = mItems.get(position);
79         MediaItemsFetcher.populateViewHolderFrom(holder, item.getDescription());
80 
81         if (holder.getEndIcon() == null) {
82             return;
83         }
84 
85         if (item.getQueueId() == getActiveQueueItemId()) {
86             int primaryColor = mMediaPlaybackModel.getPrimaryColor();
87             Drawable drawable =
88                     mContext.getDrawable(R.drawable.ic_music_active);
89             drawable.setColorFilter(primaryColor, PorterDuff.Mode.SRC_IN);
90             holder.getEndIcon().setImageDrawable(drawable);
91         } else {
92             holder.getEndIcon().setImageBitmap(null);
93         }
94     }
95 
96     @Override
onItemClick(int position)97     public void onItemClick(int position) {
98         if (mClickListener != null) {
99             mClickListener.onQueueItemClicked(mItems.get(position));
100         }
101     }
102 
103     @Override
cleanup()104     public void cleanup() {
105         mMediaPlaybackModel.removeListener(mListener);
106     }
107 
108     @Override
getScrollPosition()109     public int getScrollPosition() {
110         long activeId = getActiveQueueItemId();
111         // A linear scan isn't really the best thing to do for large lists but we suspect that
112         // the queue isn't going to be very long anyway so we can just do the trivial thing. If
113         // it starts becoming a problem, we can build an index over the ids.
114         for (int position = 0; position < mItems.size(); position++) {
115             MediaSession.QueueItem item = mItems.get(position);
116             if (item.getQueueId() == activeId) {
117                 return position;
118             }
119         }
120         return MediaItemsFetcher.DONT_SCROLL;
121     }
122 
updateItemsFrom(List<MediaSession.QueueItem> queue)123     private void updateItemsFrom(List<MediaSession.QueueItem> queue) {
124         mItems.clear();
125         mItems.addAll(queue);
126     }
127 
getActiveQueueItemId()128     private long getActiveQueueItemId() {
129         if (mMediaPlaybackModel != null) {
130             PlaybackState playbackState = mMediaPlaybackModel.getPlaybackState();
131             if (playbackState != null) {
132                 return playbackState.getActiveQueueItemId();
133             }
134         }
135         return MediaSession.QueueItem.UNKNOWN_ID;
136     }
137 
138     private final MediaPlaybackModel.Listener mListener =
139             new MediaPlaybackModel.AbstractListener() {
140         @Override
141         public void onQueueChanged(List<MediaSession.QueueItem> queue) {
142             updateItemsFrom(queue);
143             mCallback.onItemsUpdated();
144         }
145 
146         @Override
147         public void onPlaybackStateChanged(@Nullable PlaybackState state) {
148             // Since active playing item may have changed, force re-draw of queue items.
149             mCallback.onItemsUpdated();
150         }
151 
152         @Override
153         public void onSessionDestroyed(CharSequence destroyedMediaClientName) {
154             onQueueChanged(Collections.emptyList());
155         }
156     };
157 }
158