• Nenhum resultado encontrado

4.2 Synced-WebServers

4.3.2. Formatação dos dados contextualizados

Para o correto funcionamento do sincronismo entre os conteúdos web e televisivo, algumas informações importantes sobre a programação corrente precisam ser coletadas, como por exemplo, o nome, gênero, horário de início e duração. Estas informações são necessárias tanto para o cálculo dos pontos de sincronismo, no caso dos dados temporais, quanto para a tomada de decisão durante a avaliação dos critérios de interrupção e notificação ao usuário.

A aquisição dessas informações é possível a partir de um objeto SIEvent retornada pelo ServiceManager à uma chamada ao Service Provider. A interface SIEvent

é disponibilizada pela API do Ginga-J e tem como responsabilidade indicar um programa especifico no serviço da TV. Segundo NBR 15606-4(2010), cada objeto que implementa a interface SIEvent é identificado pela combinação do original_id, transport_stream_id, service_id e event_id, sendo único para cada programa da grade.

Objetos que implementam esta interface disponibilizam métodos públicos de acesso ao conteúdo contextual da programação, métodos estes utilizados para a formação de um JSON com todas as informações relevantes ao sincronismo, como mostrado no exemplo de código abaixo.

private String getJsonFromEvent(SIEvent event) {

System.out.println("##getJsonFromEvent ##"); String jsonResult = null;

if (siEvent.getLevel1ContentNibbles() != null) { jsonResult = loadJsonData(event.getName(), getHexString(event.getLevel1ContentNibbles()), System.currentTimeMillis(), event.getStartTime().getTime(), event.getDuration(), getSyncEvents()); } return jsonResult; }

private String getSyncEvents() {

String syncEvents = null;

if (siEvent.getExEventInformations() != null &&

siEvent.getExEventInformations().length > 0) {

for (int h = 0; h <

siEvent.getExEventInformations().length; h++) {

if (siEvent.getExEventInformations()[h].getName() .equals(Constants.STR_SYNC_POINTS)) {

syncEvents =

siEvent.getExEventInformations()[h].getDescription();

}

strBuffer.append("SI EX Information: getName:" + "["

+ h + "]" + siEvent.getExEventInformations()[h].getName() + "\n"); strBuffer.append("SI EX Information:

getDescription:" + "[" + h + "]" +

siEvent.getExEventInformations()[h].getDescription()

+ "\n"); }

} else {

strBuffer.append("SIEXInformation : 0 ou NULL \n"); }

return syncEvents; }

Uma vez coletados todos os dados contextuais inerentes ao sincronismo, um objeto JSON é criado para ser enviado via broadcast par ao modulo Synced- SecondScreenApp. O trecho de código abaixo mostra como o método loadJsonData, após receber os dados contextuais da programação, forma o objeto JSON final para ser enviado ao módulo Synced-SecondScreenApp.

