Android TV Input Framework(TIF)--3 显示Tv Input内容
2016-01-25 20:03
991 查看
上一篇文章我们分析了TvInputManagerService如何构建Tv Input list,这篇文章主要分析如何切换到Tv Input,并显示其内容。App一般通过TvView来跟TvInputService建立联系,通过调用TvView的方法来选择Tv Input,显示内容。我们看一下 Android开发文档对TvView的描述:
TvView类概述:
显示TV内容。TvView类为应用程序提供了一个高级接口,以显示实现TvInputService的各种TV信号源的节目。(注意系统上可用的TV Inputs列表可以通过调用
一旦应用程序提供了特定TV通道的URL给
Tv Input的选择和显示是通过TvView的tune方法来做的,我们看一下tune的实现:
tune方法有三个参数,我们只关注第一个参数inputId,每个Tv Input都有一个唯一的inputId和TvInputInfo实例,inputId由
接着ServiceHandler.handleMessage
先调用onCreateSession(inputId)创建一个Session,然后通知Session创建成功,即调用cb.onSessionCreated,最终会调到TvView.MySessionCallback.onSessionCreated,
<1> 设置当前的Session为主Session,
<2> 为当前的Input Session设置Surface,Tv Input会在这个surface上渲染视频,
<3> 调谐到对应的频道,主要是指模拟电视或者数字电视。
下面用一个序列图来简单的展示一个整个过程:
Created with Raphaël 2.1.0Tv appTv appTvViewTvViewTvInputManagerTvInputManagerTvInputServiceTvInputServiceTvInputHardwareManagerTvInputHardwareManagerTvInputHalTvInputHaltunecreateSessioncreateSessiononCreateSessiononCreateSessionpostSessionCreatedonSessionCreatedsetMainsetMainonSetMainsetSessionSurfacesetSurfacesetSurfaceonSetSurfacesetSurfaceaddOrUpdateStreamtuneonTune
TvView类概述:
显示TV内容。TvView类为应用程序提供了一个高级接口,以显示实现TvInputService的各种TV信号源的节目。(注意系统上可用的TV Inputs列表可以通过调用
TvInputManager.getTvInputList()来获取。
一旦应用程序提供了特定TV通道的URL给
tune(String, Uri)方法,它负责下层的服务绑定(和解除绑定如果当前的TvView已经绑定到一个服务)并且根据需要自动的分配或者释放资源。除了一些控制内容如何呈现的基本方法,它也提供了一个给已经连接的TvInputService分发输入事件的办法,以允许为Tv Input客制化按键动作。
Tv Input的选择和显示是通过TvView的tune方法来做的,我们看一下tune的实现:
/** * Tunes to a given channel. * * @param inputId The ID of TV input which will play the given channel. * @param channelUri The URI of a channel. * @param params Extra parameters which might be handled with the tune event. * @hide */ @SystemApi public void tune(String inputId, Uri channelUri, Bundle params) { ... if (mSessionCallback != null && mSessionCallback.mInputId.equals(inputId)) { if (mSession != null) { mSession.tune(channelUri, params); } else { // Session is not created yet. Replace the channel which will be set once the // session is made. mSessionCallback.mChannelUri = channelUri; mSessionCallback.mTuneParams = params; } } else { resetInternal(); // When createSession() is called multiple times before the callback is called, // only the callback of the last createSession() call will be actually called back. // The previous callbacks will be ignored. For the logic, mSessionCallback // is newly assigned for every createSession request and compared with // MySessionCreateCallback.this. mSessionCallback = new MySessionCallback(inputId, channelUri, params); if (mTvInputManager != null) { mTvInputManager.createSession(inputId, mSessionCallback, mHandler); } } }
tune方法有三个参数,我们只关注第一个参数inputId,每个Tv Input都有一个唯一的inputId和TvInputInfo实例,inputId由
TvInputInfo.getId()获取。第一次调用tune的时候,mSessionCallback为null,所以首先执行
mSessionCallback = new MySessionCallback(inputId, channelUri, params)创建一个SessionCallback实例,然后通过
mTvInputManager.createSession(inputId, mSessionCallback, mHandler)来跟TvInputService之间创建一个会话,当会话创建成功以后,mSessionCallback被回调回来,createSession的具体细节我们忽略掉,最终会调用到TvInputService的createSession,
public void createSession(InputChannel channel, ITvInputSessionCallback cb, String inputId) { if (channel == null) { Log.w(TAG, "Creating session without input channel"); } if (cb == null) { return; } SomeArgs args = SomeArgs.obtain(); args.arg1 = channel; args.arg2 = cb; args.arg3 = inputId; mServiceHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget(); }
接着ServiceHandler.handleMessage
public final void handleMessage(Message msg) { switch (msg.what) { case DO_CREATE_SESSION: { SomeArgs args = (SomeArgs) msg.obj; InputChannel channel = (InputChannel) args.arg1; ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2; String inputId = (String) args.arg3; args.recycle(); Session sessionImpl = onCreateSession(inputId); ... else { SomeArgs someArgs = SomeArgs.obtain(); someArgs.arg1 = sessionImpl; someArgs.arg2 = stub; someArgs.arg3 = cb; someArgs.arg4 = null; mServiceHandler.obtainMessage(ServiceHandler.DO_NOTIFY_SESSION_CREATED, someArgs).sendToTarget(); } return; } case DO_NOTIFY_SESSION_CREATED: { SomeArgs args = (SomeArgs) msg.obj; Session sessionImpl = (Session) args.arg1; ITvInputSession stub = (ITvInputSession) args.arg2; ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg3; IBinder hardwareSessionToken = (IBinder) args.arg4; try { cb.onSessionCreated(stub, hardwareSessionToken); } catch (RemoteException e) { Log.e(TAG, "error in onSessionCreated"); } if (sessionImpl != null) { sessionImpl.initialize(cb); } args.recycle(); return; }
先调用onCreateSession(inputId)创建一个Session,然后通知Session创建成功,即调用cb.onSessionCreated,最终会调到TvView.MySessionCallback.onSessionCreated,
public void onSessionCreated(Session session) { ... mSession = session; if (session != null) { synchronized (sMainTvViewLock) { if (hasWindowFocus() && TvView.this == sMainTvView.get()) { mSession.setMain(); ---<1> } } // mSurface may not be ready yet as soon as starting an application. // In the case, we don't send Session.setSurface(null) unnecessarily. // setSessionSurface will be called in surfaceCreated. if (mSurface != null) { setSessionSurface(mSurface); ---<2> if (mSurfaceChanged) { dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight); } } createSessionOverlayView(); if (mCaptionEnabled != CAPTION_DEFAULT) { mSession.setCaptionEnabled(mCaptionEnabled == CAPTION_ENABLED); } mSession.tune(mChannelUri, mTuneParams); ---<3> if (mHasStreamVolume) { mSession.setStreamVolume(mStreamVolume); } ... }
<1> 设置当前的Session为主Session,
setMain最终会调到
TvInputService.Session.onSetMain,如果TV Input Service是管理HDMI CEC逻辑设备,需要实现
onSetMain这个方法来选择对应的HDMI CEC逻辑设备作为源设备,主Session对应的Tv Input为当前活动的源设备(Active Source)。
<2> 为当前的Input Session设置Surface,Tv Input会在这个surface上渲染视频,
setSessionSurface会最终调到
TvInputService.Session.setSurface,接着会调到
TvInputHardwareManager.setSurface,最后调用到
TvInputHal.addOrUpdateStream让HAL来做相关的配置。这一步是关键,Tv Input端口的选择以及视频通道的配置都是这一部完成的。
<3> 调谐到对应的频道,主要是指模拟电视或者数字电视。
下面用一个序列图来简单的展示一个整个过程:
Created with Raphaël 2.1.0Tv appTv appTvViewTvViewTvInputManagerTvInputManagerTvInputServiceTvInputServiceTvInputHardwareManagerTvInputHardwareManagerTvInputHalTvInputHaltunecreateSessioncreateSessiononCreateSessiononCreateSessionpostSessionCreatedonSessionCreatedsetMainsetMainonSetMainsetSessionSurfacesetSurfacesetSurfaceonSetSurfacesetSurfaceaddOrUpdateStreamtuneonTune
相关文章推荐
- Android之WebRTC介绍(二)
- Android Settings.System的使用
- Android开发随笔
- Android源码之Matrix
- Android Framework层Power键关机流程
- Android Branch and master source code merge(patch)
- 这些年正Android - 序言
- 这些年正Android - 序言
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- Understanding Android Security(安卓安全的理解)
- android lint的使用
- Android 判断ListView是否在滚动到底部
- Android 设计模式之(三)观察者,适配器,桥接,组合模式
- Android 设计模式之(二)建造者,模板方法,策略模式
- Android 设计模式之(一)单例,代理,外观模式
- 安卓初学二之控件初步(一)
- Android开发中,有哪些让你觉得相见恨晚的方法、类或接口?
- 最新Android版本和API Level关系