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