SampleMediaRouteProvider.java revision 5b715a47c96bae4dace1eecd05f378e5c42108fe
1/* 2 * Copyright (C) 2013 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 17package com.example.android.supportv7.media; 18 19import com.example.android.supportv7.R; 20 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.IntentFilter.MalformedMimeTypeException; 25import android.content.res.Resources; 26import android.media.MediaRouter; 27import android.net.Uri; 28import android.os.Bundle; 29import android.support.v7.media.MediaControlIntent; 30import android.support.v7.media.MediaRouteProvider; 31import android.support.v7.media.MediaRouter.ControlRequestCallback; 32import android.util.Log; 33import android.widget.Toast; 34 35import java.util.UUID; 36 37/** 38 * Demonstrates how to create a custom media route provider. 39 * 40 * @see SampleMediaRouteProviderService 41 */ 42final class SampleMediaRouteProvider extends MediaRouteProvider { 43 private static final String TAG = "SampleMediaRouteProvider"; 44 45 private static final String FIXED_VOLUME_ROUTE_ID = "fixed"; 46 private static final String VARIABLE_VOLUME_ROUTE_ID = "variable"; 47 private static final int VOLUME_MAX = 10; 48 49 /** 50 * A custom media control intent category for special requests that are 51 * supported by this provider's routes. 52 */ 53 public static final String CATEGORY_SAMPLE_ROUTE = 54 "com.example.android.supportv4.media.CATEGORY_SAMPLE_ROUTE"; 55 56 /** 57 * A custom media control intent action for special requests that are 58 * supported by this provider's routes. 59 * <p> 60 * This particular request is designed to return a bundle of not very 61 * interesting statistics for demonstration purposes. 62 * </p> 63 * 64 * @see #DATA_PLAYBACK_COUNT 65 */ 66 public static final String ACTION_GET_STATISTICS = 67 "com.example.android.supportv4.media.ACTION_GET_STATISTICS"; 68 69 /** 70 * {@link #ACTION_GET_STATISTICS} result data: Number of times the 71 * playback action was invoked. 72 */ 73 public static final String DATA_PLAYBACK_COUNT = 74 "com.example.android.supportv4.media.EXTRA_PLAYBACK_COUNT"; 75 76 private static final IntentFilter[] CONTROL_FILTERS; 77 static { 78 CONTROL_FILTERS = new IntentFilter[2]; 79 80 CONTROL_FILTERS[0] = new IntentFilter(); 81 CONTROL_FILTERS[0].addCategory(CATEGORY_SAMPLE_ROUTE); 82 CONTROL_FILTERS[0].addAction(ACTION_GET_STATISTICS); 83 84 CONTROL_FILTERS[1] = new IntentFilter(); 85 CONTROL_FILTERS[1].addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 86 CONTROL_FILTERS[1].addAction(MediaControlIntent.ACTION_PLAY); 87 CONTROL_FILTERS[1].addDataScheme("http"); 88 CONTROL_FILTERS[1].addDataScheme("https"); 89 addDataTypeUnchecked(CONTROL_FILTERS[1], "video/*"); 90 } 91 92 private static void addDataTypeUnchecked(IntentFilter filter, String type) { 93 try { 94 filter.addDataType(type); 95 } catch (MalformedMimeTypeException ex) { 96 throw new RuntimeException(ex); 97 } 98 } 99 100 private int mVolume = 5; 101 private int mPlaybackCount; 102 103 public SampleMediaRouteProvider(Context context) { 104 super(context); 105 106 publishRoutes(); 107 } 108 109 @Override 110 public RouteController onCreateRouteController(String routeId) { 111 return new SampleRouteController(routeId); 112 } 113 114 private void publishRoutes() { 115 Resources r = getContext().getResources(); 116 117 RouteDescriptor routeDescriptor1 = new RouteDescriptor( 118 FIXED_VOLUME_ROUTE_ID, 119 r.getString(R.string.fixed_volume_route_name)); 120 routeDescriptor1.setControlFilters(CONTROL_FILTERS); 121 routeDescriptor1.setIconResource(R.drawable.media_route_icon); 122 routeDescriptor1.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE); 123 routeDescriptor1.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED); 124 routeDescriptor1.setVolume(VOLUME_MAX); 125 126 RouteDescriptor routeDescriptor2 = new RouteDescriptor( 127 VARIABLE_VOLUME_ROUTE_ID, 128 r.getString(R.string.variable_volume_route_name)); 129 routeDescriptor2.setControlFilters(CONTROL_FILTERS); 130 routeDescriptor2.setIconResource(R.drawable.media_route_icon); 131 routeDescriptor2.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE); 132 routeDescriptor2.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE); 133 routeDescriptor2.setVolumeMax(VOLUME_MAX); 134 routeDescriptor2.setVolume(mVolume); 135 136 ProviderDescriptor providerDescriptor = new ProviderDescriptor(); 137 providerDescriptor.setRoutes(new RouteDescriptor[] { 138 routeDescriptor1, routeDescriptor2 139 }); 140 setDescriptor(providerDescriptor); 141 } 142 143 private String generateStreamId() { 144 return UUID.randomUUID().toString(); 145 } 146 147 private final class SampleRouteController extends MediaRouteProvider.RouteController { 148 private final String mRouteId; 149 150 public SampleRouteController(String routeId) { 151 mRouteId = routeId; 152 Log.d(TAG, mRouteId + ": Controller created"); 153 } 154 155 @Override 156 public void onRelease() { 157 Log.d(TAG, mRouteId + ": Controller released"); 158 } 159 160 @Override 161 public void onSelect() { 162 Log.d(TAG, mRouteId + ": Selected"); 163 } 164 165 @Override 166 public void onUnselect() { 167 Log.d(TAG, mRouteId + ": Unselected"); 168 } 169 170 @Override 171 public void onSetVolume(int volume) { 172 Log.d(TAG, mRouteId + ": Set volume to " + volume); 173 if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) { 174 setVolumeInternal(volume); 175 } 176 } 177 178 @Override 179 public void onUpdateVolume(int delta) { 180 Log.d(TAG, mRouteId + ": Update volume by " + delta); 181 if (mRouteId.equals(VARIABLE_VOLUME_ROUTE_ID)) { 182 setVolumeInternal(mVolume + delta); 183 } 184 } 185 186 private void setVolumeInternal(int volume) { 187 if (volume >= 0 && volume <= VOLUME_MAX) { 188 mVolume = volume; 189 Log.d(TAG, mRouteId + ": New volume is " + mVolume); 190 publishRoutes(); 191 } 192 } 193 194 @Override 195 public boolean onControlRequest(Intent intent, ControlRequestCallback callback) { 196 Log.d(TAG, mRouteId + ": Received control request " + intent); 197 if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY) 198 && intent.hasCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 199 && intent.getData() != null) { 200 mPlaybackCount +=1; 201 202 Uri uri = intent.getData(); 203 int queueBehavior = intent.getIntExtra( 204 MediaControlIntent.EXTRA_ITEM_QUEUE_BEHAVIOR, 205 MediaControlIntent.ITEM_QUEUE_BEHAVIOR_PLAY_NOW); 206 int position = intent.getIntExtra( 207 MediaControlIntent.EXTRA_ITEM_POSITION, 0); 208 Bundle metadata = intent.getBundleExtra(MediaControlIntent.EXTRA_ITEM_METADATA); 209 Bundle headers = intent.getBundleExtra( 210 MediaControlIntent.EXTRA_ITEM_HTTP_HEADERS); 211 String streamId = generateStreamId(); 212 213 Log.d(TAG, mRouteId + ": Received play request, uri=" + uri 214 + ", queueBehavior=" + queueBehavior 215 + ", position=" + position 216 + ", metadata=" + metadata 217 + ", headers=" + headers); 218 Toast.makeText(getContext(), "Route received play request: uri=" + uri, 219 Toast.LENGTH_LONG).show(); 220 if (callback != null) { 221 Bundle result = new Bundle(); 222 result.putString(MediaControlIntent.EXTRA_ITEM_ID, streamId); 223 callback.onResult(ControlRequestCallback.REQUEST_SUCCEEDED, result); 224 } 225 return true; 226 } 227 228 if (intent.getAction().equals(ACTION_GET_STATISTICS) 229 && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) { 230 Bundle data = new Bundle(); 231 data.putInt(DATA_PLAYBACK_COUNT, mPlaybackCount); 232 if (callback != null) { 233 callback.onResult(ControlRequestCallback.REQUEST_SUCCEEDED, data); 234 } 235 return true; 236 } 237 return false; 238 } 239 } 240}