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.ComponentName;
     19 import android.media.browse.MediaBrowser;
     20 import android.media.session.MediaController;
     21 import android.media.session.MediaSession;
     22 import android.os.Bundle;
     23 import android.support.annotation.Nullable;
     24 import android.support.v4.widget.DrawerLayout;
     25 import android.util.Log;
     26 import android.view.View;
     27 import com.android.car.app.CarDrawerActivity;
     28 import com.android.car.app.CarDrawerAdapter;
     29 import com.android.car.media.MediaManager;
     30 import com.android.car.media.MediaPlaybackModel;
     31 import com.android.car.media.R;
     32 
     33 /**
     34  * Manages drawer navigation and item selection.
     35  * <p>
     36  * Maintains separate MediaPlaybackModel for media browsing and control. Sets up root Drawer
     37  * adapter with root of media-browse tree (using MediaBrowserItemsFetcher). Supports switching the
     38  * rootAdapter to show the queue-items (using MediaQueueItemsFetcher).
     39  */
     40 public class MediaDrawerController implements MediaDrawerAdapter.MediaFetchCallback,
     41         MediaItemOnClickListener {
     42     private static final String TAG = "MediaDrawerController";
     43 
     44     private static final String EXTRA_ICON_SIZE =
     45             "com.google.android.gms.car.media.BrowserIconSize";
     46 
     47     private final CarDrawerActivity mActivity;
     48     private final MediaPlaybackModel mMediaPlaybackModel;
     49     private MediaDrawerAdapter mRootAdapter;
     50 
     51     public MediaDrawerController(CarDrawerActivity activity) {
     52         mActivity = activity;
     53         Bundle extras = new Bundle();
     54         extras.putInt(EXTRA_ICON_SIZE,
     55                 mActivity.getResources().getDimensionPixelSize(R.dimen.car_list_item_icon_size));
     56         mMediaPlaybackModel = new MediaPlaybackModel(mActivity, extras);
     57         mMediaPlaybackModel.addListener(mModelListener);
     58 
     59         mRootAdapter = new MediaDrawerAdapter(mActivity);
     60         // Start with a empty title since we depend on the mMediaManagerListener callback to
     61         // know which app is being used and set the actual title there.
     62         mRootAdapter.setTitle("");
     63         mRootAdapter.setFetchCallback(this);
     64 
     65         // Kick off MediaBrowser/MediaController connection.
     66         mMediaPlaybackModel.start();
     67     }
     68 
     69     @Override
     70     public void onQueueItemClicked(MediaSession.QueueItem queueItem) {
     71         MediaController.TransportControls controls = mMediaPlaybackModel.getTransportControls();
     72 
     73         if (controls != null) {
     74             controls.skipToQueueItem(queueItem.getQueueId());
     75         }
     76 
     77         mActivity.closeDrawer();
     78     }
     79 
     80     @Override
     81     public void onMediaItemClicked(MediaBrowser.MediaItem item) {
     82         if (item.isBrowsable()) {
     83             MediaItemsFetcher fetcher;
     84             if (MediaBrowserItemsFetcher.PLAY_QUEUE_MEDIA_ID.equals(item.getMediaId())) {
     85                 fetcher = createMediaQueueItemsFetcher();
     86             } else {
     87                 fetcher = createMediaBrowserItemFetcher(item.getMediaId(),
     88                         false /* showQueueItem */);
     89             }
     90             setupAdapterAndSwitch(fetcher, item.getDescription().getTitle());
     91         } else if (item.isPlayable()) {
     92             MediaController.TransportControls controls = mMediaPlaybackModel.getTransportControls();
     93             if (controls != null) {
     94                 controls.pause();
     95                 controls.playFromMediaId(item.getMediaId(), item.getDescription().getExtras());
     96             }
     97             mActivity.closeDrawer();
     98         } else {
     99             Log.w(TAG, "Unknown item type; don't know how to handle!");
    100         }
    101     }
    102 
    103     @Override
    104     public void onFetchStart() {
    105         // Initially there will be no items and we don't want to show empty-list indicator
    106         // briefly until items are fetched.
    107         mActivity.showLoadingProgressBar(true);
    108     }
    109 
    110     @Override
    111     public void onFetchEnd() {
    112         mActivity.showLoadingProgressBar(false);
    113     }
    114 
    115     /**
    116      * Creates a new sub-level in the drawer and switches to that as the currently displayed view.
    117      *
    118      * @param fetcher The {@link MediaItemsFetcher} that is responsible for fetching the items to be
    119      *                displayed in the new view.
    120      * @param title The title text of the new view in the drawer.
    121      */
    122     private void setupAdapterAndSwitch(MediaItemsFetcher fetcher, CharSequence title) {
    123         MediaDrawerAdapter subAdapter = new MediaDrawerAdapter(mActivity);
    124         subAdapter.setFetcher(fetcher);
    125         subAdapter.setTitle(title);
    126         mActivity.switchToAdapter(subAdapter);
    127     }
    128 
    129     /**
    130      * Opens the drawer and displays the current playing queue of items. When the drawer is closed,
    131      * the view is switched back to the drawer root.
    132      */
    133     public void showPlayQueue() {
    134         mRootAdapter.setFetcher(createMediaQueueItemsFetcher());
    135         mRootAdapter.setTitle(mMediaPlaybackModel.getQueueTitle());
    136         mActivity.openDrawer();
    137         mRootAdapter.scrollToCurrent();
    138         mActivity.addDrawerListener(mQueueDrawerListener);
    139     }
    140 
    141     public void cleanup() {
    142         mActivity.removeDrawerListener(mQueueDrawerListener);
    143         mRootAdapter.cleanup();
    144         mMediaPlaybackModel.removeListener(mModelListener);
    145         mMediaPlaybackModel.stop();
    146     }
    147 
    148     /**
    149      * @return Adapter to display root items of MediaBrowse tree. {@link #showPlayQueue()} can
    150      *      be used to display items from the queue.
    151      */
    152     public CarDrawerAdapter getRootAdapter() {
    153         return mRootAdapter;
    154     }
    155 
    156     /**
    157      * Creates a {@link MediaBrowserItemsFetcher} that whose root is the given {@code mediaId}.
    158      */
    159     private MediaBrowserItemsFetcher createMediaBrowserItemFetcher(String mediaId,
    160             boolean showQueueItem) {
    161         return new MediaBrowserItemsFetcher(mActivity, mMediaPlaybackModel, this /* listener */,
    162                 mediaId, showQueueItem);
    163     }
    164 
    165     /**
    166      * Creates a {@link MediaQueueItemsFetcher} that is responsible for fetching items in the user's
    167      * current play queue.
    168      */
    169     private MediaQueueItemsFetcher createMediaQueueItemsFetcher() {
    170         return new MediaQueueItemsFetcher(mActivity, mMediaPlaybackModel, this /* listener */);
    171     }
    172 
    173     /**
    174      * Creates a {@link MediaItemsFetcher} that will display the top-most level of the drawer.
    175      */
    176     private MediaItemsFetcher createRootMediaItemsFetcher() {
    177         return createMediaBrowserItemFetcher(mMediaPlaybackModel.getMediaBrowser().getRoot(),
    178                 true /* showQueueItem */);
    179     }
    180 
    181     /**
    182      * A {@link android.support.v4.widget.DrawerLayout.DrawerListener} specifically to be used when
    183      * the play queue has been shown in the drawer. When the drawer is closed following this
    184      * display, this listener will reset the drawer to display the root view.
    185      */
    186     private final DrawerLayout.DrawerListener mQueueDrawerListener =
    187             new DrawerLayout.DrawerListener() {
    188         @Override
    189         public void onDrawerClosed(View drawerView) {
    190             mRootAdapter.setFetcher(createRootMediaItemsFetcher());
    191             mRootAdapter.setTitle(
    192                     MediaManager.getInstance(mActivity).getMediaClientName());
    193             mActivity.removeDrawerListener(this);
    194         }
    195 
    196         @Override
    197         public void onDrawerSlide(View drawerView, float slideOffset) {}
    198         @Override
    199         public void onDrawerOpened(View drawerView) {}
    200         @Override
    201         public void onDrawerStateChanged(int newState) {}
    202     };
    203 
    204     private final MediaPlaybackModel.Listener mModelListener =
    205             new MediaPlaybackModel.AbstractListener() {
    206         @Override
    207         public void onMediaAppChanged(@Nullable ComponentName currentName,
    208                 @Nullable ComponentName newName) {
    209             // Only store MediaManager instance to a local variable when it is short lived.
    210             MediaManager mediaManager = MediaManager.getInstance(mActivity);
    211             mRootAdapter.setTitle(mediaManager.getMediaClientName());
    212         }
    213 
    214         @Override
    215         public void onMediaConnected() {
    216             mRootAdapter.setFetcher(createRootMediaItemsFetcher());
    217         }
    218     };
    219 }
    220