public String loadJsonData(String name, String genre, long

currentTime, long initialTime, long programDuration, String syncpoints) {

System.out.println("##################### loadJsonData

#######################################");

strBuffer = new StringBuffer("");

strBuffer.append("{ \"ProgramInfo\": {");

strBuffer.append(" \"Name\":\"" + name + "\","); strBuffer.append(" \"Genre\":\"" + genre + "\","); strBuffer.append(" \"CurrentTime\":\"" + currentTime +

"\",");

strBuffer.append(" \"ProgramInitialTime\":\"" + initialTime + "\",");

strBuffer.append(" \"ProgramDuration\":\"" + programDuration + "\"");

if (syncpoints != null) {

//Normaliza o JSON recebido pelo TS

String temp = syncpoints;

syncpoints = temp.substring(temp.indexOf("{")+1, temp.lastIndexOf("}")); strBuffer.append(","); strBuffer.append(syncpoints); } strBuffer.append(" }"); strBuffer.append(" }");

System.out.println("json = " + strBuffer.toString()); return strBuffer.toString();

}

A correta formatação deste JSON é crucial ao funcionamento de todo o sistema, uma vez que, se alguma informação estiver faltando ou o JSON for criada de forma errada, a aplicação mobile não poderá interpretar corretamente os dados, comprometendo a normalização dos dados temporais para o sincronismo dos conteúdos e afetará o algoritmo responsável pela tomada de decisão da interrupção e notificação do usuário.

4.4 Synced-SecondScreenApp

Subsistema desenvolvido para executar no dispositivo de segunda tela. É importante observar que a escolha pela plataforma Android foi dada pela grande abrangência e pelo grande crescimento desta plataforma no cenário mundial de aparelhos móveis, sendo esta mesma solução passível de ser implementada em qualquer outra plataforma disponível como IOS ou Windows Phone.

Algumas das mais importantes funcionalidades do sistema são delegadas a este modulo, como por exemplo, a exibição do conteúdo contextual web, normalização e agendamento dos pontos de sincronismo e a lógica responsável por definir a forma com a qual o usuário irá receber os dados contextuais provenientes da TV. Para a solução proposta, apenas uma forma de transmissão de dados foi implementada, porém a forma como a transmissão deve acontecer pode ser feita de várias formas, ficando a cargo do desenvolvedor decidir qual a abordagem que se adequa melhor a sua necessidade.

O diagrama de classes da Figura 8 a seguir mostra as principais classes do sistema e as interações e dependências entre elas.

A classe MainActivity representa a tela inicial da aplicação. Nela é exibida uma lista com todos os gêneros de programação especificados em (NBR 15603-2, 2008). Para cada gênero é permitido ao usuário definir qual a forma de interrupção será executada caso ponto de sincronismo para o escolhido gênero seja recebido pela aplicação. A Figura 9 a seguir mostra a estrutura visual dessa classe.

Figura 9 - Estrutura visual da aplicação

Esta classe também dá acesso a uma forma mais específica de controle de interrupção, onde, uma vez que o usuário defina a opção de Interromper para algum dos gêneros disponibilizados, uma outra opção de configuração é habilitada, possibilitando ao usuário definir quais aplicativos instalados serão consideradas exceções a interrupção. Neste caso, caso um ponto de sincronismo seja recebido para um gênero e uma aplicação escolhida como exceção estiver em execução no momento do sincronismo a interrupção não será efetivada, apenas uma notificação irá ocorrer. O trecho de código a seguir mostra como a chamada que permite essa nova configuração é realizada.

btnSetting.setOnClickListener(new View.OnClickListener()

{

@Override

public void onClick(View arg0)

Intent = new Intent(MainActivity.this, GenrePreferenceActivity.class); intent.putExtra(Util.GENRE_PREFERENCE_EXTRA, genres.get(0).getPackageList()); startActivityForResult(intent, REQUEST_CODE); } });

A chamada de criação da nova tela é feita através de uma chamada a startActivityForResult, o que indica a necessidade da nova tela retornar informações sobre o processamento realizado. No caso, este retorno é capturado pelo método onActivityResult, definido para ser notificado ao fim da execução da tela chamada com ilustra o código abaixo.

protected void onActivityResult(int requestCode, int resultCode,

Intent data) {

super.onActivityResult(requestCode, resultCode, data);

Log.e(TAG, "onActivityResult - " + requestCode + " - " + resultCode + " - " + data); if (requestCode == REQUEST_CODE) { if (resultCode == RESULT_OK) { applicationExceptions = data.getStringExtra(Util.GENRE_PREFERENCE_EXTRA);

//save on db new exceptions

genres.get(0).setPackageList(applicationExceptions);

mDatabaseHelper.updateGenre(genres.get(0));

} else {

Log.e(TAG, "onActivityResult - RESULT_ERROR"); }

} }

Uma vez configuradas as formas de notificação para os gêneros e as exceções de interrupção, a aplicação é finalizada e um serviço, objeto Service em Android, é inicializado, representado pela classe ConnectionService. Um serviço é um componente de aplicação capaz de executar longos processamentos em background e não contém interface gráfica.

O diagrama de sequência da Figura 10a seguir ilustra as etapas no processo de configuração e inicialização do serviço de conexão da aplicação.

Figura 10 - Diagrama de sequência do serviço de conexão.

A classe ConnectionService tem como grande responsabilidade o estabelecimento de conexões e posterior recebimento dos dados contextuais enviados pelo módulo Synced-TVApp. Para isto é implementada uma técnica de pooling de conexão, onde o objeto capaz de realizar a conexão fica “escutando” a rede numa determinada porta específica a espera do recebimento dos dados. Este pooling de conexão continua ativo sempre que o dispositivo de segunda tela possua uma conexão wifi habilitada e conectada. O código a seguir mostra o funcionamento do pooling e a forma como os dados contextuais é recebido.

