Home | History | Annotate | Download | only in drawer
      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.MediaDescription;
     22 import android.media.browse.MediaBrowser;
     23 import android.media.session.MediaSession;
     24 import android.util.Log;
     25 
     26 import com.android.car.media.MediaPlaybackModel;
     27 import com.android.car.media.R;
     28 
     29 import java.util.ArrayList;
     30 import java.util.List;
     31 
     32 import androidx.car.drawer.DrawerItemViewHolder;
     33 
     34 /**
     35  * {@link MediaItemsFetcher} implementation that fetches items from a specific {@link MediaBrowser}
     36  * node.
     37  * <p>
     38  * It optionally supports surfacing the Media app's queue as the last item.
     39  */
     40 class MediaBrowserItemsFetcher implements MediaItemsFetcher {
     41     private static final String TAG = "Media.BrowserFetcher";
     42 
     43     /**
     44      * An id that can be returned from {@link MediaBrowser.MediaItem#getMediaId()} to indicate that
     45      * a {@link android.media.browse.MediaBrowser.MediaItem} representing the play queue has been
     46      * clicked.
     47      */
     48     static final String PLAY_QUEUE_MEDIA_ID = "com.android.car.media.drawer.PLAY_QUEUE";
     49 
     50     private final Context mContext;
     51     private final MediaPlaybackModel mMediaPlaybackModel;
     52     private final String mMediaId;
     53     private final boolean mShowQueueItem;
     54     private final MediaItemOnClickListener mItemClickListener;
     55     private ItemsUpdatedCallback mCallback;
     56     private List<MediaBrowser.MediaItem> mItems = new ArrayList<>();
     57     private boolean mQueueAvailable;
     58 
     59     MediaBrowserItemsFetcher(Context context, MediaPlaybackModel model,
     60             MediaItemOnClickListener listener, String mediaId, boolean showQueueItem) {
     61         mContext = context;
     62         mMediaPlaybackModel = model;
     63         mItemClickListener = listener;
     64         mMediaId = mediaId;
     65         mShowQueueItem = showQueueItem;
     66     }
     67 
     68     @Override
     69     public void start(ItemsUpdatedCallback callback) {
     70         mCallback = callback;
     71         updateQueueAvailability();
     72         if (mMediaPlaybackModel.isConnected()) {
     73             mMediaPlaybackModel.getMediaBrowser().subscribe(mMediaId, mSubscriptionCallback);
     74         } else {
     75             mItems.clear();
     76             callback.onItemsUpdated();
     77         }
     78         mMediaPlaybackModel.addListener(mModelListener);
     79     }
     80 
     81     private final MediaPlaybackModel.Listener mModelListener =
     82             new MediaPlaybackModel.AbstractListener() {
     83         @Override
     84         public void onQueueChanged(List<MediaSession.QueueItem> queue) {
     85             updateQueueAvailability();
     86         }
     87         @Override
     88         public void onSessionDestroyed(CharSequence destroyedMediaClientName) {
     89             updateQueueAvailability();
     90         }
     91         @Override
     92         public void onMediaConnectionSuspended() {
     93             if (mCallback != null) {
     94                 mCallback.onItemsUpdated();
     95             }
     96         }
     97     };
     98 
     99     private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
    100         new MediaBrowser.SubscriptionCallback() {
    101             @Override
    102             public void onChildrenLoaded(String parentId, List<MediaBrowser.MediaItem> children) {
    103                 mItems.clear();
    104                 mItems.addAll(children);
    105                 mCallback.onItemsUpdated();
    106             }
    107 
    108             @Override
    109             public void onError(String parentId) {
    110                 mItems.clear();
    111                 mCallback.onItemsUpdated();
    112             }
    113         };
    114 
    115     private void updateQueueAvailability() {
    116         if (mShowQueueItem && !mMediaPlaybackModel.getQueue().isEmpty()) {
    117             mQueueAvailable = true;
    118         }
    119     }
    120 
    121     @Override
    122     public int getItemCount() {
    123         int size = mItems.size();
    124         if (mQueueAvailable) {
    125             size++;
    126         }
    127         return size;
    128     }
    129 
    130     @Override
    131     public boolean usesSmallLayout(int position) {
    132         if (mQueueAvailable && position == mItems.size()) {
    133             return true;
    134         }
    135         return MediaItemsFetcher.usesSmallLayout(mItems.get(position).getDescription());
    136     }
    137 
    138     @Override
    139     public void populateViewHolder(DrawerItemViewHolder holder, int position) {
    140         if (mQueueAvailable && position == mItems.size()) {
    141             holder.getTitle().setText(mMediaPlaybackModel.getQueueTitle());
    142             return;
    143         }
    144         MediaBrowser.MediaItem item = mItems.get(position);
    145         MediaItemsFetcher.populateViewHolderFrom(holder, item.getDescription());
    146 
    147         if (holder.getEndIcon() == null) {
    148             return;
    149         }
    150 
    151         if (item.isBrowsable()) {
    152             int iconColor = mContext.getColor(R.color.car_tint);
    153             Drawable drawable = mContext.getDrawable(R.drawable.ic_chevron_right);
    154             drawable.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
    155             holder.getEndIcon().setImageDrawable(drawable);
    156         } else {
    157             holder.getEndIcon().setImageDrawable(null);
    158         }
    159     }
    160 
    161     @Override
    162     public void onItemClick(int position) {
    163         if (mItemClickListener == null) {
    164             return;
    165         }
    166 
    167         MediaBrowser.MediaItem item = mQueueAvailable && position == mItems.size()
    168                 ? createPlayQueueMediaItem()
    169                 : mItems.get(position);
    170 
    171         mItemClickListener.onMediaItemClicked(item);
    172     }
    173 
    174     /**
    175      * Creates and returns a {@link android.media.browse.MediaBrowser.MediaItem} that represents an
    176      * entry for the play queue. A play queue media item will have a media id of
    177      * {@link #PLAY_QUEUE_MEDIA_ID} and is {@link MediaBrowser.MediaItem#FLAG_BROWSABLE}.
    178      */
    179     private MediaBrowser.MediaItem createPlayQueueMediaItem() {
    180         MediaDescription description = new MediaDescription.Builder()
    181                 .setMediaId(PLAY_QUEUE_MEDIA_ID)
    182                 .setTitle(mMediaPlaybackModel.getQueueTitle())
    183                 .build();
    184 
    185         return new MediaBrowser.MediaItem(description, MediaBrowser.MediaItem.FLAG_BROWSABLE);
    186     }
    187 
    188     @Override
    189     public void cleanup() {
    190         mMediaPlaybackModel.removeListener(mModelListener);
    191         mMediaPlaybackModel.getMediaBrowser().unsubscribe(mMediaId);
    192         mCallback = null;
    193     }
    194 
    195     @Override
    196     public int getScrollPosition() {
    197         return MediaItemsFetcher.DONT_SCROLL;
    198     }
    199 }
    200