1 /* 2 * Copyright 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.basicmediarouter; 18 19 import android.app.Activity; 20 import android.app.MediaRouteActionProvider; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.media.MediaRouter; 24 import android.media.MediaRouter.RouteInfo; 25 import android.os.Bundle; 26 import android.view.Display; 27 import android.view.Menu; 28 import android.view.MenuItem; 29 import android.view.View; 30 import android.view.WindowManager; 31 import android.widget.Button; 32 import android.widget.TextView; 33 34 /** 35 * <p> 36 * This sample demonstrates the use of the MediaRouter API to show content on a 37 * secondary display using a {@link android.app.Presentation}. 38 * </p> 39 * <p> 40 * The activity uses the {@link android.media.MediaRouter} API to automatically detect when a 41 * presentation display is available and to allow the user to control the media 42 * routes using a menu item provided by the {@link android.app.MediaRouteActionProvider}. 43 * When a presentation display is available a {@link android.app.Presentation} (implemented 44 * as a {@link SamplePresentation}) is shown on the preferred display. A button 45 * toggles the background color of the secondary screen to show the interaction 46 * between the primary and secondary screens. 47 * </p> 48 * <p> 49 * This sample requires an HDMI or Wifi display. Alternatively, the 50 * "Simulate secondary displays" feature in Development Settings can be enabled 51 * to simulate secondary displays. 52 * </p> 53 * 54 * @see android.app.Presentation 55 * @see android.media.MediaRouter 56 */ 57 public class MainActivity extends Activity { 58 59 private MediaRouter mMediaRouter; 60 61 // Active Presentation, set to null if no secondary screen is enabled 62 private SamplePresentation mPresentation; 63 64 @Override onCreate(Bundle savedInstanceState)65 protected void onCreate(Bundle savedInstanceState) { 66 super.onCreate(savedInstanceState); 67 68 setContentView(R.layout.sample_main); 69 mTextStatus = (TextView) findViewById(R.id.textStatus); 70 71 // get the list of background colors 72 mColors = getResources().getIntArray(R.array.androidcolors); 73 74 // Enable clicks on the 'change color' button 75 mButton = (Button) findViewById(R.id.button1); 76 mButton.setOnClickListener(new View.OnClickListener() { 77 78 @Override 79 public void onClick(View v) { 80 showNextColor(); 81 } 82 }); 83 84 // BEGIN_INCLUDE(getMediaRouter) 85 // Get the MediaRouter service 86 mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE); 87 // END_INCLUDE(getMediaRouter) 88 } 89 90 /** 91 * Implementing a {@link android.media.MediaRouter.Callback} to update the displayed 92 * {@link android.app.Presentation} when a route is selected, unselected or the 93 * presentation display has changed. The provided stub implementation 94 * {@link android.media.MediaRouter.SimpleCallback} is extended and only 95 * {@link android.media.MediaRouter.SimpleCallback#onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo)} 96 * , 97 * {@link android.media.MediaRouter.SimpleCallback#onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo)} 98 * and 99 * {@link android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo)} 100 * are overridden to update the displayed {@link android.app.Presentation} in 101 * {@link #updatePresentation()}. These callbacks enable or disable the 102 * second screen presentation based on the routing provided by the 103 * {@link android.media.MediaRouter} for {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} 104 * streams. @ 105 */ 106 private final MediaRouter.SimpleCallback mMediaRouterCallback = 107 new MediaRouter.SimpleCallback() { 108 109 // BEGIN_INCLUDE(SimpleCallback) 110 /** 111 * A new route has been selected as active. Disable the current 112 * route and enable the new one. 113 */ 114 @Override 115 public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { 116 updatePresentation(); 117 } 118 119 /** 120 * The route has been unselected. 121 */ 122 @Override 123 public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { 124 updatePresentation(); 125 126 } 127 128 /** 129 * The route's presentation display has changed. This callback 130 * is called when the presentation has been activated, removed 131 * or its properties have changed. 132 */ 133 @Override 134 public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { 135 updatePresentation(); 136 } 137 // END_INCLUDE(SimpleCallback) 138 }; 139 140 /** 141 * Updates the displayed presentation to enable a secondary screen if it has 142 * been selected in the {@link android.media.MediaRouter} for the 143 * {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} type. If no screen has been 144 * selected by the {@link android.media.MediaRouter}, the current screen is disabled. 145 * Otherwise a new {@link SamplePresentation} is initialized and shown on 146 * the secondary screen. 147 */ updatePresentation()148 private void updatePresentation() { 149 150 // BEGIN_INCLUDE(updatePresentationInit) 151 // Get the selected route for live video 152 RouteInfo selectedRoute = mMediaRouter.getSelectedRoute( 153 MediaRouter.ROUTE_TYPE_LIVE_VIDEO); 154 155 // Get its Display if a valid route has been selected 156 Display selectedDisplay = null; 157 if (selectedRoute != null) { 158 selectedDisplay = selectedRoute.getPresentationDisplay(); 159 } 160 // END_INCLUDE(updatePresentationInit) 161 162 // BEGIN_INCLUDE(updatePresentationDismiss) 163 /* 164 * Dismiss the current presentation if the display has changed or no new 165 * route has been selected 166 */ 167 if (mPresentation != null && mPresentation.getDisplay() != selectedDisplay) { 168 mPresentation.dismiss(); 169 mPresentation = null; 170 mButton.setEnabled(false); 171 mTextStatus.setText(R.string.secondary_notconnected); 172 } 173 // END_INCLUDE(updatePresentationDismiss) 174 175 // BEGIN_INCLUDE(updatePresentationNew) 176 /* 177 * Show a new presentation if the previous one has been dismissed and a 178 * route has been selected. 179 */ 180 if (mPresentation == null && selectedDisplay != null) { 181 182 // Initialise a new Presentation for the Display 183 mPresentation = new SamplePresentation(this, selectedDisplay); 184 mPresentation.setOnDismissListener(mOnDismissListener); 185 186 // Try to show the presentation, this might fail if the display has 187 // gone away in the mean time 188 try { 189 mPresentation.show(); 190 mTextStatus.setText(getResources().getString(R.string.secondary_connected, 191 selectedRoute.getName(MainActivity.this))); 192 mButton.setEnabled(true); 193 showNextColor(); 194 } catch (WindowManager.InvalidDisplayException ex) { 195 // Couldn't show presentation - display was already removed 196 mPresentation = null; 197 } 198 } 199 // END_INCLUDE(updatePresentationNew) 200 201 } 202 203 @Override onResume()204 protected void onResume() { 205 super.onResume(); 206 207 // BEGIN_INCLUDE(addCallback) 208 // Register a callback for all events related to live video devices 209 mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mMediaRouterCallback); 210 // END_INCLUDE(addCallback) 211 212 // Show the 'Not connected' status message 213 mButton.setEnabled(false); 214 mTextStatus.setText(R.string.secondary_notconnected); 215 216 // Update the displays based on the currently active routes 217 updatePresentation(); 218 } 219 220 @Override onPause()221 protected void onPause() { 222 super.onPause(); 223 224 // BEGIN_INCLUDE(onPause) 225 // Stop listening for changes to media routes. 226 mMediaRouter.removeCallback(mMediaRouterCallback); 227 // END_INCLUDE(onPause) 228 } 229 230 @Override onStop()231 protected void onStop() { 232 super.onStop(); 233 234 // BEGIN_INCLUDE(onStop) 235 // Dismiss the presentation when the activity is not visible. 236 if (mPresentation != null) { 237 mPresentation.dismiss(); 238 mPresentation = null; 239 } 240 // BEGIN_INCLUDE(onStop) 241 } 242 243 /** 244 * Inflates the ActionBar or options menu. The menu file defines an item for 245 * the {@link android.app.MediaRouteActionProvider}, which is registered here for all 246 * live video devices using {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO}. 247 */ 248 @Override onCreateOptionsMenu(Menu menu)249 public boolean onCreateOptionsMenu(Menu menu) { 250 super.onCreateOptionsMenu(menu); 251 252 getMenuInflater().inflate(R.menu.main, menu); 253 254 // BEGIN_INCLUDE(MediaRouteActionProvider) 255 // Configure the media router action provider 256 MenuItem mediaRouteMenuItem = menu.findItem(R.id.menu_media_route); 257 MediaRouteActionProvider mediaRouteActionProvider = 258 (MediaRouteActionProvider) mediaRouteMenuItem.getActionProvider(); 259 mediaRouteActionProvider.setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); 260 // BEGIN_INCLUDE(MediaRouteActionProvider) 261 262 return true; 263 } 264 265 /** 266 * Listens for dismissal of the {@link SamplePresentation} and removes its 267 * reference. 268 */ 269 private final DialogInterface.OnDismissListener mOnDismissListener = 270 new DialogInterface.OnDismissListener() { 271 @Override 272 public void onDismiss(DialogInterface dialog) { 273 if (dialog == mPresentation) { 274 mPresentation = null; 275 } 276 } 277 }; 278 279 // Views used to display status information on the primary screen 280 private TextView mTextStatus; 281 private Button mButton; 282 283 // selected color index 284 private int mColor = 0; 285 286 // background colors 287 public int[] mColors; 288 289 /** 290 * Displays the next color on the secondary screen if it is activate. 291 */ showNextColor()292 private void showNextColor() { 293 if (mPresentation != null) { 294 // a second screen is active and initialized, show the next color 295 mPresentation.setColor(mColors[mColor]); 296 mColor = (mColor + 1) % mColors.length; 297 } 298 } 299 300 } 301