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 17 package com.example.android.supportv7.media; 18 19 import com.example.android.supportv7.R; 20 21 import android.content.Intent; 22 import android.net.Uri; 23 import android.os.Bundle; 24 import android.support.v4.app.FragmentManager; 25 import android.support.v4.view.MenuItemCompat; 26 import android.support.v7.app.ActionBarActivity; 27 import android.support.v7.app.MediaRouteActionProvider; 28 import android.support.v7.app.MediaRouteDiscoveryFragment; 29 import android.support.v7.media.MediaControlIntent; 30 import android.support.v7.media.MediaRouter; 31 import android.support.v7.media.MediaRouter.Callback; 32 import android.support.v7.media.MediaRouter.RouteInfo; 33 import android.support.v7.media.MediaRouter.ProviderInfo; 34 import android.support.v7.media.MediaRouteSelector; 35 import android.util.Log; 36 import android.view.Menu; 37 import android.view.MenuItem; 38 import android.view.View; 39 import android.view.View.OnClickListener; 40 import android.widget.AdapterView.OnItemClickListener; 41 import android.widget.AdapterView; 42 import android.widget.ArrayAdapter; 43 import android.widget.Button; 44 import android.widget.ListView; 45 import android.widget.TextView; 46 import android.widget.Toast; 47 48 /** 49 * <h3>Media Router Support Activity</h3> 50 * 51 * <p> 52 * This demonstrates how to use the {@link MediaRouter} API to build an 53 * application that allows the user to send content to various rendering 54 * targets. 55 * </p> 56 */ 57 public class SampleMediaRouterActivity extends ActionBarActivity { 58 private static final String TAG = "MediaRouterSupport"; 59 private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment"; 60 61 private MediaRouter mMediaRouter; 62 private MediaRouteSelector mSelector; 63 private ArrayAdapter<MediaItem> mMediaItems; 64 private TextView mInfoTextView; 65 private ListView mMediaListView; 66 private Button mPlayButton; 67 private Button mStatisticsButton; 68 69 @Override onCreate(Bundle savedInstanceState)70 protected void onCreate(Bundle savedInstanceState) { 71 // Be sure to call the super class. 72 super.onCreate(savedInstanceState); 73 74 // Get the media router service. 75 mMediaRouter = MediaRouter.getInstance(this); 76 77 // Create a route selector for the type of routes that we care about. 78 mSelector = new MediaRouteSelector.Builder() 79 .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO) 80 .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) 81 .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 82 .addControlCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE) 83 .build(); 84 85 // Add a fragment to take care of media route discovery. 86 // This fragment automatically adds or removes a callback whenever the activity 87 // is started or stopped. 88 FragmentManager fm = getSupportFragmentManager(); 89 if (fm.findFragmentByTag(DISCOVERY_FRAGMENT_TAG) == null) { 90 DiscoveryFragment fragment = new DiscoveryFragment(); 91 fragment.setRouteSelector(mSelector); 92 fm.beginTransaction() 93 .add(fragment, DISCOVERY_FRAGMENT_TAG) 94 .commit(); 95 } 96 97 // Populate an array adapter with fake media items. 98 String[] mediaNames = getResources().getStringArray(R.array.media_names); 99 String[] mediaUris = getResources().getStringArray(R.array.media_uris); 100 mMediaItems = new ArrayAdapter<MediaItem>(this, 101 android.R.layout.simple_list_item_single_choice, android.R.id.text1); 102 for (int i = 0; i < mediaNames.length; i++) { 103 mMediaItems.add(new MediaItem(mediaNames[i], Uri.parse(mediaUris[i]))); 104 } 105 106 // Initialize the layout. 107 setContentView(R.layout.sample_media_router); 108 109 mInfoTextView = (TextView)findViewById(R.id.info); 110 111 mMediaListView = (ListView)findViewById(R.id.media); 112 mMediaListView.setAdapter(mMediaItems); 113 mMediaListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 114 mMediaListView.setOnItemClickListener(new OnItemClickListener() { 115 @Override 116 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 117 updateButtons(); 118 } 119 }); 120 121 mPlayButton = (Button)findViewById(R.id.play_button); 122 mPlayButton.setOnClickListener(new OnClickListener() { 123 @Override 124 public void onClick(View v) { 125 play(); 126 } 127 }); 128 129 mStatisticsButton = (Button)findViewById(R.id.statistics_button); 130 mStatisticsButton.setOnClickListener(new OnClickListener() { 131 @Override 132 public void onClick(View v) { 133 showStatistics(); 134 } 135 }); 136 } 137 138 @Override onStart()139 public void onStart() { 140 // Be sure to call the super class. 141 super.onStart(); 142 143 updateRouteDescription(); 144 } 145 146 @Override onCreateOptionsMenu(Menu menu)147 public boolean onCreateOptionsMenu(Menu menu) { 148 // Be sure to call the super class. 149 super.onCreateOptionsMenu(menu); 150 151 // Inflate the menu and configure the media router action provider. 152 getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); 153 154 MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); 155 MediaRouteActionProvider mediaRouteActionProvider = 156 (MediaRouteActionProvider)MenuItemCompat.getActionProvider(mediaRouteMenuItem); 157 mediaRouteActionProvider.setRouteSelector(mSelector); 158 159 // Return true to show the menu. 160 return true; 161 } 162 updateRouteDescription()163 private void updateRouteDescription() { 164 RouteInfo route = mMediaRouter.getSelectedRoute(); 165 mInfoTextView.setText("Currently selected route: " + route.getName() 166 + " from provider " + route.getProvider().getPackageName() 167 + ", description: " + route.getDescription()); 168 updateButtons(); 169 } 170 updateButtons()171 private void updateButtons() { 172 MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(); 173 174 MediaItem item = getCheckedMediaItem(); 175 if (item != null) { 176 mPlayButton.setEnabled(route.supportsControlRequest(makePlayIntent(item))); 177 } else { 178 mPlayButton.setEnabled(false); 179 } 180 181 mStatisticsButton.setEnabled(route.supportsControlRequest(makeStatisticsIntent())); 182 } 183 play()184 private void play() { 185 final MediaItem item = getCheckedMediaItem(); 186 if (item == null) { 187 return; 188 } 189 190 MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(); 191 Intent intent = makePlayIntent(item); 192 if (route.supportsControlRequest(intent)) { 193 MediaRouter.ControlRequestCallback callback = 194 new MediaRouter.ControlRequestCallback() { 195 @Override 196 public void onResult(Bundle data) { 197 String streamId = data != null ? data.getString( 198 MediaControlIntent.EXTRA_ITEM_ID) : null; 199 200 Log.d(TAG, "Play request succeeded: data=" + data + " , streamId=" + streamId); 201 Toast.makeText(SampleMediaRouterActivity.this, 202 "Now playing " + item.mName, 203 Toast.LENGTH_LONG).show(); 204 } 205 206 @Override 207 public void onError(String error, Bundle data) { 208 Log.d(TAG, "Play request failed: error=" + error + ", data=" + data); 209 Toast.makeText(SampleMediaRouterActivity.this, 210 "Unable to play " + item.mName + ", error: " + error, 211 Toast.LENGTH_LONG).show(); 212 } 213 }; 214 215 Log.d(TAG, "Sending play request: intent=" + intent); 216 route.sendControlRequest(intent, callback); 217 } else { 218 Log.d(TAG, "Play request not supported: intent=" + intent); 219 Toast.makeText(SampleMediaRouterActivity.this, 220 "Play not supported for " + item.mName, Toast.LENGTH_LONG).show(); 221 } 222 } 223 showStatistics()224 private void showStatistics() { 225 MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(); 226 Intent intent = makeStatisticsIntent(); 227 if (route.supportsControlRequest(intent)) { 228 MediaRouter.ControlRequestCallback callback = new MediaRouter.ControlRequestCallback() { 229 @Override 230 public void onResult(Bundle data) { 231 Log.d(TAG, "Statistics request succeeded: data=" + data); 232 if (data != null) { 233 int playbackCount = data.getInt( 234 SampleMediaRouteProvider.DATA_PLAYBACK_COUNT, -1); 235 Toast.makeText(SampleMediaRouterActivity.this, 236 "Total playback count: " + playbackCount, 237 Toast.LENGTH_LONG).show(); 238 } else { 239 Toast.makeText(SampleMediaRouterActivity.this, 240 "Statistics query did not return any data", 241 Toast.LENGTH_LONG).show(); 242 } 243 } 244 245 @Override 246 public void onError(String error, Bundle data) { 247 Log.d(TAG, "Statistics request failed: error=" + error + ", data=" + data); 248 Toast.makeText(SampleMediaRouterActivity.this, 249 "Unable to query statistics, error: " + error, 250 Toast.LENGTH_LONG).show(); 251 } 252 }; 253 254 Log.d(TAG, "Sent statistics request: intent=" + intent); 255 route.sendControlRequest(intent, callback); 256 } else { 257 Log.d(TAG, "Statistics request not supported: intent=" + intent); 258 Toast.makeText(SampleMediaRouterActivity.this, 259 "Statistics not supported.", Toast.LENGTH_LONG).show(); 260 } 261 } 262 makePlayIntent(MediaItem item)263 private Intent makePlayIntent(MediaItem item) { 264 Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); 265 intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); 266 intent.setDataAndType(item.mUri, "video/mp4"); 267 return intent; 268 } 269 makeStatisticsIntent()270 private Intent makeStatisticsIntent() { 271 Intent intent = new Intent(SampleMediaRouteProvider.ACTION_GET_STATISTICS); 272 intent.addCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE); 273 return intent; 274 } 275 getCheckedMediaItem()276 private MediaItem getCheckedMediaItem() { 277 int index = mMediaListView.getCheckedItemPosition(); 278 if (index >= 0 && index < mMediaItems.getCount()) { 279 return mMediaItems.getItem(index); 280 } 281 return null; 282 } 283 284 private final class DiscoveryFragment extends MediaRouteDiscoveryFragment { 285 @Override onCreateCallback()286 public Callback onCreateCallback() { 287 // Return a custom callback that will simply log all of the route events 288 // for demonstration purposes. 289 return new MediaRouter.Callback() { 290 @Override 291 public void onRouteAdded(MediaRouter router, RouteInfo route) { 292 Log.d(TAG, "onRouteAdded: route=" + route); 293 } 294 295 @Override 296 public void onRouteChanged(MediaRouter router, RouteInfo route) { 297 Log.d(TAG, "onRouteChanged: route=" + route); 298 updateRouteDescription(); 299 } 300 301 @Override 302 public void onRouteRemoved(MediaRouter router, RouteInfo route) { 303 Log.d(TAG, "onRouteRemoved: route=" + route); 304 } 305 306 @Override 307 public void onRouteSelected(MediaRouter router, RouteInfo route) { 308 Log.d(TAG, "onRouteSelected: route=" + route); 309 updateRouteDescription(); 310 } 311 312 @Override 313 public void onRouteUnselected(MediaRouter router, RouteInfo route) { 314 Log.d(TAG, "onRouteUnselected: route=" + route); 315 updateRouteDescription(); 316 } 317 318 @Override 319 public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { 320 Log.d(TAG, "onRouteVolumeChanged: route=" + route); 321 } 322 323 @Override 324 public void onRoutePresentationDisplayChanged( 325 MediaRouter router, RouteInfo route) { 326 Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route); 327 } 328 329 @Override 330 public void onProviderAdded(MediaRouter router, ProviderInfo provider) { 331 Log.d(TAG, "onRouteProviderAdded: provider=" + provider); 332 } 333 334 @Override 335 public void onProviderRemoved(MediaRouter router, ProviderInfo provider) { 336 Log.d(TAG, "onRouteProviderRemoved: provider=" + provider); 337 } 338 339 @Override 340 public void onProviderChanged(MediaRouter router, ProviderInfo provider) { 341 Log.d(TAG, "onRouteProviderChanged: provider=" + provider); 342 } 343 }; 344 } 345 346 @Override onPrepareCallbackFlags()347 public int onPrepareCallbackFlags() { 348 // Add the CALLBACK_FLAG_UNFILTERED_EVENTS flag to ensure that we will 349 // observe and log all route events including those that are for routes 350 // that do not match our selector. This is only for demonstration purposes 351 // and should not be needed by most applications. 352 return super.onPrepareCallbackFlags() 353 | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS; 354 } 355 } 356 357 private static final class MediaItem { 358 public final String mName; 359 public final Uri mUri; 360 361 public MediaItem(String name, Uri uri) { 362 mName = name; 363 mUri = uri; 364 } 365 366 @Override 367 public String toString() { 368 return mName; 369 } 370 } 371 372 /** 373 * Trivial subclass of this activity used to provide another copy of the 374 * same activity using a light theme instead of the dark theme. 375 */ 376 public static class Light extends SampleMediaRouterActivity { 377 } 378 379 /** 380 * Trivial subclass of this activity used to provide another copy of the 381 * same activity using a light theme with dark action bar instead of the dark theme. 382 */ 383 public static class LightWithDarkActionBar extends SampleMediaRouterActivity { 384 } 385 } 386