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