这个Demo演示了presentation的另一种选择Display的方式:利用MediaRouterAPI。
媒体路由服务一直保持着对系统中可用的音频和视频路由的追踪。当媒体路由被选择或取消选择或者路由首选的presentation显示屏幕发生变化时,它都会发送通知消息。所以一个应用程序可以非常简单地观察这些通知消息来并自动地在首选的presentation显示屏幕上显示或撤消一个presentation。
定义presentation的布局文件,在这里定义了一个android.opengl.GLSurfaceView,用于显示3D视图,还定义了一个显示当前display基本信息的textView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.opengl.GLSurfaceView
android:id="@+id/surface_view_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"/>
<TextView
android:id="@+id/tv_display_info"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="text"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="center"/>
</LinearLayout>
定义DemoPresentation类继承Presentation
public class DemoPresentation extends Presentation {
private GLSurfaceView surface_view;
private TextView tv_dipaly_info;
private Display display;
public DemoPresentation(Context outerContext, Display display) {
super(outerContext, display);
this.display=display;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.presentation_content);
surface_view=(GLSurfaceView) findViewById(R.id.surface_view_content);
tv_dipaly_info=(TextView) findViewById(R.id.tv_display_info);
//加载并渲染长方体模型
surface_view.setRenderer(new CubeRenderer());
tv_dipaly_info.setText("与prsentation相关联的屏幕是:"+display.getName());
}
public GLSurfaceView getSurface_view() {
return surface_view;
}
}
在这里我们用到了一个矩形的3D模型,所以我们需要创建出这个长方体的立体模型。
/**
* 定义一个3D模型,实现GLSurfaceView.Renderer接口,该接口是一个专门用于渲染3D的接口
* 实现该接口必须重载三个方法
* @author aaaa
*
*/
public class CubeRenderer implements Renderer {
float box[] = new float[] {
// FRONT
-0.5f, -0.5f, 0.5f,
0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// BACK
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// LEFT
-0.5f, -0.5f, 0.5f,
-0.5f, 0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
-0.5f, 0.5f, -0.5f,
// RIGHT
0.5f, -0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
// TOP
-0.5f, 0.5f, 0.5f,
0.5f, 0.5f, 0.5f,
-0.5f, 0.5f, -0.5f,
0.5f, 0.5f, -0.5f,
// BOTTOM
-0.5f, -0.5f, 0.5f,
-0.5f, -0.5f, -0.5f,
0.5f, -0.5f, 0.5f,
0.5f, -0.5f, -0.5f,
};
FloatBuffer cubeBuff;
private boolean mTranslucentBackground;
float xrot = 0.0f;
float yrot = 0.0f;
public CubeRenderer(boolean mTranslucentBackground) {
super();
this.mTranslucentBackground = mTranslucentBackground;
cubeBuff = makeFloatBuffer(box);
}
/**
* 将float数组转换存储在字节缓冲数组
* @param arr
* @return
*/
public FloatBuffer makeFloatBuffer(float[] arr) {
ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer fb = bb.asFloatBuffer();
fb.put(arr);
fb.position(0);
return fb;
}
public CubeRenderer() {
// TODO Auto-generated constructor stub
cubeBuff = makeFloatBuffer(box);//转换float数组
}
protected void init(GL10 gl) {
gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
if(mTranslucentBackground){
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}else{
gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glClearDepthf(1.0f);
gl.glDepthFunc(GL10.GL_LEQUAL);
gl.glShadeModel(GL10.GL_SMOOTH);
}
/**
* 创建时调用,通常在此进行初始化设置
*/
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
init(gl);
}
/**
* 视窗改变时调用,通常在此设置视窗范围以及透视,投影范围
*/
@Override
public void onSurfaceChanged(GL10 gl, int w, int h) {
// TODO Auto-generated method stub
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, ((float) w) / h, 0.1f, 10f);
}
/**
* 渲染绘图操作,重绘时调用
*/
@Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, 3, 0, 0, 0, 0, 1, 0);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeBuff);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glRotatef(xrot, 1, 0, 0);
gl.glRotatef(yrot, 0, 1, 0);
gl.glColor4f(1.0f, 0, 0, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);
gl.glColor4f(0, 1.0f, 0, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);
gl.glColor4f(0, 0, 1.0f, 1.0f);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);
xrot += 1.0f;
yrot += 0.5f;
}
}
创建主布局文件:activity.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffee89">
<TextView
android:id="@+id/tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<android.opengl.GLSurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
MainActivity
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private TextView tv_show;
// 定义一个GLSurfaceView类,用于显示3D视图
private GLSurfaceView surface_view;
private MediaRouter mMediaRouter;
private DemoPresentation mPresentation;
//应用是否是可见状态的标志位
private boolean mPaused;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* 获取到媒体路由,当媒体路由被选择或取消选择或者路由首选的presentation显示屏幕发生变化时,
* 它都会发送通知消息。一个应用程序可以非常简单通过地观察这些通知消息来自动地在首选的presentation
* 显示屏幕上显示或隐藏一个presentation。
*/
mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE);
tv_show = (TextView) findViewById(R.id.tv_show);
surface_view = (GLSurfaceView) findViewById(R.id.surface_view);
// 设置我们要渲染的图形为CubeRenderer,一个矩形3D模型
surface_view.setRenderer(new CubeRenderer());
}
@Override
protected void onResume() {
super.onResume();
//设置对媒体路由变化的监听
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mRouteCallBack);
updatePresentation();
mPaused=false;
updatePresentation();
}
private MediaRouter.SimpleCallback mRouteCallBack=new MediaRouter.SimpleCallback(){
@Override
public void onRouteSelected(MediaRouter router, int type, RouteInfo info) {
super.onRouteSelected(router, type, info);
updatePresentation();
}
@Override
public void onRouteUnselected(MediaRouter router, int type,
RouteInfo info) {
super.onRouteUnselected(router, type, info);
updatePresentation();
}
@Override
public void onRouteChanged(MediaRouter router, RouteInfo info) {
super.onRouteChanged(router, info);
updatePresentation();
}
};
@Override
protected void onPause() {
super.onPause();
mPaused=true;
//取消媒体路由的监听
mMediaRouter.removeCallback(mRouteCallBack);
//更新显示内容
updateContents();
}
@Override
protected void onStop() {
super.onStop();
if(mPresentation!=null){
mPresentation.dismiss();
mPresentation=null;
}
}
private void updatePresentation() {
//获取到被选中的媒体路由,类型为视频路由
MediaRouter.RouteInfo route = mMediaRouter
.getSelectedRoute(MediaRouter.ROUTE_TYPE_LIVE_VIDEO);
//获取到路由推荐的presentation display
Display presentationDisplay=route!=null ? route.getPresentationDisplay():null;
if(presentationDisplay==null){
Log.i(TAG,"没有找到视频路由推荐的display");
}else{
Log.i(TAG,presentationDisplay.getName());
}
//如果presentation已经存在且它的显示屏不是媒体路由推荐的显示屏,则取消presentation
if(mPresentation!=null && mPresentation.getDisplay()!=presentationDisplay){
Log.i(TAG, "Dismissing presentation because the current route no longer "
+ "has a presentation display.");
mPresentation.dismiss();
mPresentation=null;
}
//显示resentation
if(mPresentation==null && presentationDisplay!=null){
mPresentation=new DemoPresentation(this, presentationDisplay);
//设置presentation的解除监听
mPresentation.setOnDismissListener(mPresentationDismissListener);
mPresentation.show();
}
updateContents();
}
/**
* 更新presentation中显示的内容,如果presentation已经创建并显示则将内容显示在presentation上
* 如果没有创建presentation则将内容显示在主屏幕上
*/
private void updateContents() {
//显示在次级屏蔽上
if(mPresentation!=null){
tv_show.setText("在屏幕:"+mPresentation.getDisplay().getName()+"中显示presentation的内容。");
//隐藏主屏幕的surfaceView
surface_view.setVisibility(View.INVISIBLE);
surface_view.onPause();
//如果当前应用处于不可见状态
if(mPaused){
mPresentation.getSurface_view().onPause();
}else{
mPresentation.getSurface_view().onResume();
}
}else {
//将内容显示到本机屏幕上
tv_show.setText("在本机屏幕:"+getWindowManager().getDefaultDisplay().getName()+"中显示内容。");
surface_view.setVisibility(View.VISIBLE);
if(mPaused){
surface_view.onPause();
}else{
surface_view.onResume();
}
}
}
private OnDismissListener mPresentationDismissListener=new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if(dialog==mPresentation){
mPresentation=null;
updateContents();
}
}
};
}