blob: 1512b52f11ab0072ad71a28218311a8cd94fe101 [file] [log] [blame]
/*
* Copyright (C) 2013 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.example.android.supportv7.media;
import com.example.android.supportv7.R;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.content.res.Resources;
import android.media.MediaRouter;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaItemStatus;
import android.support.v7.media.MediaRouteProvider;
import android.support.v7.media.MediaRouter.ControlRequestCallback;
import android.support.v7.media.MediaRouteProviderDescriptor;
import android.support.v7.media.MediaRouteDescriptor;
import android.util.Log;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.UUID;
/**
* Demonstrates how to create a custom media route provider.
*
* @see SampleMediaRouteProviderService
*/
final class SampleMediaRouteProvider extends MediaRouteProvider {
private static final String TAG = "SampleMediaRouteProvider";
private static final String FIXED_VOLUME_ROUTE_ID = "fixed";
private static final String VARIABLE_VOLUME_ROUTE_ID = "variable";
private static final int VOLUME_MAX = 10;
/**
* A custom media control intent category for special requests that are
* supported by this provider's routes.
*/
public static final String CATEGORY_SAMPLE_ROUTE =
"com.example.android.supportv7.media.CATEGORY_SAMPLE_ROUTE";
/**
* A custom media control intent action for special requests that are
* supported by this provider's routes.
* <p>
* This particular request is designed to return a bundle of not very
* interesting statistics for demonstration purposes.
* </p>
*
* @see #DATA_PLAYBACK_COUNT
*/
public static final String ACTION_GET_STATISTICS =
"com.example.android.supportv7.media.ACTION_GET_STATISTICS";
/**
* {@link #ACTION_GET_STATISTICS} result data: Number of times the
* playback action was invoked.
*/
public static final String DATA_PLAYBACK_COUNT =
"com.example.android.supportv7.media.EXTRA_PLAYBACK_COUNT";
private static final ArrayList<IntentFilter> CONTROL_FILTERS;
static {
IntentFilter f1 = new IntentFilter();
f1.addCategory(CATEGORY_SAMPLE_ROUTE);
f1.addAction(ACTION_GET_STATISTICS);
IntentFilter f2 = new IntentFilter();
f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
f2.addAction(MediaControlIntent.ACTION_PLAY);
f2.addDataScheme("http");
f2.addDataScheme("https");
addDataTypeUnchecked(f2, "video/*");
CONTROL_FILTERS = new ArrayList<IntentFilter>();
CONTROL_FILTERS.add(f1);
CONTROL_FILTERS.add(f2);
}
private static void addDataTypeUnchecked(IntentFilter filter, String type) {
try {
filter.addDataType(type);
} catch (MalformedMimeTypeException ex) {
throw new RuntimeException(ex);
}
}
private int mVolume = 5;
private int mPlaybackCount;
public SampleMediaRouteProvider(Context context) {
super(context);
publishRoutes();
}
@Override
public RouteController onCreateRouteController(String routeId) {
return new SampleRouteController(routeId);
}
private void publishRoutes() {
Resources r = getContext().getResources();
MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
FIXED_VOLUME_ROUTE_ID,
r.getString(R.string.fixed_volume_route_name))
.setDescription(r.getString(R.string.sample_route_description))
.addControlFilters(CONTROL_FILTERS)
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
.setVolume(VOLUME_MAX)
.build();
MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
VARIABLE_VOLUME_ROUTE_ID,
r.getString(R.string.variable_volume_route_name))
.setDescription(r.getString(R.string.sample_route_description))
.addControlFilters(CONTROL_FILTERS)
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
.setVolumeMax(VOLUME_MAX)
.setVolume(mVolume)
.build();
MediaRouteProviderDescriptor providerDescriptor =
new MediaRouteProviderDescriptor.Builder()
.addRoute(routeDescriptor1)
.addRoute(routeDescriptor2)
.build();
setDescriptor(providerDescriptor);
}
private String generateStreamId() {
return UUID.randomUUID().toString();
}
private final class SampleRouteController extends MediaRouteProvider.RouteController {
private final String mRouteId;
public SampleRouteController(String routeId) {
mRouteId = routeId;
Log.d(TAG, mRouteId + ": Controller created");
}
@Override
public void onRelease() {
Log.d(TAG, mRouteId + ": Controller released");
}
@Override
public void onSelect() {
Log.d(TAG, mRouteId + ": Selected");
}
@Override
public void onUnselect() {
Log.d(TAG, mRouteId + ": Unselected");
}
@Override
public void onSetVolume(int volume) {
Log.d(TAG, mRouteId + ": Set volume to " + volume);
if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) {
setVolumeInternal(volume);
}
}
@Override
public void onUpdateVolume(int delta) {
Log.d(TAG, mRouteId + ": Update volume by " + delta);
if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) {
setVolumeInternal(mVolume + delta);
}
}
private void setVolumeInternal(int volume) {
if (volume >= 0 && volume <= VOLUME_MAX) {
mVolume = volume;
Log.d(TAG, mRouteId + ": New volume is " + mVolume);
publishRoutes();
}
}
@Override
public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
Log.d(TAG, mRouteId + ": Received control request " + intent);
if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)
&& intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
&& intent.getData() != null) {
mPlaybackCount +=1;
Uri uri = intent.getData();
int queueBehavior = intent.getIntExtra(
MediaControlIntent.EXTRA_ITEM_QUEUE_BEHAVIOR,
MediaControlIntent.ITEM_QUEUE_BEHAVIOR_PLAY_NOW);
double contentPosition = intent.getDoubleExtra(
MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0);
Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA);
Bundle headers = intent.getBundleExtra(
MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS);
Log.d(TAG, mRouteId + ": Received play request, uri=" + uri
+ ", queueBehavior=" + queueBehavior
+ ", contentPosition=" + contentPosition
+ ", metadata=" + metadata
+ ", headers=" + headers);
if (uri.toString().contains("hats")) {
// Simulate generating an error whenever the uri contains the word 'hats'.
Toast.makeText(getContext(), "Route rejected play request: uri=" + uri
+ ", no hats allowed!", Toast.LENGTH_LONG).show();
if (callback != null) {
callback.onError("Simulated error. No hats allowed!", null);
}
} else {
Toast.makeText(getContext(), "Route received play request: uri=" + uri,
Toast.LENGTH_LONG).show();
String streamId = generateStreamId();
if (callback != null) {
MediaItemStatus status = new MediaItemStatus.Builder(
MediaItemStatus.PLAYBACK_STATE_PLAYING)
.setContentPosition(contentPosition)
.build();
Bundle result = new Bundle();
result.putString(MediaControlIntent.EXTRA_ITEM_ID, streamId);
result.putBundle(MediaControlIntent.EXTRA_ITEM_STATUS, status.asBundle());
callback.onResult(result);
}
}
return true;
}
if (intent.getAction().equals(ACTION_GET_STATISTICS)
&& intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
Bundle data = new Bundle();
data.putInt(DATA_PLAYBACK_COUNT, mPlaybackCount);
if (callback != null) {
callback.onResult(data);
}
return true;
}
return false;
}
}
}