Wednesday, August 26, 2015

Android TV Framework : HDMI Events Call Flow to TvInputService

HDMI Events Call Flow to TvInputService

In previous post we understood how HdmiControlManager.DEVICE_EVENT_ADD_DEVICE event is generated in Hdmi framework, now we will check further how this event is reached in TvInputFramework and finaly to a TvInputService implementation.

There are 3 categories of events notified from HdmiControlService to TvInputFramework,
1.HotplugEvent and
2.DeviceEvent
3.SystemAudioModeChange

TvInputManagerService registers for these as EventListener in TvInputHardwareManager class.
TvInputHardwareManager manages the hardwares either of TvInputHal(tv_input_device_t) type implemented in tv_input.cpp or hdmi_cec_device Type implemented in HDMI-CEC hal.

public TvInputManagerService(){
   mTvInputHardwareManager = new TvInputHardwareManager(context, new HardwareListener());
}

//TvInputHardwareManager.java
public void onBootPhase(int phase) {
   mHdmiControlService.addHotplugEventListener(mHdmiHotplugEventListener);
   mHdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener);
   mHdmiControlService.addSystemAudioModeChangeListener(
mHdmiSystemAudioModeChangeListener);
   mHdmiDeviceList.addAll(mHdmiControlService.getInputDevices());

}

HdmiHotplugEventListener extends IHdmiHotplugEventListener.Stub {
   public void onReceived(HdmiHotplugEvent event) {
      mHdmiStateMap.put(event.getPort(), event.isConnected());

      mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
         convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget();
}

HdmiDeviceEventListener extends IHdmiDeviceEventListener.Stub {
  public void onStatusChanged(HdmiDeviceInfo deviceInfo, int status) {
    switch (status) {
         case HdmiControlManager.DEVICE_EVENT_ADD_DEVICE: {
            mHdmiDeviceList.add(deviceInfo);
            messageType = ListenerHandler.HDMI_DEVICE_ADDED;
         }
         case HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE: {
            if (!mHdmiDeviceList.remove(originalDeviceInfo)) 
            messageType = ListenerHandler.HDMI_DEVICE_REMOVED;
         }
         case HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE: {
            if (!mHdmiDeviceList.remove(originalDeviceInfo)) {
            mHdmiDeviceList.add(deviceInfo);
            messageType = ListenerHandler.HDMI_DEVICE_UPDATED;
         }
         Message msg = mHandler.obtainMessage(messageType, 0, 0, obj);
msg.sendToTarget();
}

This handler notifies to TvInputManagerService.
ListenerHandler extends Handler {
  public final void handleMessage(Message msg) {
      switch (msg.what) {
          case STATE_CHANGED: {
              mListener.onStateChanged(inputId, state);
              break;
          }
          case HDMI_DEVICE_ADDED: {
              mListener.onHdmiDeviceAdded(info);
              break;
          }
          case HDMI_DEVICE_REMOVED: {
              mListener.onHdmiDeviceRemoved(info);
              break;
          }

TvInputManagerService broadcasts this event to all services currently available in system.

public void onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
   // Broadcast the event to all hardware inputs.
   serviceState.service.notifyHdmiDeviceAdded(deviceInfo);
}

TvInputService gets the event and posts to its handler which will call the onHdmiDeviceAdded.

TvInputService.java
void notifyHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
   mServiceHandler.obtainMessage(ServiceHandler.DO_ADD_HDMI_TV_INPUT,
          deviceInfo).sendToTarget();
}

ServiceHandler extends Handler {
   case DO_ADD_HDMI_TV_INPUT: {
        HdmiDeviceInfo deviceInfo = (HdmiDeviceInfo) msg.obj;
        TvInputInfo inputInfo = onHdmiDeviceAdded(deviceInfo);
        if (inputInfo != null) {
              broadcastAddHdmiTvInput(deviceInfo.getId(), inputInfo);
        }
}

Note here that a custom TvInputService must override to modify default behavior of ignoring all HDMI logical input device i.e. build a TvInputInfo using this HdmiDeviceInfo and return it.

public TvInputInfo onHdmiDeviceAdded(HdmiDeviceInfo deviceInfo) {
     return null;
}
(How to override this? link TvInputService Implementation : Creating TvInputInfo )

With this TvInputInfo, TvInputService broadcasts to TvInputManagerService so that it can add/update this new TvInputInfo in TvInputList.
broadcastAddHdmiTvInput(int id, TvInputInfo inputInfo) {
                  mCallbacks.getBroadcastItem(i).addHdmiTvInput(id, inputInfo);
}

In next post we will use this HdmiDeviceInfo/TvInputInfo for CEC communication implementation.


No comments:

Post a Comment