• 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.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 
MediaDrawerController(CarDrawerActivity activity)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
onQueueItemClicked(MediaSession.QueueItem queueItem)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
onMediaItemClicked(MediaBrowser.MediaItem item)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
onFetchStart()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
onFetchEnd()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      */
setupAdapterAndSwitch(MediaItemsFetcher fetcher, CharSequence title)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      */
showPlayQueue()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 
cleanup()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      */
getRootAdapter()152     public CarDrawerAdapter getRootAdapter() {
153         return mRootAdapter;
154     }
155 
156     /**
157      * Creates a {@link MediaBrowserItemsFetcher} that whose root is the given {@code mediaId}.
158      */
createMediaBrowserItemFetcher(String mediaId, boolean showQueueItem)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      */
createMediaQueueItemsFetcher()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      */
createRootMediaItemsFetcher()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