DatagramSocket serverSocket = null; try {

serverSocket = new DatagramSocket(Util.PORT); byte[] receiveData = new byte[Util.DATA_LENGTH];

while (mWifiManager.isWifiEnabled()) {

try {

receiveData = new byte[Util.DATA_LENGTH]; DatagramPacket receivePacket = new

DatagramPacket(receiveData, receiveData.length);

Log.e(TAG, "Waiting for datagram packet"); serverSocket.setSoTimeout(Util.DATAGRAM_TIMEOUT); serverSocket.setReuseAddress(true);

serverSocket.setBroadcast(true); serverSocket.receive(receivePacket);

String sentence = new String(receiveData).trim(); InetAddress IPAddress = receivePacket.getAddress(); int port = receivePacket.getPort();

Log.e(TAG, "From: " + IPAddress + ":" + port); Log.e(TAG, "Message: " + sentence);

Message message = mHandler.obtainMessage(); message.obj = sentence;

message.what = STATUS_OK;

mHandler.sendMessage(message);

}

catch (IOException e)

{

Log.e(TAG, "IOException", e); }

}

A constante Util.PORT especifica qual a porta está sendo “escutada” para que o recebimento dos dados contextuais seja possível e deve coincidir com a porta definida pelo módulo Synced-TVApp. Para a implementação desta solução esta constante é definida como:

public static final int PORT = 7654;

O método receiveda classe DatagramSocketé responsável pelo recebimento dos dados contextuais. Este método, pela API, é definido como um método bloqueante, onde a sua execução é condicionada ao estabelecimento da conexão ou a uma exceção lançada caso um timeout de conexão seja lançada.

Uma vez recebida a informação, ela deve ser exatamente equivalente a mensagem enviada pelo modulo Synced-TVApp, possibilitando que o tratamento das informações seja executado de forma correta e os pontos de sincronismo gerados de forma apropriada. O documento JSON recebido deve seguir a estrutura semelhante ao exemplo abaixo.

{

"ProgramInfo": {

"Name": "Mais Voce", "Genre":"0x6", "CurrentTime":"3282986312986", "ProgramInitialTime":"9874938739847", "ProgramDuration":"090909098808", "syncpoints": [ { "time": "200", "inttype": 0, "url":"http://192.168.0.127/teste/index.php"}, { "time": "300", "inttype": 1, "url":"http://192.168.0.127/teste/teste1.php"}, { "time": "400", "inttype": 0, "url":"http://192.168.0.127/teste/teste2.php"} ] } }

O exemplo acima demonstra quais os dados são essenciais para que a proposta deste trabalho possa ser aplicada. São eles:

1. Name: Nome da programação sendo exibida.

2. Genre: Gênero da programação, seguindo o padrão especificado na norma. 3. CurrentTime: Horário atual da TV, em milissegundos.

4. ProgramInitialTime: Horário indicado na tabela EIT como sendo o do início da programação atual.

5. ProgramDuration: Duração da programação, em milissegundos.

6. Syncpoints: Especificação dos pontos de sincronismo com os dados contextuais web.

A utilização e relevância destes campos serão explanadas com maior abrangência em seções posteriores, onde serão abordadas as necessidades de validação contextual do gênero televisivo e dos tempos para o calculo dos momentos de sincronismo.

Uma vez recebido o JSON pela classe ConnectionService, o processo de análise dos critérios de interrupção e gerenciamento dos pontos de sincronismo é delegado para a classe ParseJsonService. Como dito anteriormente, esta classe contém os métodos responsáveis por realizar a análise do documento JSON, verifica a ação a ser realizada de acordo com o gênero e agenda os alarmes, objetos do tipo Alarm em Android, que farão o sincronismo dos conteúdos contextuais.

O diagrama de sequência da

Figura 11 a seguir mostra o fluxo de execução desde o momento do recebimento dos dados da TV até o momento do sincronismo do conteúdo.

Observe que, como mostrado no diagrama acima, uma vez que os dados contextuais são recebidos, uma serie de processamentos são executados antes do sincronismo esteja apto a acontecer. Inicialmente o gênero é extraído e validado de acordo com as escolhas do usuário para este determinado gênero. Logo após os outros dados são “parseados” e os tempos recebidos normalizados. Com os dados temporais normalizados, os alarmes podem ser agendados de forma correta.

Quando um desses alarmes dispara, um componente do android denominado BroadcastReceiver do tipo ScheduleAlarmreceiver é invocado, fazendo a chamada para a inicialização da classe WebActivity que exibirá ou notificará acerca do conteúdo web

sincronizado. Os critérios utilizados na tomada de decisão da forma de notificação ao usuário deste conteúdo sincronizado será explicado mais adiante.

Documentos relacionados