blob: c9ef26ead4fbb9a96d536158a37c1318ffbac37e [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.car.media.drawer;
import android.content.ComponentName;
import android.media.browse.MediaBrowser;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.View;
import com.android.car.app.CarDrawerActivity;
import com.android.car.app.CarDrawerAdapter;
import com.android.car.media.MediaManager;
import com.android.car.media.MediaPlaybackModel;
import com.android.car.media.R;
/**
* Manages drawer navigation and item selection.
* <p>
* Maintains separate MediaPlaybackModel for media browsing and control. Sets up root Drawer
* adapter with root of media-browse tree (using MediaBrowserItemsFetcher). Supports switching the
* rootAdapter to show the queue-items (using MediaQueueItemsFetcher).
*/
public class MediaDrawerController implements MediaDrawerAdapter.MediaFetchCallback,
MediaItemOnClickListener {
private static final String TAG = "MediaDrawerController";
private static final String EXTRA_ICON_SIZE =
"com.google.android.gms.car.media.BrowserIconSize";
private final CarDrawerActivity mActivity;
private final MediaPlaybackModel mMediaPlaybackModel;
private MediaDrawerAdapter mRootAdapter;
public MediaDrawerController(CarDrawerActivity activity) {
mActivity = activity;
Bundle extras = new Bundle();
extras.putInt(EXTRA_ICON_SIZE,
mActivity.getResources().getDimensionPixelSize(R.dimen.car_list_item_icon_size));
mMediaPlaybackModel = new MediaPlaybackModel(mActivity, extras);
mMediaPlaybackModel.addListener(mModelListener);
mRootAdapter = new MediaDrawerAdapter(mActivity);
// Start with a empty title since we depend on the mMediaManagerListener callback to
// know which app is being used and set the actual title there.
mRootAdapter.setTitle("");
mRootAdapter.setFetchCallback(this);
// Kick off MediaBrowser/MediaController connection.
mMediaPlaybackModel.start();
}
@Override
public void onQueueItemClicked(MediaSession.QueueItem queueItem) {
MediaController.TransportControls controls = mMediaPlaybackModel.getTransportControls();
if (controls != null) {
controls.skipToQueueItem(queueItem.getQueueId());
}
mActivity.closeDrawer();
}
@Override
public void onMediaItemClicked(MediaBrowser.MediaItem item) {
if (item.isBrowsable()) {
MediaItemsFetcher fetcher;
if (MediaBrowserItemsFetcher.PLAY_QUEUE_MEDIA_ID.equals(item.getMediaId())) {
fetcher = createMediaQueueItemsFetcher();
} else {
fetcher = createMediaBrowserItemFetcher(item.getMediaId(),
false /* showQueueItem */);
}
setupAdapterAndSwitch(fetcher, item.getDescription().getTitle());
} else if (item.isPlayable()) {
MediaController.TransportControls controls = mMediaPlaybackModel.getTransportControls();
if (controls != null) {
controls.pause();
controls.playFromMediaId(item.getMediaId(), item.getDescription().getExtras());
}
mActivity.closeDrawer();
} else {
Log.w(TAG, "Unknown item type; don't know how to handle!");
}
}
@Override
public void onFetchStart() {
// Initially there will be no items and we don't want to show empty-list indicator
// briefly until items are fetched.
mActivity.showLoadingProgressBar(true);
}
@Override
public void onFetchEnd() {
mActivity.showLoadingProgressBar(false);
}
/**
* Creates a new sub-level in the drawer and switches to that as the currently displayed view.
*
* @param fetcher The {@link MediaItemsFetcher} that is responsible for fetching the items to be
* displayed in the new view.
* @param title The title text of the new view in the drawer.
*/
private void setupAdapterAndSwitch(MediaItemsFetcher fetcher, CharSequence title) {
MediaDrawerAdapter subAdapter = new MediaDrawerAdapter(mActivity);
subAdapter.setFetcher(fetcher);
subAdapter.setTitle(title);
mActivity.switchToAdapter(subAdapter);
}
/**
* Opens the drawer and displays the current playing queue of items. When the drawer is closed,
* the view is switched back to the drawer root.
*/
public void showPlayQueue() {
mRootAdapter.setFetcher(createMediaQueueItemsFetcher());
mRootAdapter.setTitle(mMediaPlaybackModel.getQueueTitle());
mActivity.openDrawer();
mRootAdapter.scrollToCurrent();
mActivity.addDrawerListener(mQueueDrawerListener);
}
public void cleanup() {
mActivity.removeDrawerListener(mQueueDrawerListener);
mRootAdapter.cleanup();
mMediaPlaybackModel.removeListener(mModelListener);
mMediaPlaybackModel.stop();
}
/**
* @return Adapter to display root items of MediaBrowse tree. {@link #showPlayQueue()} can
* be used to display items from the queue.
*/
public CarDrawerAdapter getRootAdapter() {
return mRootAdapter;
}
/**
* Creates a {@link MediaBrowserItemsFetcher} that whose root is the given {@code mediaId}.
*/
private MediaBrowserItemsFetcher createMediaBrowserItemFetcher(String mediaId,
boolean showQueueItem) {
return new MediaBrowserItemsFetcher(mActivity, mMediaPlaybackModel, this /* listener */,
mediaId, showQueueItem);
}
/**
* Creates a {@link MediaQueueItemsFetcher} that is responsible for fetching items in the user's
* current play queue.
*/
private MediaQueueItemsFetcher createMediaQueueItemsFetcher() {
return new MediaQueueItemsFetcher(mActivity, mMediaPlaybackModel, this /* listener */);
}
/**
* Creates a {@link MediaItemsFetcher} that will display the top-most level of the drawer.
*/
private MediaItemsFetcher createRootMediaItemsFetcher() {
return createMediaBrowserItemFetcher(mMediaPlaybackModel.getMediaBrowser().getRoot(),
true /* showQueueItem */);
}
/**
* A {@link android.support.v4.widget.DrawerLayout.DrawerListener} specifically to be used when
* the play queue has been shown in the drawer. When the drawer is closed following this
* display, this listener will reset the drawer to display the root view.
*/
private final DrawerLayout.DrawerListener mQueueDrawerListener =
new DrawerLayout.DrawerListener() {
@Override
public void onDrawerClosed(View drawerView) {
mRootAdapter.setFetcher(createRootMediaItemsFetcher());
mRootAdapter.setTitle(
MediaManager.getInstance(mActivity).getMediaClientName());
mActivity.removeDrawerListener(this);
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {}
@Override
public void onDrawerOpened(View drawerView) {}
@Override
public void onDrawerStateChanged(int newState) {}
};
private final MediaPlaybackModel.Listener mModelListener =
new MediaPlaybackModel.AbstractListener() {
@Override
public void onMediaAppChanged(@Nullable ComponentName currentName,
@Nullable ComponentName newName) {
// Only store MediaManager instance to a local variable when it is short lived.
MediaManager mediaManager = MediaManager.getInstance(mActivity);
mRootAdapter.setTitle(mediaManager.getMediaClientName());
}
@Override
public void onMediaConnected() {
mRootAdapter.setFetcher(createRootMediaItemsFetcher());
}
};
}