UNIVERSIDADE PRESBITERIANA MACKENZIE …fmsantos/resources/files/graduacao/TGI.pdf ·...
Transcript of UNIVERSIDADE PRESBITERIANA MACKENZIE …fmsantos/resources/files/graduacao/TGI.pdf ·...
UNIVERSIDADE PRESBITERIANA MACKENZIE
FACULDADE DE COMPUTAÇÃO E INFORMÁTICA
FABIO PIRES PINCELLO
FELIPE MARTINS DOS SANTOS
INTERATIVIDADE EM SISTEMAS DE TELEVISÃO DIGITAL ATRAVÉS DE JAVA TV
São Paulo
2009
FABIO PIRES PINCELLO
FELIPE MARTINS DOS SANTOS
INTERATIVIDADE EM SISTEMAS DE TELEVISÃO DIGITAL ATRAVÉS DE JAVA TV
ORIENTADOR: Profº Dr. Luís Tadeu Mendes Raunheitte
São Paulo
2009
Trabalho de Graduação
Interdisciplinar apresentado à
Faculdade de Computação e
Informática da Universidade
Presbiteriana Mackenzie como
requisito parcial para obtenção do
título de Bacharel em Ciência da
Computação.
FABIO PIRES PINCELLO
FELIPE MARTINS DOS SANTOS
INTERATIVIDADE EM SISTEMAS DE TELEVISÃO DIGITAL ATRAVÉS DE JAVA TV
Aprovados em
BANCA EXAMINADORA
______________________________________________________________________
______________________________________________________________________
______________________________________________________________________
Trabalho de Graduação
Interdisciplinar apresentado à
Faculdade de Computação e
Informática da Universidade
Presbiteriana Mackenzie como
requisito parcial para obtenção do
título de Bacharel em Ciência da
Computação.
Aos nossos pais, que sempre lutaram para nos proporcionar
uma educação de qualidade e desde cedo nos mostraram
a importância dos estudos.
Aos nossos amigos, que nos apóiam em todos os momentos
e nos dão ânimo para superar todos os obstáculos
que surgem durante a vida.
AGRADECIMENTOS
Agradecemos a Deus acima de tudo pela força que nos deu nessa caminhada, não só durante o
trabalho, mas durante a vida toda.
Agradecemos aos nossos familiares pelo apoio em momentos difíceis e por entenderem
nossas ausências nos momentos de estudo.
Agradecemos ao nosso orientador, Profº Drº Luis Tadeu Mendes Raunheitte, por ter tido
paciência nos momentos difíceis, por ter confiado em nós e pelas valiosas dicas durante o
período de orientação.
Subestimamos a necessidade que os seres humanos
têm de se relacionar entre si.
Por isso, não conseguimos prever tecnologias
como o celular e a Internet.
(Jean Paul Jacob)
Eu não temo os computadores.
Eu temo a ausência deles.
(Isaac Asimov)
RESUMO
O objetivo desse trabalho é apresentar o desenvolvimento de aplicações interativas
para ambientes de TV digital utilizando a linguagem Java e a API Java TV. Para isso,
conceitos de interatividade são investigados e analisados para que requisitos importantes
relacionados a esses conceitos sejam definidos e utilizados em uma aplicação para TV digital.
Primeiramente, o trabalho comenta a história e evolução da TV, desde os antigos televisores
analógicos em preto e branco até o sistema de televisão atual e os recentes aparelhos de
televisão digital, e também identifica as principais vantagens da TV digital. Em seguida, os
fundamentos da televisão digital são abordados bem como os conceitos de digitalização dos
sinais de TV analógica, vantagens e desvantagens da digitalização, representação da imagem
digital, televisão de alta definição, modulação, transmissão, recepção e compressão do sinal
digital, padrões de TV digital e sistemas de TV digital interativa. Depois disso, são
apresentadas noções de Interação Humano-Computador (IHC), com uma breve explicação
sobre o processo de desenvolvimento interativo e a avaliação de sistemas interativos. Nesse
ponto, um breve estudo sobre a API Java TV é apresentado. Com os conceitos de TV digital e
IHC, busca-se a interseção das duas áreas aplicando IHC no desenvolvimento de um
aplicativo em Java para televisão digital. Seguindo esse contexto, foi desenvolvido um
aplicativo interativo para TV digital com o auxílio da API Java TV, onde o telespectador teria
a oportunidade de votar, a partir de uma lista definida pela emissora, em um filme de sua
preferência. Para finalizar, o desenvolvimento dessa aplicação é comentado e testado no
emulador XleTView.
Palavras-Chave: TV Digital, Interatividade, Linguagem de Programação Java, API Java TV.
ABSTRACT
The aim of this work is to present the development of interactive applications to
Digital TV environments using the Java language and the Java TV API. For this, interactivity
concepts are investigated and analysed, important requirements related to this concepts are
defined and applied to an application for the Digital TV. First of all, the work describe the
TV’s history and evolution, since the time that was used black and white analogic TVs until
the invention of the recent Digital TV equipments, and identify the vantages in Digital TV.
Following, the work explain the core of Digital TV, where describe some concepts like: signal
digitalization in Digital TV, vantages and disadvantages in digitalization, digital image
representation, high definition television, modulation, transmission, reception and signal
compression, digital TV patterns and interactive Digital TV systems. After, we present
Human Computer Interaction (HCI) with a briefly explanation of interactive development
process and interactive systems evaluation. At this point, a briefly study over the Java TV API
is presented. With Digital TV and HCI concepts defined, we search the intersection between
the two areas applying HCI in the development of an application in Java for Digital TV.
Following this context, it was developed an interactive application for Digital TV using Java
TV API, where the televiewer has the opportunity to vote, with a predefined list, in a movie of
his preference. To finalize, the development of the application is commented and tested in the
XleTView emulator.
Keywords: Digital TV, Interactivity, Java Programming Language, Java TV API.
LISTA DE ILUSTRAÇÕES
Figura 1 Digitalização de um sinal analógico (amostragem e quantização) ........ 19
Figura 2 Sistema de coordenadas para representar cada pixel da imagem ........... 21
Figura 3 Modulação por amplitude, freqüência e fase ......................................... 24
Figura 4 Diagrama do transmissor ....................................................................... 26
Figura 5 Diagrama do receptor de TV Digital ..................................................... 26
Figura 6 Modelo de um sistema de televisão digital interativa ............................ 30
Figura 7 Arquitetura de TV digital com tecnologias usadas em cada camada .... 31
Figura 8 Modelo do Ciclo de Vida de Xlets ........................................................ 41
Figura 9 Implementação vazia de um Xlet .......................................................... 42
Figura 10 Enquete implementada em Java TV ...................................................... 47
Figura 11 Aplicação de pesquisa com opinião implementar em Java TV ............. 48
Figura 12 Protótipo de aplicação de enquetes de filmes implementada em
Java TV .................................................................................................. 51
Figura 13 Diagrama UML de Casos de Uso para aplicação de votação de
Filmes ..................................................................................................... 52
Figura 14 Diagrama de Classes para aplicação de votação de filmes .................... 53
Figura 15 Início da aplicação ................................................................................. 57
Figura 16 Menu da aplicação ................................................................................. 58
Figura 17 Tela de votação ...................................................................................... 59
Figura 18 Filme selecionado .................................................................................. 60
Figura 19 Tela de confirmação do voto ................................................................. 61
Figura 20 Tela de resultados parciais da votação .................................................. 62
Figura 21 Tela de comentários .............................................................................. 63
LISTA DE TABELAS
Tabela 1 Resoluções de TV digital ................................................................... 23
Tabela 2 Classificação das técnicas de compressão ......................................... 28
LISTA DE ABREVIATURAS, SIGLAS E SÍMBOLOS
API Application Programming Interface
ARIB Association of Radio Industries and Business
ASTC Advanced Television System
AWT Abstract Window Toolkit
COFDM Coded Orthogonal Frequency Multiplex
DASE DTV Application Software Environment
DVB-T Digital Video Broadcast - Terrestrial
EDTV Enhanced Definition Television
GUI Graphical User Interface
HAVi Home Audio and Video interoperability
HDTV High Definition Television
IHC Interação Humano Computador
IPTV Internet Protocol Television
ISDB-T Integrated System Digital Broadcasting - Terrestrial
JDK Java Development Kit
MHP Multimedia Home Platform
MPEG Moving Picture Expert Group
MUSE Multiple Subnyquist Sampling Encoding
MUSICAM Masking Pattern Universal Sub-band Integrated Coding and Multiplexing
ROM Read Only Memory
SBTVD SistemaBrasileiro de TV Digital
SDTV Standard Definition Television
STB Set-Top Box
VM Virtual Machine
SUMÁRIO
1 INTRODUÇÃO .................................................................................................... 14
1.1 OBJETIVO ............................................................................................................ 14
1.2 ESTRUTURA DO TRABALHO ................................................................................. 15
1.3 BREVE HISTÓRICO DA EVOLUÇÃO DA TV ........................................................... 16
1.4 VANTAGENS DA TV DIGITAL .............................................................................. 16
2 FUNDAMENTOS DE TV DIGITAL ................................................................. 18
2.1 DIGITALIZAÇÃO DOS SINAIS DE TV ANALÓGICA ................................................... 18
2.2 VANTAGENS E DESVANTAGENS DA DIGITALIZAÇÃO DO SINAL ........................... 19
2.3 REPRESENTAÇÃO DA IMAGEM DIGITAL ............................................................... 20
2.4 TELEVISÃO DE ALTA DEFINIÇÃO ......................................................................... 21
2.5 MODULAÇÃO DO SINAL ....................................................................................... 23
2.6 TRANSMISSÃO E RECEPÇÃO DO SINAL DE TV DIGITAL ....................................... 25
2.7 COMPRESSÃO DO SINAL DIGITAL ........................................................................ 26
2.8 PADRÕES DE TV DIGITAL .................................................................................... 28
2.9 SISTEMAS DE TV DIGITAL INTERATIVA: COMPONENTES E ARQUITETURA .......... 30
3 INTERAÇÃO HUMANO-COMPUTADOR APLICADA A SISTEMAS DE TV
DIGITAL ....................................................................................................................... 33
3.1 VISÃO GERAL ...................................................................................................... 33
3.2 QUALIDADE DE IHC E SATISFAÇÃO DO USUÁRIO ................................................ 33
3.3 PROCESSO DE DESENVOLVIMENTO INTERATIVO .................................................. 35
3.4 AVALIAÇÃO DE SISTEMAS INTERATIVOS ............................................................. 36
4 APLICAÇÕES PARA TV DIGITAL UTILIZANDO A API JAVA TV ........ 39
4.1 VISÃO GERAL ...................................................................................................... 39
4.2 XLETS .................................................................................................................. 40
4.3 PACOTES DA API JAVA TV .................................................................................. 43
4.4 COMPONENTES GUI PARA APLICAÇÕES JAVA TV ............................................... 44
4.5 EXEMPLOS DE XLETS ........................................................................................... 45
5 DESENVOLVIMENTO DE APLICATIVO INTERATIVO ATRAVÉS DE JAVA
TV 49
5.1 VISÃO GERAL ...................................................................................................... 49
5.2 ESCOLHA INTERATIVA DE PROGRAMAÇÃO .......................................................... 49
5.3 DESENVOLVIMENTO DE PROTÓTIPO ..................................................................... 50
5.4 DESENVOLVIMENTO DE APLICATIVO ................................................................... 51
5.5 FUNCIONAMENTO DO APLICATIVO ...................................................................... 56
6 CONCLUSÃO ....................................................................................................... 64
REFERÊNCIAS ........................................................................................................... 65
APÊNDICE A ............................................................................................................... 67
14
1 INTRODUÇÃO
Desde seu surgimento, através da tecnologia analógica, a televisão tornou-se um
veículo de comunicação de grande importância e atualmente caracteriza-se por ser um meio
popular para acesso à informação. No Brasil, por exemplo, esse aparelho está presente em
mais de 90% dos lares e muitas vezes é a única fonte de informação disponível, o que indica
que seu conteúdo tem participação relevante para o telespectador brasileiro (MONTEZ;
BECKER, 2005, p. 25). Dessa forma, a televisão é responsável por grande parte do
entretenimento e ainda representa uma forte influência cultural, social, econômica e política.
Assim como outros meios de comunicação, o sistema de televisão evolui
constantemente. Atualmente, as TVs já apresentam tecnologia digital tanto em sua construção
como no sistema de transmissão e, como conseqüência, viabilizam de forma mais concreta
recursos de interatividade.
Para permitir essa interação, surge a necessidade de agregar ao receptor de TV a
capacidade de processar o código que define a aplicação interativa, obtido na recepção
juntamente com os sinais de áudio e vídeo. Além disso, deve existir um canal de retorno, por
onde a emissora da aplicação interativa recebe respostas do telespectador.
Unindo a popularidade desse meio de transmissão com a possibilidade de interação,
pode-se usar a televisão digital como forma de inclusão digital, medida que foi iniciada pelo
governo brasileiro com a criação do Sistema Brasileiro de TV Digital (SBTVD) em novembro
de 2003 e que pretende fornecer dentro de alguns anos os serviços de acesso à internet através
da TV digital.
1.1 Objetivo
Seguindo essa tendência de utilizar recursos de interatividade em TV digital, o
objetivo deste trabalho é realizar um estudo sobre a criação de aplicações para televisão
digital através da API Java TV, utilizando esse conhecimento para desenvolver na prática uma
aplicação interativa para TV digital. Para atingir esse objetivo, pesquisas foram realizadas
sobre a arquitetura do sistema de televisão digital interativa, sobre conceitos de interatividade
15
e sobre o funcionamento e a mecânica da API Java TV. De forma específica, esse trabalho
possui os seguintes objetivos:
Apresentar um levantamento teórico dos fundamentos de televisão digital;
Apresentar um estudo sobre conceitos de interatividade e sobre como utilizar a API
Java TV para o desenvolvimento de aplicações interativas para televisão digital;
Desenvolver um aplicativo para televisão digital utilizando a API Java TV e aplicar
os conceitos de interatividade estudados.
1.2 Estrutura do Trabalho
O capítulo 1 do trabalho apresenta uma introdução, além de explicar os objetivos,
fornecer um breve histórico da evolução da televisão e explicar as vantagens da utilização da
televisão digital.
O capítulo 2 apresenta os fundamentos da TV Digital, explicando alguns conceitos
importantes para um entendimento básico sobre essa tecnologia: digitalização de sinais
analógicos, representação de imagem digital, televisão de alta definição, modulação,
compressão, transmissão e recepção do sinal de TV digital, padrões de televisão digital
existentes e os componentes e arquitetura do sistema de TV digital interativa.
No capítulo 3, são apresentados conceitos sobre interação humano-computador (IHC),
procurando inseri-los no contexto de sistemas de televisão digital. Primeiramente é
apresentada uma visão geral do assunto, seguido de discussões sobre a satisfatibilidade do
usuário, o processo de desenvolvimento interativo e a avaliação de sistemas interativos.
O capítulo 4 apresenta um estudo sobre a API Java TV, uma extensão da linguagem de
programação Java, que permite que sejam desenvolvidas aplicações para TV digital. Esse
capítulo fornece uma visão geral do assunto, e apresenta a interface Xlet que permite a
implementação da aplicação e os componentes GUI (Graphical User Interface).
Por fim, no capítulo 5, o desenvolvimento do aplicativo é descrito e documentado,
utilizando os conceitos de interação estudados e a linguagem de programação Java, auxiliado
pela interface Xlet e pelos componentes GUI disponibilizados pela API Java TV.
16
1.3 Breve Histórico da Evolução da TV
Inicialmente, a televisão construída na década de 30, era um aparelho analógico que
exibia vídeo em preto-e-branco, porém essa realidade foi modificada já na década de 1950,
quando a televisão passou a apresentar transmissão de vídeo em cores e com um maior
número de canais. Nessa época, o sinal gerado pela câmera era enviado diretamente para a
antena, transmitindo o sinal ao vivo para o telespectador (MONTEZ; BECKER, 2005, p. 22).
Após 1956, foi criado o videoteipe, possibilitando o armazenamento dos vídeos
gerados pela câmera para edição antes de serem transmitidos.
Na década de 80, o controle remoto foi desenvolvido para dispensar a locomoção do
telespectador até o aparelho de TV.
Nessa mesma época, as ilhas de edição digitais passaram a oferecer mais recursos para
os editores. Esse avanço foi considerado como início da TV digital.
Após esse avanço utilizando tecnologia digital, desde a década de 1990, o estudo sobre
transmissão digital e modulação do sinal audiovisual para a transmissão terrestre e por satélite
foi sendo aprimorado (MONTEZ; BECKER, 2005, p. 22).
1.4 Vantagens da TV Digital
Nos sistemas analógicos, a definição da imagem, obtida nos aparelhos receptores,
geralmente é bastante reduzida em função do número inferior de pontos da imagem e das
perdas relacionadas a interferências e ruídos, diminuindo consideravelmente a qualidade da
imagem apresentada. Através do sistema de transmissão digital, ao invés da transmissão de
sinais analógicos via radiodifusão, sinais digitais são transmitidos via propagação
eletromagnética, onde os sinais de som e imagem são representados por seqüências binárias,
reduzindo a interferência a ruídos e permitindo a eliminação de “fantasmas” e “chuviscos”.
Além disso, através da transmissão analógica toda informação precisa ser incluída no sinal,
ocupando todo o canal de 6 MHz disponibilizado pelo sistema de televisão brasileiro. Já pela
transmissão digital o sinal pode ser compactado, considerando redundâncias e detalhes
imperceptíveis ao ser humano que são possíveis detectar nos sinais binários. Dessa forma, a
17
taxa de transmissão é diminuída e é possível transmitir uma maior quantidade de dados
através do mesmo canal de 6 MHz (MONTEZ; BECKER, 2005, p. 26-27).
Outra vantagem do sistema de transmissão digital é a ausência de interferências entre
canais alocados em freqüências próximas. Essa interferência que ocorre em sistemas de
transmissão analógicos obriga a reserva de certa faixa do espectro livre entre dois canais, que
pode ser realocada para outras emissoras de TV ou prestadora de serviço de
telecomunicações, no sistema de TV digital.
Assim como muitas outras vantagens proporcionadas pelo sistema digital, também se
destaca a viabilidade de fornecer interatividade. Esse recurso, que pode ser amplamente
explorado pela tecnologia digital, é apresentado no capítulo 3 com maiores detalhes e é usado
para o desenvolvimento apresentado no capítulo 5.
18
2 FUNDAMENTOS DE TV DIGITAL
2.1 Digitalização dos Sinais de TV Analógica
Para entender o conteúdo relacionado ao termo “sinal” e considerando que existem
vários significados para esse termo, uma possível definição para o termo é:
O sinal é a medida de uma grandeza de natureza física – seja acústica, ótica ou
elétrica – que veicula algum tipo de informação. Um sinal sonoro, por exemplo,
corresponde a uma onda sonora, que veicula informações sobre a voz de um locutor,
uma música, o ruído de uma pedra caindo etc. Um sinal de TV corresponde a uma
onda eletromagnética que veicula informações sobre áudio, vídeo e dados de
sincronização, usadas pelo aparelho receptor (MONTEZ; BECKER, 2005, p. 41).
Também pode-se considerar a explicação dada por Carlos Montez e Valdecir Becker
(2005, p. 42) para o significado do termo “analógico”: “Todo tipo de sinal em que a amplitude
varia continuamente no tempo é denominado sinal analógico.”.
O sistema de TV analógico utiliza três sinais, na faixa de 6 MHz, para apresentação de
cores: R (vermelho), G (verde) e B (azul). Como essas são as cores primárias, as demais cores
são apresentadas a partir de combinações proporcionais desses sinais. Além desses sinais,
existe também o sinal Y (luminância), que controla a sensação de brilho e luminosidade. O
sinal de luminância era usado desde os sistemas de TV em preto-e-branco e foi mantido por
questão de compatibilidade entre TV em cores e TV em preto-e-branco. Posteriormente foram
criados também os coeficientes de PB e PR, que são sinais de “diferença de cor” (YAMADA,
2005, p. 20-21).
Para executar funções mais sofisticadas, atualmente os receptores de TV analógica
recorrem à digitalização desses sinais analógicos, que envolve as etapas de amostragem e
quantização (YAMADA, 2005, p. 24). Os autores Carlos Montez e Valdecir Becker (2005, p.
42), explicam que amostrar significa: “capturar, de forma periódica, os valores do sinal
analógico”. Explicam também, que “a quantização implica na representação de cada um
desses valores usando um número de bits predefinido para armazená-los”. Digitalizar o sinal
significa que, através de um processo de digitalização, o sinal é amostrado discretamente com
uma freqüência de amostragem e passa por uma quantização, ou seja, cada nível de amplitude
será relacionado a uma respectiva combinação de bits, conforme definido anteriormente por
Montez e Becker. Atualmente, existe uma recomendação conhecida como ITUR601, que
19
padronizou o valor fUF = 3,375MHz como sendo a unidade fundamental de amostragem
(YAMADA, 2005, p. 24).
Os formatos de digitalização são definidos de acordo com o número de unidades de fUF
utilizados na amostragem. Exemplos de formatos:
Formato 4:4:4 – consiste em amostragens de 4fUF para R, G e B, ou amostragens de
4fUF para Y, PB e PR e é usado para exibições de qualidade extremamente alta.
Formato 4:2:2 – consiste em amostragens de 4fUF para Y e 2fUF para PB e PR e é o
formato mais utilizado. A qualidade da imagem exibida através desse formato é muito
boa.
Formato 4:1:1 – consiste em amostragens de 4fUF para Y e 1fUF para PB e PR.
Formato 4:2:0 – Esse formato possui a vantagem de fornecer economia na taxa de bits.
Consiste em amostragens no formato 4:2:2 em uma linha e em amostragens no
formato 4:0:0 na linha seguinte, sem os sinais de PB e PR (YAMADA, 2005, p. 25).
2.2 Vantagens e Desvantagens da Digitalização do Sinal
As principais desvantagens de digitalizar um sinal são que se perde uma pequena parte
da informação durante o processo de amostragem e há uma distorção do sinal original devido
ao processo de quantização, onde existe certo “arredondamento” do sinal. Essa distorção fica
evidente ao visualizar a Figura 1 (MONTEZ; BECKER, 2005, p. 42-43).
Figura 1 – Digitalização de um sinal analógico (amostragem e quantização)
Fonte: Montez e Becker (2005, p. 42)
Para diminuir esses efeitos sobre a conversão do sinal, deve-se usar uma taxa de
amostragem alta e um número grande de bits para o processo de quantização, porém com isso
20
o sinal digital fica maior, sendo necessário maior espaço de armazenamento e de largura de
banda disponível. Dessa forma, deve-se estabelecer uma relação de custo-benefício entre a
qualidade e tamanho do sinal digitalizado (MONTEZ; BECKER, 2005, p. 43).
Apesar dessas desvantagens, o grande benefício da digitalização é que, ao digitalizar
um sinal, é possível processá-lo em computadores, podendo ser manipulado facilmente e
tratado com algumas técnicas como compressão, detecção e correção de erros, etc.
(MONTEZ; BECKER, 2005, p. 44).
Outro benefício é que pequenos ruídos na transmissão digital podem ser tratados e
corrigidos, desde que não ultrapassem determinado limite (MONTEZ; BECKER, 2005, p.
44).
2.3 Representação da Imagem Digital
Em aparelhos de TV Digital, a imagem é representada por um sistema de coordenadas
bidimensional linha X coluna que subdivide a tela em pixels (picture elements), onde cada
pixel recebe uma intensidade de sinal de acordo com um valor numérico que representa uma
cor (HU; RAUNHEITTE, 2004, p. 236). Um exemplo dessa representação de uma imagem
digital é exibida na Figura 2.
21
Figura 2 – Sistema de coordenadas para representar cada pixel da imagem.
Fonte: Hu e Raunheitte (2004, p. 232)
Pode-se definir um pixel como sendo o menor detalhe que um sistema reprodutor de
imagens consegue reproduzir (YAMADA, 2004, p. 17). Seguindo essa idéia, tem-se o
seguinte conceito sobre pixel:
Pixel é o componente elementar de uma imagem digital que representa a
intensidade luminosa de determinado ponto. Aos valores dos pixels associa-se uma
tabela de cores ou de níveis de cinza. Uma imagem é formada por uma matriz de
pixels denominada BitMap ou mapa de bits. (HU; RAUNHEITTE, 2004, p. 28).
Sendo assim, a imagem é modelada matematicamente através de uma matriz
bidimensional representando o sistema de coordenada de pixels, onde cada pixel tem uma
posição na matriz indicada pela relação linha X coluna que corresponde à sua posição na tela
(HU; RAUNHEITTE, 2004, p. 236).
2.4 Televisão de Alta Definição
No início da década de 80, os japoneses apresentaram os resultados de uma pesquisa
que iniciou o processo de evolução da televisão para o que chamamos de televisão de alta
22
definição. Através dessa pesquisa, foi desenvolvido um sistema analógico que oferecia um
número de linhas maior que o dobro (de 525 para 1125), além de melhorar a qualidade da
transmissão do som. Essa pesquisa deu origem ao sistema japonês MUSE (Multiple Sub-
Nyquist Sampling Encoding), que foi o primeiro sistema de televisão de alta definição a entrar
em operação em escala comercial (FERNANDES; LEMOS; SILVEIRA; 2004, p. 9).
A resolução é um termo que está relacionado à quantidade de informação que pode ser
exibida, sendo então um elemento muito importante para definir a qualidade da imagem de
TV e, portanto, uma característica importante para televisão de alta definição. Geralmente, a
referência usada para medir a resolução em aparelhos de TV é o número de linhas na vertical
(TORRES, 2005).
As TVs de alta definição atuais, mais conhecidas como HDTV (High Deffinition TV),
são aparelhos de alta resolução, com capacidade de operar em resolução de até 1080 linhas
ativas, ao contrário das TVs analógicas, que operam em resolução de 485 linhas ativas.
Portanto, esses aparelhos conseguem exibir com ótima qualidade a imagem da TV. Porém, a
transmissão de imagens em alta resolução através dos canais de radiodifusão só foi possível
através do sistema de TV digital (TORRES, 2005).
Outro elemento que também contribui de forma significativa com a qualidade de
imagem é o modo de varredura não-entrelaçado (ou varredura progressiva) que o aparelho de
HDTV pode proporcionar, diferente do modo de varredura entrelaçado, que também é usado
em alguns aparelhos de HDTV, mas é o único modo usado no sistema de transmissão
analógica. O modo de varredura entrelaçado é identificado com a letra “i”, de interlaced e o
modo não-entrelaçado é identificado com a letra “p”, de progressive (TORRES, 2005).
No sistema de transmissão analógica, onde o método de varredura é entrelaçado,
primeiro são desenhadas as linhas ímpares e após a tela ser preenchida completamente as
linhas pares são desenhadas. Com o método de varredura não-entrelaçado, as linhas são
desenhadas em apenas uma varredura. Como a freqüência de 60 campos por segundo é
mantida, ou seja, a cada segundo a tela é preenchida 60 vezes, em um segundo o modo de
varredura entrelaçado oferece apenas 30 quadros completos, pois a informação completa de
um quadro é obtida pelo intercalamento das linhas de dois campos, enquanto que o modo não-
entrelaçado oferece 60 quadros completos por segundo. Dessa forma, a varredura progressiva
23
cria uma imagem mais nítida e não apresenta cintilação, fenômeno conhecido como flicker
(TORRES, 2005).
Além desses elementos, outra característica das TVs é a sua relação de aspecto da
imagem (largura/altura). Enquanto que nas TVs analógicas a relação de aspecto empregada é
4:3, em padrões de HDTV essa relação é 16:9 (TORRES, 2005).
A Tabela 1 apresenta as resoluções de TV digital existentes:
Nome Resolução Varredura Relação de Aspecto
480i 640 x 480 Entrelaçada 4:3 (1,33)
480p 640 x 480 Não-Entrelaçada 4:3 (1,33)
720i 1280 x 720 Entrelaçada 16:9 (1,78)
720p 1280 x 720 Não-Entrelaçada 16:9 (1,78)
1080i 1920 x 1080 Entrelaçada 16:9 (1,78)
1080p 1920 x 1080 Não-Entrelaçada 16:9 (1,78)
Tabela 1 – Resoluções de TV digital.
Fonte: Torres (2005)
As modalidades com relação de aspecto 4:3 são parecidas com a TV analógica e
conhecidas como SDTV (Standard Definition Television). Entre as modalidades com relação
de aspecto 16:9, existem as EDTV (Enhanced Definition Television), que são TVs de média
definição, possibilitando a utilização de aparelhos com 720 linhas de 1280 pontos. Acima
desta, vem o HDTV, com uma resolução de 1080 linhas de 1920 pontos (TORRES, 2005).
2.5 Modulação do Sinal
A modulação é o processo em que, de acordo com o sinal da informação a ser
transmitido, altera alguma característica da onda original, gerando assim uma onda portadora,
onde há uma faixa de freqüências controlada de forma a sofrer o mínimo de atenuação,
distorção e interferência ao transmitir os dados (MONTEZ; BECKER, 2005, p. 46).
Para transportar o sinal de TV Digital, constituído de áudio, vídeo e dados, até o
usuário, é utilizado um sistema de comunicação. Para proteger o sinal dos problemas de
atenuação por perdas de energia do sinal transmitido, ruídos provocados por outros sinais e
24
distorções de atraso, é necessário que a informação sofra uma modulação na transmissão e
uma demodulação na recepção. Além disso, principalmente para o sistema de transmissão
digital, a modulação é muito importante, pois faz com que o sinal digital seja deslocado para
uma faixa de freqüência adequada para transmissão pelos canais de radiodifusão (MONTEZ;
BECKER, 2005, p. 46-47).
Existem três métodos fundamentais para modular o sinal: modulação por amplitude,
modulação por freqüência ou modulação por fase. Normalmente, para sinais digitais, esses
métodos de modulação são combinados, fazendo com que a transmissão fique mais imune a
erros e com maior capacidade de transmissão de bits por segundo (MONTEZ; BECKER,
2005, p. 47). Esses métodos podem ser visualizados na Figura 3.
Figura 3 – Modulação por amplitude, freqüência e fase.
Fonte: Montez e Becker (2004, p. 47)
Nos televisores digitais os efeitos causados pelos ruídos e interferências são
percebidos como artefatos (minúsculos quadrados) que se espalham pela tela. Para minimizar
esses efeitos, procurou-se usar uma modulação mais robusta, aplicando técnicas como
distribuição aleatória de bits, corretor de erros, embaralhamento do conteúdo dos dados, etc.
(YAMADA, 2004, p. 30).
25
2.6 Transmissão e Recepção do Sinal de TV Digital
A transmissão de sinais de TV Digital segue as mesmas condições utilizadas para TV
analógica, com a largura de banda de cada canal sendo 6MHz e obedecendo as mesmas faixas
de freqüência disponibilizadas para os canais (YAMADA, 2004, p. 30).
A maior mudança entre os transmissores para TV analógicos e digitais é o processo de
modulação, onde, como foi explicado, utilizam-se técnicas para minimizar ruídos e
interferências indesejadas (YAMADA, 2004, p. 30).
Durante a etapa de transmissão, o sinal passa por um processo de compressão usando
métodos tais como o MPEG2 (Moving Picture Expert Group), pois o sinal de vídeo de alta
definição (HDTV) tem uma taxa de bits muito elevada, incompatível com o meio de
radiodifusão que limita a largura de banda a 6MHz (YAMADA, 2004, p. 31).
Após a compressão, os sinais de vídeo, áudio e dados são multiplexados em um único
fluxo de bits através de um circuito multiplexador. Esse fluxo passa então por um circuito
modulador, que o processa de acordo com o método utilizado por cada padrão de TV Digital
(YAMADA, 2004, p. 31).
O sinal modulado passa por um amplificador de FI, que tem por objetivo eliminar as
freqüências indesejadas geradas no processo de modulação. A freqüência do sinal é então
convertida para freqüência final de transmissão e por fim é amplificado para a transmissão ter
potência necessária para cobrir a área desejada (YAMADA, 2004, p. 31). A Figura 4 ilustra
esse processo.
26
Figura 4 – Diagrama do transmissor.
Fonte: Yamada (2004, p. 31)
Na recepção, ocorre o processo inverso da transmissão. Nesse caso, a demodulação é
alcançada através das funções inversas as que foram utilizadas na modulação. Como o sinal
recebido pela antena pode chegar muito baixo dependendo da distância, freqüência e
condições de propagação, o receptor tem um dispositivo de controle automático de ganho
(CAG), o que possibilita a entrega de um nível de sinal estável e constante ao demodulador,
independente do sinal de entrada (YAMADA, 2004, p. 33). Os principais componentes de um
receptor são exibidos na Figura 5.
Figura 5 – Diagrama do receptor de TV Digital.
Fonte: Yamada (2004, p. 33)
2.7 Compressão do Sinal Digital
Devido aos requisitos de difusão e armazenamento de mídias digitais, fica evidente
que a compressão é uma das mais importantes atividades no processamento de dados digitais.
Esse processo ocorre durante a etapa de codificação, logo após a digitalização dos sinais de
áudio, vídeo e dados, e pode ser medido através da taxa de compressão, que é a divisão do
27
número de bytes antes da compressão pelo total de bytes resultante (MONTEZ; BECKER,
2005, p. 55-56).
Existem dois fatores que possibilitam a compressão em mídias digitais: a redundância
da informação e a limitação da percepção humana. Para conseguir uma alta compressão dos
dados multimídia, são utilizadas em TV digital técnicas combinadas, baseadas tanto nas
características da percepção humana quanto nas redundâncias existentes na informação a ser
transmitida. Sem essas técnicas de compressão, seria impossível a transmissão de fluxos de
vídeo no caso da HDTV sem compressão, onde a taxa supera 800 Mbps (MONTEZ;
BECKER, 2005, p. 56).
No caso de vídeos, podemos destacar dois tipos de redundância. Um deles se refere à
repetição de trechos idênticos na imagem. Esse tipo de redundância é conhecido como
redundância espacial e as técnicas utilizadas para eliminar informações redundantes
adjacentes desse tipo costumam ser denominadas codificação preditiva. Outro tipo de
redundância, chamado de redundância temporal, existe quando não há alteração entre quadros
adjacentes. Com o áudio, a redundância é considerada muitas vezes nos momentos de
silêncio. Dessa forma, usa-se a técnica de supressão do silêncio, reduzindo bastante o
tamanho dos arquivos de áudio (MONTEZ; BECKER, 2005, p. 56-57).
A limitação da percepção humana também é amplamente explorada pela compressão,
aproveitando-se de algumas propriedades do sistema nervoso humano. Uma delas é o
mascaramento, onde um estímulo específico não é percebido na presença simultânea ou logo
após algum outro estímulo. Isso ocorre tanto no caso de áudio, onde alguns tons não são
ouvidos na presença simultânea de outros, quanto no caso de vídeo, onde a iluminação pode
tornar objetos na penumbra invisíveis. Outra propriedade é que o olho humano é bem mais
sensível a variação de tons de cinza do que a variação de tons coloridos. Isso é utilizado em
técnicas que separam os tons de cinza, denominados “luminância”, dos componentes das
cores, denominados “crominância”. Dessa forma, a crominância é codificada em uma
freqüência menor, por uma técnica conhecida como subamostragem (MONTEZ; BECKER,
2005, p. 57-58).
Além das técnicas que se baseiam nesses dois fatores descritos, existem outras, que
são normalmente utilizadas em documentos digitais, como a codificação estatística utilizada
28
na técnica de codificação de Huffman, onde para representar seqüências binárias mais
freqüentes, são utilizados menos bits do que a quantidade utilizada em seqüências menos
freqüentes (MONTEZ; BECKER, 2005, p. 58).
As técnicas de compressão podem ser classificadas através de algumas características.
Diferente das técnicas com perdas utilizadas para compressão multimídia, onde a
representação dos dados na forma de bits é bem diferente da original, as técnicas utilizadas
para compressão de documentos de texto, bases de dados e planilhas, são consideradas sem
perdas. Além disso, as técnicas de compressão podem ser baseadas em entropia ou baseadas
na fonte. As técnicas baseadas em entropia não consideram a característica e semântica do
dado a ser comprimido, sendo assim técnicas sem perdas. Já nas técnicas baseadas na fonte, a
característica e semântica do dado são consideradas para o processo de compressão
(MONTEZ; BECKER, 2005, p. 58-59).
A Tabela 2 exibe uma classificação para algumas técnicas de compressão:
Com Perdas Sem Perdas
Baseada na Fonte Baseada em
mascaramento Baseada em transformada
Baseada em Entropia
Huffman, supressão de seqüências
repetidas, codificação estatística,
eliminação de redundância
Tabela 2 – Classificação das técnicas de compressão.
Fonte: Montez e Becker (2005)
Existem vários métodos de compressão de vídeo, porém o mais utilizado em TV
Digital é o MPEG2, embora o Brasil tenha definido o H.264 como método de compressão.
2.8 Padrões de TV Digital
Os três principais padrões de TV Digital existentes são: ATSC (Advanced Television
System Comitee), DVB-T (Digital Video Broadcasting – Terrestrial) e ISDB-T (Integrated
System Digital Broadcasting – Terrestrial), que são, respectivamente, os padrões americano,
europeu e japonês. O sistema brasileiro de televisão Digital baseia-se no padrão japonês
(YAMADA, 2005, p. 44).
29
Para compressão da imagem de vídeo, esses três padrões adotaram o algoritmo
MPEG2. Já para compressão de áudio, cada padrão escolheu algoritmos de digitalização e/ou
compressão diferente. Multiplexadas às informações de áudio e vídeo, algumas informações
complementares e facilidades operacionais são incluídas no sinal digital (YAMADA, 2005, p.
44-45).
A principal característica do padrão ATSC é o fato de ser monoportadora (portadora
única) com modulação de amplitude com banda lateral vestigial de oito níveis ocupando a
mesma banda de 6MHz utilizada no sistema analógico. Nesse padrão, o modulador recebe um
feixe digital com uma taxa constante de 19,39Mbps, formado pela multiplexação dos sinais
comprimidos de áudio e vídeo mais o canal de dados. O padrão AC3 Dolby Digital é utilizado
para o canal de som. Através desse padrão, é possível configurar o áudio com um canal
(Mono) até seis canais (Multicanal), com taxa útil de bits de 384Kbps após a compressão. O
perceptual coding é um algoritmo proprietário utilizado para comprimir o sinal de áudio
(YAMADA, 2005, p. 45-52).
No sistema europeu (DVB-T), o método de modulação utilizado é o COFDM (Coded
Orthogonal Frequency Multiplex). Esse método é multiportadora e multiplexado por divisão
de freqüência (FDM). Antes de entrar no modulador, o sinal digital é codificado por código
corretor de erro. Isso garante uma maior confiabilidade diante das interferências recebidas do
meio. Para compressão do som, utiliza-se o Musicam (Masking Pattern Universal Sub-band
Integrated Coding and Multiplexing). Esse sistema de compressão digital aproveita-se das
características de mascaramento do ouvido e utiliza técnicas psicométricas de codificação
especificadas pelo padrão MPEG2 Audio Layer II. Esse padrão permite que o áudio seja
mono, estéreo e multicanal para taxa de bits de até 384Kbps (YAMADA, 2005, p. 52-68).
O sistema ISDB-T é uma forma mais aprimorada do DVB-T, onde o sistema de
modulação e multiplexação são os mesmos do DVB-T. Uma das principais características que
difere esse sistema dos demais é a segmentação de banda, dividindo a largura de 6MHz do
canal em 13 segmentos e utilizando os segmentos de acordo com o tipo de transmissão
escolhido (YAMADA, 2005, p. 68-69).
30
2.9 Sistemas de TV Digital Interativa: Componentes e Arquitetura
De forma idêntica a qualquer sistema de comunicação, o sistema de TV Digital é
composto por transmissor, receptor e canal de comunicação. A Figura 6 ilustra um modelo de
sistema de televisão digital interativa representando esses componentes (MONTEZ;
BECKER, 2005, p. 73).
Figura 6 – Modelo de um sistema de televisão digital interativa.
Fonte: Montez e Becker (2004, p. 73)
Na transmissão, temos o provedor do serviço de difusão, também denominado difusor.
O difusor, que além de construir e transmitir o conteúdo ao telespectador, também tem a
capacidade de controlar o acesso, restringindo a disponibilidade aos serviços de acordo com a
disponibilidade para cada tipo de assinante. Para que esse acesso condicional seja possível,
antes da multiplexação do sinal o serviço é protegido através de criptografia, que pode ser
decodificada na recepção através de informações enviadas por pacotes adicionais (MONTEZ;
BECKER, 2005, p. 75).
Para esse sistema, o canal de comunicação é conhecido como meio de difusão. O meio
de difusão pode ser via satélite, cabo ou difusão terrestre (radiodifusão). Como a radiodifusão
é o meio usado atualmente pelo sistema de TV convencional, esse meio de difusão tem uma
grande vantagem, pois viabiliza a transmissão simultânea de canais para TVs analógicas e
digitais, facilitando o processo de migração dos telespectadores da TV analógica para a TV
digital. Por outro lado, a largura de banda é pequena para esse meio de difusão. Além disso,
assim como a transmissão via satélite, não há canal de retorno, usado para que o telespectador
31
possa interagir com o provedor de serviços. Portanto, desses meios de difusão apresentados, o
único que permite a interatividade é a comunicação via cabo, pois além de ser um canal de
difusão também serve como canal de retorno (MONTEZ; BECKER, 2005, p. 74).
Após ser captado pelo meio de difusão, o sinal é processado pelo receptor, que pode
estar embutido em uma TV digital ou estar separado da TV analógica em um equipamento
chamado set top box. Esse equipamento é responsável por converter os sinais digitais
recebidos pelo meio de difusão para o sinal analógico reconhecido pela TV convencional,
além de poder também fornecer um canal de retorno para interatividade ao telespectador. Para
que essa interação seja possível, o set top box apresenta uma arquitetura idêntica à de um
microcomputador, porém com alguns componentes de hardware específicos. Além disso,
esses dispositivos possuem sistemas operacionais simples, geralmente armazenados em
memória ROM (Read Only Memory) (MONTEZ; BECKER, 2005, p. 77-79).
A arquitetura de TV digital é dividida entre as camadas de aplicações, middleware,
compressão, transporte e modulação (MONTEZ; BECKER, 2005, p. 86). A Figura 7
apresenta uma arquitetura de TV digital representando as camadas de tecnologias existentes.
Figura 7 – Arquitetura de TV digital com tecnologias usadas em cada camada.
Fonte: Montez e Becker (2004, p. 86)
32
A camada de middleware serve como uma interface entre as camadas inferiores
(compressão, transporte e modulação) e as aplicações. Sendo assim, o middleware fornece
portabilidade para as aplicações, que podem ser executadas sob qualquer receptor digital, seja
embutido na TV ou via set top box, desde que o receptor suporte o middleware adotado
(MONTEZ; BECKER, 2005, p. 87).
Os sistemas de TV digital norte americano, europeu e japonês adotam diferentes
padrões de middleware. O sistema ATSC (padrão norte-americano) utiliza o DASE (DTV
Application Software Environment) como middleware, o sistema DVB (padrão europeu)
utiliza o MHP (Multimedia Home Plataform) e o sistema ISDB (padrão japonês) utiliza o
ARIB (Association of Radio Industries and Business) (MONTEZ; BECKER, 2005, p. 87-90).
33
3 INTERAÇÃO HUMANO-COMPUTADOR APLICADA A SISTEMAS
DE TV DIGITAL
3.1 Visão Geral
A Interação Humano-Computador (IHC) é uma área da Ciência da Computação que
estuda a relação entre pessoas e sistemas computacionais. Para se definir de maneira mais
formal e direta o que é a IHC, dois outros conceitos básicos precisam ser definidos de
antemão: Interface e Interação.
“Interface é toda a porção de um sistema com a qual um usuário mantém contato ao
utilizá-lo, tanto ativa quanto passivamente.” (SILVA, 2006, p.8).
A interação no contexto da TV digital pode ser definida como a comunicação entre o
usuário e o sistema televisivo. Com a existência desta comunicação torna-se possível uma
participação mais ativa do telespectador.
A importância da IHC está em produzir sistemas com maior qualidade de interação. A
qualidade de interação é definida por vários fatores que estão na maioria das vezes
direcionadas à avaliação do usuário final, no caso, o telespectador. Para obter um software de
qualidade seguindo a IHC é preciso que os usuários finais estejam no mínimo satisfeitos na
utilização do software.
Definida a importância da interação nos sistemas de TV e considerando que a
qualidade é avaliada principalmente com a opinião do usuário final, segue uma breve
introdução de como se alcançar a qualidade de IHC e a satisfação do usuário.
3.2 Qualidade de IHC e Satisfação do Usuário
Sistemas para uso com fins pessoais, empresariais, e as aplicações de entretenimento
são de grande interesse por possuírem algum foco em fatores humanos. Para esse tipo de
sistema, a facilidade de aprendizado, baixa taxa de erros e satisfação subjetiva são
fundamentais e sem essas características o usuário pode vir a abandonar a aplicação
(SHNEIDERMAN, 1998, p.17).
34
A TV digital se enquadra na classe de sistemas que possuem foco em fatores humanos
já que na maioria das vezes é utilizada em lares e como meio de entretenimento. A
experiência precisa ser agradável para manter o telespectador na frente da televisão e
utilizando a aplicação. No início, quando as primeiras aplicações da TV Digital começarem a
surgir de maneira aberta ao grande público, os usuários precisarão de uma experiência fácil e
agradável, atraindo pessoas de todas as idades e regiões. Isso pode trazer grandes impactos
como deseja o governo, permitindo a inclusão digital de pessoas que não estão habituadas a
utilizar um computador ou outros dispositivos interativos de igual capacidade informática e
computacional.
Para se alcançar a qualidade de software do ponto de vista interativo e evitar problemas como
o abandono da aplicação por parte do usuário, podem ser considerados vários aspectos, o
principal desses aspectos é a usabilidade. A usabilidade normalmente é definida como a
facilidade de uso de um software, mas apenas esse fator não caracteriza a usabilidade por
completo. Outros fatores que caracterizam a usabilidade segundo Silva (2006), são: facilidade
de aprendizado, eficiência de uso, produtividade, satisfação do usuário, flexibilidade, utilidade
e segurança no uso.
Considerando os fatores acima mencionados é possível perceber que todos estão
centrados no usuário. No contexto da TV Digital, para que o desenvolvimento de software
alcance a satisfação do telespectador e a qualidade de IHC, será preciso observar quem
utilizará o software, onde este software será utilizado, e todos os fatores relacionados ao
ambiente onde o software estará sendo utilizado. Considerando o ambiente onde está situado
o usuário final é possível imaginar-se na situação deste usuário e então propor requisitos para
que a aplicação faça o mínimo necessário e, além disso, gere inovações para que em alguns
pontos a aplicação supere o esperado, tornando-se mais agradável e útil.
Além da usabilidade, outros aspectos devem ser considerados quando se busca a
qualidade de IHC. Segundo Silva (2009), comunicabilidade e aplicabilidade são dois aspectos
complementares aos de usabilidade.
Comunicabilidade é a capacidade de a interface comunicar ao usuário final qual a
funcionalidade de um determinado componente. A aplicabilidade é determinada pelo
35
aproveitamento do sistema no contexto para o qual foi projetado e pelos contextos em que
pode ser aplicado como uma solução. (SILVA, 2009).
Após ter sido definida a IHC e a razão de sua utilização, é necessário seguir um
processo para alcançar o principal objetivo de uma aplicação interativa: satisfazer o usuário
final, que nesse caso é o telespectador. Considerando que para uma aplicação desenvolvida no
âmbito de TV digital alcançar mais rapidamente a satisfação do usuário esta aplicação deve
seguir um processo, a próxima seção define interatividade e como este desenvolvimento pode
ser guiado através de um processo de projeto interativo.
3.3 Processo de Desenvolvimento Interativo
A interatividade é o grau de interação que um sistema fornece para a comunicação com os
seus usuários. Na televisão analógica, a interatividade se restringe a comunicação por outros
meios, por exemplo: o telefone. Mas na televisão digital, através do meio de transmissão, é
possível para a emissora transmitir informação além da programação. O usuário pode
informar suas preferências utilizando então o canal de retorno, tornando a televisão mais
personalizada.
Muitos fatores determinam se a interatividade de um sistema é boa ou ruim. A interatividade
em um sistema está amplamente relacionada com a usabilidade, e os fatores de qualidade de
IHC. Pode-se então aplicar o processo de desenvolvimento interativo para modelar a
interatividade de um sistema.
O processo de desenvolvimento interativo é composto basicamente de quatro
atividades que são as seguintes: identificação de necessidades e estabelecimento de requisitos,
desenvolvimento de projetos alternativos, construção de versões interativas dos projetos e
avaliação do que está sendo construído nos projetos. Uma característica chave do processo é
que pode ser aplicado de maneira iterativa (PREECE; ROGERS; SHARP, 2002, p. 169).
Durante a obtenção dos requisitos é necessário conhecimento do domínio onde a
aplicação será executada para evitar assim possíveis riscos relacionados à inviabilidade de
requisitos (PREECE; ROGERS; SHARP, 2002, p. 169).
36
Na etapa de obtenção de requisitos, cuidados relacionados à inviabilidade devem ser
consultados para que a interação não seja prejudicada. A tentativa não planejada de se
implementar alguma funcionalidade com pouca viabilidade pode requerer adaptações
inadequadas na interface, o que prejudica a interação do sistema.
Após a obtenção dos requisitos é necessário projetar as primeiras interfaces do
sistema, produzindo inclusive interfaces alternativas. Esta etapa tem por objetivo alcançar os
requisitos estabelecidos anteriormente e sugerir novas idéias através das alternativas geradas.
É uma atividade fundamental no processo de projeto de interação (PREECE; ROGERS;
SHARP, 2002, p. 169).
O projeto de interfaces alternativas tem grande importância no processo porque além
de gerar novas opções de como a interface pode ser desenhada e a interação modelada,
permite que inovações aconteçam da junção de idéias.
Com os projetos de interfaces já desenhados é possível iniciar a construção de uma
versão interativa. A versão interativa pode ser um protótipo em software ou um protótipo em
papel que apenas exibe como a interface reage às diversas formas de interação fornecidas pelo
sistema. Além de fornecer uma visão de como o sistema será; o protótipo permite uma melhor
avaliação do projeto. (PREECE; ROGERS; SHARP, 2002, p. 169).
Para finalizar, depois de desenvolvidas as interfaces e suas respectivas interações, é
necessário realizar a avaliação da mesma. A avaliação da interface é realizada baseando-se em
usabilidade e aceitabilidade por parte do usuário final. Se a interface for escolhida, pode-se
então aplicar algum processo iterativo de desenvolvimento de software para aperfeiçoar o
sistema, incluindo a interface. (PREECE; ROGERS; SHARP, 2002, p. 169).
3.4 Avaliação de Sistemas Interativos
Uma das etapas fundamentais do processo de desenvolvimento de software para
qualquer ramo é a fase de testes e avaliação. Nessas etapas os objetivos são alcançar a
qualidade do software, encontrar bugs, acrescentar últimos detalhes, entre outros.
37
Para o desenvolvimento de um aplicativo interativo para a TV Digital não é diferente.
A avaliação é importante pelos motivos já citados e, além disso, a interação é testada e
avaliada para garantir que o aplicativo agradará aos telespectadores.
A avaliação da interatividade pode ser feita através de parâmetros como: facilidade de
uso, facilidade de aprendizado, eficácia, eficiência, segurança e satisfação. Sendo também
fonte de entretenimento e atratividade. A avaliação focando esses objetivos deve percorrer
desde testes com a navegação através do aplicativo até reações obtidas pelos usuários com as
respostas produzidas pelo sistema na interface. Os testes de interatividade são importantes por
diversos fatores, alguns deles são: problemas comuns corrigidos antes do lançamento do
produto, redução nos custos de aprendizado para o usuário, menores necessidades de
modificação da interface entre outros. (PREECE; ROGERS; SHARP, 2002, p. 318)
Há várias maneiras de se avaliar a usabilidade de um sistema. Mas a principal
avaliação ocorre quando o usuário final testa o sistema, chamada de avaliação heurística.
Outra maneira de se testar um sistema é quando alguma pessoa é designada a realizar o teste,
mas essa não é necessariamente um usuário final, chamado teste de usabilidade. (LAUESEN,
2005).
A avaliação heurística é o método mais informal e mais comumente utilizado para
avaliação de interatividade em sistemas. A avaliação heurística é realizada com vários juízes
especialistas em usabilidade. Cada juiz avalia separadamente o sistema e depois todos
discutem a respeito da interface projetada (HOLZINGER, 2005).
Os métodos de teste de usabilidade são menos informais por serem com prováveis
usuários finais do sistema. Os métodos mais comuns são os baseados em questionário por
serem os mais simples de serem realizados. Existem também os métodos de observação de
campo e outros que consistem em pensar em voz alta. Os testes baseados em questionários
são realizados a partir de questões pré-definidas, onde o usuário comenta sua experiência após
a utilização do sistema. Os testes baseados no ato de pensar em voz alta consistem do
acompanhamento do projetista enquanto o usuário utiliza o sistema. O usuário também fala
tudo o que sente ou percebe ao utilizar a interface do sistema. Os métodos de observação de
campo ocorrem quando os futuros utilizadores do sistema são visitados por projetistas que de
maneira silenciosa verificam como o trabalho pode ser otimizado através de algum sistema
computacional (HOLZINGER, 2005).
38
Para o desenvolvimento de aplicações da TV Digital, o uso de métodos de observação
de campo se torna menos atraente. Contudo, os métodos de questionário e pensar em voz alta
podem ajudar na identificação de pontos de vista diferentes de diferentes pessoas ou grupos
de pessoas, principalmente porque o conhecimento e a facilidade de manuseio de tecnologias
ainda é um pouco restrito no Brasil.
39
4 APLICAÇÕES PARA TV DIGITAL UTILIZANDO A API JAVA TV
4.1 Visão Geral
Java é uma linguagem de programação orientada a objetos. Uma das facilidades que
existem para a linguagem e para o desenvolvimento de aplicações de TV Digital é a API
(Application Programming Interface) Java TV.
JavaTV é uma API, desenvolvida pela Sun Microsystems em parceria com empresas
do ramo de televisão digital, que fornece meios de desenvolvimento para aplicações de TV
digital interativa através da linguagem de programação Java utilizando apenas chamadas a
recursos já implementados. A tecnologia Java possui alto grau de portabilidade, isto é, pode
ser executada em diversas plataformas. Essa característica faz com que a linguagem seja
utilizada em aplicações que são executadas sobre os mais diversos aparelhos. Aproveitando-se
dessa portabilidade do Java, a API Java TV foi projetada exclusivamente para receptores de
televisão digital. Sendo assim, a aplicação pode ser executada sobre os aparelhos de televisão
digital, desde que estes utilizem o mesmo padrão de middleware. O padrão de middleware a
ser adotado no Brasil é o SBTVD, um padrão baseado no ISDB, que é o padrão japonês para
TV Digital.
Segundo o site da Sun, Java TV fornece acesso às seguintes funcionalidades:
Streaming de áudio/vídeo;
Acesso incondicional;
Acesso a canais de dados in-band e out-of-band;
Acesso ao serviço de informação;
Controle de mudança de canal;
Controle do gráfico apresentado na tela;
Funcionalidades adicionais, como sincronização de mídia e controle do ciclo
de vida da aplicação.
Uma aplicação desenvolvida para televisão digital pode utilizar as bibliotecas
disponíveis na API Java TV, que permitem aos desenvolvedores oferecer aos telespectadores
40
conteúdos interativo em seus televisores, como vídeos sob demanda, guias de programação
eletrônica ou seleção de diversos ângulos da câmera em eventos desportivos, por exemplo.
A API Java TV geralmente funciona sob um sistema operacional de tempo real (Real
Time Operational System - RTOS), que controla o hardware através de uma coleção de
drivers de dispostivo e fornece o suporte necessário à implementação da máquina virtual Java
e suas bibliotecas.
Para simular o STB (Set-Top Box), existe um emulador chamado XleTView, este
aplicativo emula o middleware MHP (Multimedia Home Platform). Não é o mesmo adotado
no Brasil, mas fornece funcionalidades suficientes para simular um ambiente de TV e então
aplicar conceitos de IHC (Interação Humano-Computador).
O desenvolvimento e teste de aplicações para TV em um ambiente simples requer
basicamente estas ferramentas: Java JDK (Java Development Kit), API Java TV e XleTView.
4.2 Xlets
O Xlet é uma interface da API Java TV que permite o desenvolvimento de aplicativos
que possam ser reconhecidos pelo middleware como aplicativos de TV digital. A interface
Xlet possui quatro métodos que devem ser implementados caso seja utilizada. Esses métodos
alteram o estado de um Xlet durante seu ciclo de vida. De acordo com a especificação da Sun,
os estados do ciclo de vida de um Xlet são: Carregado, Pausado, Ativo e Destruído. A Figura
8 exibe a relação existente entre esses estados no ciclo de vida de um Xlet.
41
Figura 8 – Modelo do Ciclo de Vida de Xlets
Através de métodos definidos na interface Xlet é possível transitar entre os estados.
Existem quatro métodos, também mostrados na Figura 8 que permitem a mudança de estados.
Os métodos são: initXlet( XletContext context ), startXlet( ), pauseXlet( ) e destroyXlet(
boolean unconditional ).
Quando o middleware carrega o Xlet, este se encontra no estado Carregado (Loaded),
em que só entra uma vez durante seu ciclo de vida. Nesse momento, o middleware invoca o
método initXlet(XletContext context), que será chamado apenas uma vez durante o ciclo de
vida do Xlet. Este método sinaliza o Xlet a se inicializar e entrar no estado Pausado (Paused).
Como parâmetro, é passado um XletContext, que pode ser usado pelo Xlet para acessar
propriedades associadas com o ambiente de execução.
Estando o Xlet no estado Pausado, o middleware pode invocar o método startXlet()
para sinalizar o Xlet a entrar no estado Ativo (Active). O código para execução da aplicação
deve estar contido nesse método.
42
Do estado Ativo, o Xlet pode retornar ao estado Pausado para parar a execução da
aplicação, através da invocação do método pauseXlet().
O método destroyXlet(boolean unconditional) é utilizado pelo middleware para
encerrar o Xlet. A partir desse momento, o Xlet entra no estado Destruído (Destroyed). Esse
método deve ser utilizado para liberar qualquer recurso que esteja em execução e salvar
qualquer persistência necessária, pois após a execução desse método o Xlet é destruído. O
valor booleano recebido pelo método de destruição do Xlet garante que nenhuma requisição
continuará em execução quando o unconditional for igual a true, mesmo se por alguma razão
o Xlet não ir para o estado Destruído.
Uma implementação vazia de um Xlet em Java pode ser visualizada na Figura 9:
Figura 9 – Implementação vazia de um Xlet
Os métodos de alteração de estado do Xlet são invocados pelo middleware, exceto em
alguns casos, quando é necessário que o próprio Xlet invoque a alteração.
// Import da API Java TV e outras classes necessárias para a Aplicação
public class Aplicacao implements Xlet {
public void initXlet (XletContext context) throws XletStateChangeException {
//implementação
}
public void startXlet ( ) throws XletStateChangeException {
//implementação
}
public void pauseXlet ( ) {
//implementação
}
public void destroyXlet (boolean unconditional) throws
XletStateChangeException {
//implementação
}
}
43
A implementação dos métodos de gerenciamento de estado permite não só que uma
aplicação gerencie o ciclo de vida de um Xlet, mas possibilita a comunicação entre Xlets no
mesmo ambiente. Para obter informações sobre o ambiente no qual está sendo executado, o
Xlet utiliza-se do objeto XletContext. O objeto XletContext possui funcionalidades como:
notificar ao seu ambiente que a execução da Xlet será parada ou que será destruída.
(MORRIS, 2008).
4.3 Pacotes da API Java TV
A API Java TV possibilita não só o desenvolvimento de aplicações simples para a TV
Digital utilizando Xlets simples, mas permite também acesso aos pacotes de classes utilizadas
pelas aplicações no escopo da TV Digital. A API Java TV é formada pelos seguintes pacotes
segundo Pawlan (2001):
javax.tv.carousel
javax.tv.graphics
javax.tv.locator
javax.tv.media
javax.tv.media.protocol
javax.tv.net
javax.tv.service
javax.tv.service.guide
javax.tv.service.navigation
javax.tv.service.selection
javax.tv.service.transport
javax.tv.util
javax.tv.xlet
O pacote principal do Java TV é o javax.tv.xlet, que contém as interfaces Xlet e
XletContext. O pacote javax.tv.graphics permite o desenho de GUI (Graphics User Interface),
assunto da seção 4.3. O pacote javax.tv.net permite o acesso a datagramas transmitidos por
broadcast utilizando o protocolo de Internet (Internet Protocol). E o pacote javax.tv.media,
44
que possibilita a visualização de recursos multimídia utilizando JMF (Java Media
Framework). Esses são apenas alguns dos pacotes utilizados pelo Java TV (PAWLAN, 2001).
O desenvolvimento de GUI é um fator importante pois possibilita que o telespectador
que utiliza a aplicação tenha uma interface amigável (user-friendly) para manipular a
aplicação. A seção 4.3 descreve maneiras de se utilizar GUI em aplicações Java TV.
4.4 Componentes GUI para Aplicações Java TV
A especificação da Sun para o Java TV define que as aplicações devem se aproveitar
dos recursos fornecidos pela VM (Virtual Machine) durante a execução. Um dos recursos
fornecidos pela VM é o Java AWT (Abstract Window Toolkit). O Java AWT exibe os
componentes de interface de acordo com o sistema no qual é executado. Sendo assim,
interfaces iguais podem ser exibidas de maneiras distintas em diferentes receptores. Outra
opção para o desenvolvimento de interfaces para aplicativos de TV Digital são os
componentes HAVi (Home Audio and Video interoperability) de interface com o usuário. Os
componentes HAVi foram desenvolvidos pelas principais empresas fornecedoras de aparelhos
eletrônicos com a intenção de fazer com que os aplicativos desenvolvidos sobre MHP
pudessem ser levados a outras plataformas de TV Digital diferentes da DVB (Digital Video
Broadcasting).
A HAVi User-Interface Architecture define um framework de desenvolvimento para
aplicações interativas de televisão digital onde o foco é voltado para a interface de usuário. Os
pacotes principais do framework HAVi são: org.havi.ui e org.havi.ui.event. Os componentes
do pacote org.havi.ui permitem a construção e exibição de componentes gráficos. Enquanto os
componentes do pacote org.havi.ui.event são baseados no tratamento de eventos a partir de
ações do usuário. Portanto, é possível com os pacotes de exibição e tratamento de eventos,
modelar a interatividade em um sistema para televisão digital. (HAVI, 2001).
A classe principal do pacote org.havi.ui é a classe org.havi.ui.HComponent que
estende a classe java.awt.Component. A partir do relacionamento de herança entre as duas
classes surge a interoperabilidade entre Java AWT e HAVi. A classe org.havi.ui.HComponent
é estendida por todos os outros componentes gráficos HAVi. No pacote org.havi.ui.event
existem classes e interfaces voltadas para o recebimento e tratamento de eventos. Para
aplicações em TV Digital uma classe importante é HRcEvent, que define alguns eventos de
45
controle remoto e constantes associadas aos eventos. Os listeners aparecem no pacote Java
AWT, com a interface KeyListener e em HAVi, com a interface HKeyListener que estende
KeyListener (HAVI, 2001).
Com as constantes utilizadas nas classes de eventos, a comparação e utilização dos eventos
obtidos por listeners se tornam mais simples e fácil de manipular. A razão da simplicidade na
manipulação são os nomes atribuídos para cada constante, já que os nomes na maioria das
vezes descrevem bem a funcionalidade do evento.
Outra classe importante da arquitetura HAVi é a classe HScene, localizada no pacote
org.havi.ui. A classe HScene surgiu com o intuito de eliminar o problema de gerenciamento
de janelas. Enquanto em computadores pessoais se pode facilmente manipular múltiplas
janelas; em um receptor de TV Digital não existe um gerenciador de janelas com a mesma
capacidade. Assim, o problema surge para o middleware que precisa gerenciar outros recursos
além das janelas e para o usuário que possui uma interface mais limitada para manipular as
janelas. O HScene elimina o problema se tornando um componente de nível superior para
GUIs, isto é, engloba outros componentes, assim como java.awt.Frame, mas sem precisar de
um gerenciador de janelas (MORRIS; SMITH-CHAIGNEAU, 2005).
A seção 4.5 exibirá duas aplicações simples que utilizam componentes gráficos, a primeira
utiliza componentes AWT, enquanto a segunda utiliza componentes HAVi.
4.5 Exemplos de Xlets
Com base nos itens das seções anteriores é possível implementar Xlets com interface
gráfica e com algum grau de interação. A interação pode ser obtida através da manipulação de
objetos Xlets que possuem referências para objetos gráficos, por exemplo, HComponents.
Os Xlets são executados sobre o XleTView, que é um emulador para o padrão de
middleware MHP, utilizado nos sistemas europeus de TV Digital. O XleTView gerencia o
ciclo de vida dos Xlets possibilitando a execução em computadores pessoais. Ao carregar um
Xlet na memória do emulador, é o próprio XleTView que possui componentes para chamar os
métodos initXlet, startXlet, pauseXlet e destroyXlet, de maneira similar como seria realizado
por um middleware em um set-top box real.
46
Na Figura 10 é apresentada uma enquete em forma de Xlet que está ocorrendo durante
uma partida de futebol, a parte gráfica da enquete foi criada utilizando componentes de
interface de usuário do Java AWT, mas sem a aplicação de conceitos de IHC. É possível
observar e enumerar alguns problemas na interface:
Janela de enquete grande, desproporcional ao seu conteúdo, o que atrapalha o
telespectador de assistir a partida de futebol. O fato da enquete se apresentar de
maneira opaca também impacta.
A interface não é auto-explicativa de como se votar.
o A votação é realizada com o botão “Votar” ou com o botão “OK” do controle
remoto? A seleção do voto através de botões no estilo RadioButton é muito boa
quando se utiliza o mouse, mas também é quando o que temos é apenas um
controle remoto?
A exibição da enquete seria correta em um aparelho de televisão?
o Provavelmente não. As fontes utilizadas na enquete não seriam bem exibidas em
um aparelho de TV por serem muito pequenas. Parte da enquete está fora da zona
delimitadora do emulador. A zona delimitadora também é chamada de área segura
e é representada pela parte interna ao retângulo amarelo exibido no emulador.
Para o aplicativo ser aceito pelo telespectador em uma televisão como forma de
interação, problemas como os mencionados acima precisam ser levados em consideração.
47
Figura 10 – Enquete implementada em Java TV.
Na Figura 11, é apresentada uma aplicação Xlet com uma área de texto onde o usuário
deve interagir e opinar sobre um determinado assunto. Contudo, o emulador não fornece
muitas opções através do controle remoto. No controle remoto padrão existem apenas teclas
numéricas e algumas teclas auxiliares. O fato de limitar a entrada de dados também limita a
interface e a interação com o usuário. Nas televisões atuais acontece o mesmo problema.
48
Figura 11 – Aplicação de pesquisa com opinião implementar em Java TV
Algumas soluções para o problema seriam:
Assemelhar as teclas do controle remoto às teclas de um telefone celular, onde
também são definidos caracteres. Tal solução utiliza aspectos que busca a Qualidade
de IHC, conhecidos como comunicabilidade e aplicabilidade. A comunicabilidade
expressa que a interface sendo modificada para utilizar o design das teclas de um
telefone celular traria benefícios para quem já utiliza celulares convencionais e
venham a utilizar o controle remoto. A aplicabilidade estaria também sendo utilizada
pois a solução de interface do aparelho celular estaria sendo aplicada ao contexto de
TV Digital em um controle remoto.
Outra solução seria expor junto ao texto um teclado virtual, onde o usuário visualizaria
um teclado comum na tela e poderia navegar pelas teclas através das setas do controle
remoto digitando o comentário desejado.
49
5 DESENVOLVIMENTO DE APLICATIVO INTERATIVO ATRAVÉS DE
JAVA TV
5.1 Visão Geral
O objetivo deste capítulo é descrever e documentar o desenvolvimento do aplicativo
proposto em Java TV. O aplicativo agrega os conhecimentos obtidos com IHC e utiliza o
emulador XleTView. Nos próximos itens são exibidas algumas informações da aplicação
desenvolvida, que explora o conceito de interatividade da TV Digital. No final do capítulo o
estudo sobre a aplicação é aprofundado.
5.2 Escolha Interativa de Programação
Atualmente algumas emissoras utilizam a idéia de escolha de programação através de
telefonemas. Muitas pessoas acabam não participando por estarem distantes de um telefone ou
pelo custo cobrado por ligação. Uma maneira diferente se obter a participação do
telespectador com a TV digital é através de uma aplicação recebida pelo STB. A aplicação
precisa apenas de um meio de interação e um canal de retorno para a emissora. Neste tipo de
aplicação o usuário seleciona a opção de programação escolhida por ele através do controle
remoto, os dados de cada usuário são enviados à emissora, e a emissora realiza então uma
análise sobre as escolhas e permite que aquela com o maior número de votos seja a
programação exibida.
Para esclarecer algumas necessidades da aplicação, a seguir são apresentadas as
funcionalidades que aplicação pode ter:
Fornecer duas ou três alternativas para escolha de programação.
Exibir a sinopse da programação que está marcada como escolhida.
Exibir a imagem ou trailler da programação, que está marcada como escolhida.
Fornecer a possibilidade de justificativas para o voto.
Toda aplicação baseada em IHC precisa fornecer um feedback constante para o
usuário. O feedback é necessário para que o usuário saiba como prosseguir. Um
exemplo de feedback necessário é a inclusão de um retorno após a votação. O retorno
pode ser com as estatísticas de votações atuais ou simplesmente com uma mensagem
50
como: “Programação escolhida com sucesso”, “Voto aceito com sucesso”, etc
(PREECE; ROGERS; SHARP, 2002, p. 21).
Depois de fechadas as escolhas de aplicações, deve ser enviado um sinal para os
usuários. O sinal deve afirmar que as escolhas foram encerradas e que uma das
programações foi a vencedora, essa é outra maneira de se obter feedback da aplicação.
Depois de definidos os requisitos iniciais, é necessário verificar a viabilidade do
aplicativo. Isso é realizado no próximo item.
5.3 Desenvolvimento de Protótipo
A etapa de desenvolvimento de protótipo é muito utilizada em diversos projetos de
software. Para que o usuário final tenha conhecimento de como será o aplicativo final os
desenvolvedores costumam fazer protótipos da aplicação final, mesmo que sem
funcionalidades muito avançadas. A etapa de desenvolvimento de protótipo é muito
importante no estudo da IHC por tornar possível a visualização de uma possível interface para
o sistema. De maneira similar, é possível criar o protótipo da interação. Mesmo que o
protótipo não tenha sido implementado, é possível alcançar o efeito do protótipo desenhando
a interface e a interação. (PREECE; ROGERS; SHARP, 2002).
A Figura 12 mostra um protótipo da interface da aplicação de escolha de programação
interativa:
51
Figura 12 – Protótipo de aplicação de enquetes de filmes implementada em Java TV
Esse protótipo da aplicação corrige algumas falhas no exemplo de enquete do capítulo
4, para isso se utiliza apenas de RadioButtons, sem o botão “Votar”, nesse caso o
telespectador precisaria apenas mover as setas do controle remoto para cima ou para baixo
para escolher a programação, sendo que a opção marcada também seria a programação a
aparecer do lado direito da tela. A área de preview é formada pela imagem ampliada do item
selecionado à esquerda e por uma área de texto preenchida com a sinopse do item
selecionado.
A utilização de traillers não foi possível devido a uma incapacidade do XleTView para
reproduzir vídeos controlados a partir de Xlets. (MONTEZ; PICCIONI, 2004)
5.4 Desenvolvimento de Aplicativo
Depois de desenvolvido o protótipo e analisada a viabilidade da aplicação, foi possível
desenvolver o aplicativo final. A Figura 13 apresenta o diagrama de casos de uso da aplicação
projetada. Os casos de uso do diagrama podem ser resumidamente descritos como:
52
Votar em Filme: participando da votação o telespectador seleciona e confirma
o voto para algum filme.
Comentar Filme: depois de eleger um filme o telespectador tem a possibilidade
de comentar sobre a votação.
Ver Comentários: possibilita ao telespectador o acesso à tela de visualização de
comentários para os filmes em votação.
Ver Resultados da Votação: possibilita ao telespectador visualizar o resultado
parcial da votação.
Abandonar Votação: possibilita ao telespectador o abandono da votação antes
ou depois de eleger algum filme.
Figura 13 – Diagrama UML de Casos de Uso para aplicação de votação de filmes.
A Figura 14 apresenta o diagrama de classes para a aplicação desenvolvida.
53
Figura 14 – Diagrama de Classes para aplicação de votação de filmes.
A aplicação desenvolvida é dividida em duas partes. A primeira das partes é
representada pelo Xlet implementado para a escolha de filmes. A segunda parte é uma
aplicação que simula o comportamento de uma aplicação em execução na emissora. O sistema
como um todo é simulado da seguinte maneira: as informações sobre os filmes disponíveis
para votação são requisitados à emissora pela aplicação quando os usuários acessam a
votação. Ao votarem, os dados das votações são enviados para a emissora a partir do
XleTView, que simula um STB que possui uma conexão com a internet, e então a parte da
aplicação da emissora armazena os dados em um banco de dados. Em algum momento
posterior, quando o telespectador desejar consultar os resultados da votação ou os últimos
comentários sobre os filmes, os dados devem ser solicitados novamente pela aplicação
executada sobre o XleTVIew para a emissora, que então retorna as informações atualizadas.
A parte da aplicação que é um Xlet determina a interação com o telespectador. A partir
da interface o usuário possui meios de participar ou abandonar uma votação, eleger um filme,
justificar uma escolha através do controle remoto do XleTView que foi adaptado, consultar os
resultados da votação e consultar os últimos comentários sobre os filmes. A comunicação
entre as duas partes da aplicação divide o sistema e propicia uma interatividade mais intensa e
um feedback maior para o telespectador, simulando o canal de retorno.
54
A utilização de canal de retorno é possível em ambientes reais de televisão digital se o
STB estiver conectado a uma internet banda larga. Dessa característica nasceu a definição de
Internet Protocol Television (IPTV). A IPTV possibilita através da internet maior
interatividade para o telespectador que pode então personalizar a programação que deseja ver
na televisão. (SOFTV INTERACTIVE, 2007).
A simulação de canal de retorno foi implementada através da interface entre as classes
ControladorDeAcessoExterno e ProcessadorDeVotos exibida no diagrama da Figura 14. A
classe ControladorDeAcessoExterno pertence ao subsistema Set-Top Box modelado com a
classe EscolhaDeFilmesXlet e possibilita através da utilização de sockets fornecidos na API
do Java o contato com a classe ProcessadorDeVotos do subsistema externo, que seria a
Emissora. No diagrama, o subsistema externo é representado pela classe ProcessadorDeVotos
em conjunto com VotacaoFilmesDAO.
O canal de retorno é utilizado pela aplicação em quatro circunstâncias: quando o
telespectador acessa a tela de votação, durante a votação de um filme, durante a visualização
de resultados e quando o telespectador buscar os comentários de outras pessoas sobre os
filmes da votação. Quando o telespectador acessa a tela de votação, o Xlet abre uma conexão
com a emissora e requisita as informações dos filmes disponíveis para votação. Nessa tela, os
filmes são exibidos e ficam disponíveis para serem votados. A partir desse ponto, o
telespectador pode selecionar um filme e o eleger, fazendo com que a aplicação abra uma
conexão com a emissora e envie as informações relacionadas ao voto. Durante a visualização
de resultados o acesso externo também é necessário, o que faz com que o Xlet solicite os
resultados parciais da votação para exibi-los para o telespectador com gráficos. Ao visualizar
os comentários, a conexão é novamente aberta para obtenção dos cinco últimos comentários.
Embora as informações dos filmes estejam sendo enviadas pela emissora, não foi
possível, pelo menos no tempo disponível para conclusão desse trabalho, enviar as imagens
relacionadas aos filmes via socket. Para que um objeto possa ser enviado via socket, sua
classe deve implementar a interface Serializable. Está sendo utilizada a classe Image do
pacote java.awt, que não implementa Serializable. Para contornar esse problema, a emissora
envia apenas o nome do arquivo de imagem. As imagens são montadas então na instância da
classe Votacao. Essa solução não deixa o sistema tão preparado para a estrutura real, onde as
imagens deveriam chegar da emissora e não estarem armazenadas previamente no STB.
55
O Xlet também trata os dados para exibi-los de uma maneira mais intuitiva para o
usuário, informando inclusive se a votação já foi iniciada ou concluída. Além disso, foi
inserida a funcionalidade de a aplicação emitir som ao navegar pelo menu do aplicativo,
durante a seleção do filme a votar e ao confirmar o voto, com o objetivo de garantir uma
forma eficiente de feedback ao telespectador e melhorar a IHC da aplicação.
Para que a emissora tenha armazenadas as informações de filmes, votações e usuários
que votaram, foi utilizado um banco de dados, contendo as seguintes tabelas:
filme;
usuario;
voto.
A tabela filme armazena as informações dos filmes que podem ser escolhidos pela
emissora para serem elegíveis aos telespectadores. Contém as seguintes colunas:
codigo: armazena uma identificação única do filme em uma variável inteira;
nome: armazena o nome do filme em um campo de texto com até cinqüenta
caracteres;
descricao: armazena a sinopse do filme em um campo de texto com até dois
mil caracteres;
arquivoImagem: armazena o nome do arquivo de imagem que é exibido na tela
de votação;
arquivoCartaz: armazena o nome do arquivo de imagem que é exibido ao lado
da opção na tela de votação;
nomeGenero: armazena o gênero do filme em um campo de texto com até
cinqüenta caracteres.
A tabela usuario armazena informações de cada telespectador que participa da
votação. Contém as seguintes colunas:
código: armazena uma identificação do usuário em uma variável inteira;
56
nome: armazena o nome do usuário em um campo de texto com até cinqüenta
caracteres.
A tabela voto armazena as votações realizadas e contém as seguintes colunas:
codigoUsuario: armazena em um inteiro o código do telespectador relacionado
com a tabela usuario;
codigo: armazena o código do filme votado;
comentario: armazena o comentário deixado pelo telespectador.
Os códigos-fonte da aplicação encontram-se no Apêndice A.
5.5 Funcionamento do Aplicativo
O ProcessadorDeVotos simula parte do sistema da emissora e é iniciado antes da
aplicação. Nesse momento, é necessário escolher os três filmes candidatos à eleição dos
telespectadores. As informações desses filmes já devem estar previamente armazenadas em
banco de dados.
A classe EscolherFilmesXlet implementa o Xlet e, portanto, uma instância é carregada
pelo STB iniciando a aplicação. Neste ponto foi tomado o cuidado de não interromper
visualmente a programação a que o telespectador está assistindo, mas sim apenas avisá-lo
sobre a disponibilidade do sistema de votação e permitir o acesso a esse sistema. Para isso,
EscolherFilmesXlet instancia um objeto da classe ContainerInicial que tem a única função de
exibir a mensagem “Pressione ‘AZUL’ para acessar a votação de filmes.”. Essa mensagem é
posicionada na parte superior da tela, deixando grande parte da área da programação da
emissora visível ao telespectador. A Figura 15 exibe o início da aplicação.
57
Figura 15 – Início da aplicação
Pressionada a tecla azul do controle remoto, a aplicação é redirecionada para uma
instância da classe Menu, apresentando um menu, que é exibido na Figura 16. A partir desse
menu, é possível navegar entre quatro opções: “Votar em um filme”, “Resultados parciais”,
“Comentários” e “Sair”. A navegação é feita através das teclas das setas para cima e para
baixo do controle remoto. Para permitir um feedback visual ao telespectador, a opção
selecionada aparece com uma cor opaca, enquanto a cor das demais opções possui uma certa
transparência. Ao desenvolver esse menu, também preocupou-se em manter boa parte da área
visual da programação disponível ao telespectador, já que não se faz necessário a ocupação de
toda a tela para exibição das opções.
58
Figura 16 – Menu da aplicação
A opção “Votar em um filme” redireciona a aplicação à tela de votação,
disponibilizada pela instância da classe Votacao. Nesse momento, é feita uma chamada ao
ControladorDeAcessoExterno, que faz uma requisição dos filmes disponíveis para votação
via socket à emissora através do ProcessadorDeVotos. O ProcessadorDeVotos recebe os
filmes pelo VotacaoFilmesDAO, que realiza a busca dos filmes no banco de dados. Ao
receber as informações dos filmes, Votacao organiza as informações na tela, conforme a
Figura 17.
59
Figura 17 – Tela de votação
Os filmes podem ser selecionados pelas teclas das setas para cima e para baixo do
controle remoto. Da mesma forma que no menu, é possível diferenciar visualmente a opção
selecionada. Além disso, para cada opção selecionada são exibidas uma imagem do filme e
sua sinopse. Ao pressionar o botão “OK” do controle remoto, o telespectador vota no filme
selecionado e no canto esquerdo da tela é exibida uma área de texto, fornecendo a opção da
justificativa do voto através do controle remoto. A figura 18 exibe a visualização da tela nesse
momento.
60
Figura 18 – Filme selecionado
Para permitir a inserção de texto via controle remoto, foi implementado um
ProcessadorDeTeclas, cujo serviço utilizado pela Votacao fornece ao telespectador interação
idêntica a de digitação de texto a partir de um celular. Ao digitar a tecla “OK” novamente, a
justificativa é finalizada e a aplicação é redirecionada para uma tela de confirmação.
Na tela de confirmação, uma instância de ConfirmacaoVoto apresenta uma pergunta se
realmente deseja-se votar no filme, o nome do filme e as opções “Sim” e “Não”. A opção
“Não” cancela a votação do filme escolhido e redireciona a aplicação para a tela de menu.
Caso seja escolhida a opção “Sim”, é feita uma chamada ao ControladorDeAcessoExterno,
que envia as informações do voto definitivo ao ProcessadorDeVotos que, por sua vez,
armazena no banco de dados através do VotacaoFilmesDAO. Nesse momento, é enviado um
sinal sonoro ao telespectador, confirmando a votação. A tela de confirmação é ilustrada na
Figura 19.
61
Figura 19 – Tela de confirmação do voto
A opção do menu “Resultados parciais” redireciona a aplicação à tela de resultados.
Essa tela é apresentada pela instância Resultados, que chama o ControladorDeAcessoExterno
para obter as quantidades de votações para cada filme. O ControladorDeAcessoExterno
solicita essas informações ao ProcessadorDeVotos, que busca no banco de dados com o
auxílio do VotacaoFilmesDAO. Com as informações das quantidades das votações,
Resultados calcula a porcentagem das votações dos filmes e as exibe na tela. A tecla “OK” do
controle remoto é usada para retornar ao menu. É possível visualizar essa tela na Figura 20.
62
Figura 20 – Tela de resultados parciais da votação
A opção “Comentários” redireciona a aplicação a uma tela apresentada por uma
instância de Comentarios. Nesse ponto, o ControladorDeAcessoExterno é chamado para obter
os cinco últimos comentários registrados na emissora por uma requisição ao
ProcessadorDeVotos. Após a requisição, o ProcessadorDeVotos busca os comentários no
banco pelo VotacaoFilmesDAO e responde ao ControladorDeAcessoExterno que, por sua
vez, repassa a informação à Comentarios. A tela de comentários é exibida na Figura 21.
63
Figura 21 – Tela de comentários
A opção “Sair” do menu principal tem a função de retornar a aplicação à tela inicial,
aonde o telespectador tem a visão da programação.
64
6 CONCLUSÃO
O desenvolvimento deste trabalho como um todo abrangeu algumas áreas de
conhecimento bastante relacionadas, entre elas, estavam: a Televisão Digital, a API Java TV
utilizada com a linguagem Java, os componentes de interface HAVi e a Interatividade, que é
muito relacionada com a Interação Humano-Computador.
Os capítulos iniciais possibilitaram o entendimento das vantagens de se utilizar a
Televisão Digital, substituindo então a Televisão Analógica. Assim, os maiores benefícios são
a melhor qualidade de imagem e a interatividade, viabilizada através de um canal de retorno
onde o telespectador pode transmitir suas preferências.
A interatividade, obtida a partir da Televisão Digital, foi observada e com o auxílio da
área de Interação Humano-Computador foram alcançadas idéias de como poderiam ser
desenvolvidas aplicações para obter aceitação dos telespectadores. No desenvolvimento de
aplicações foi utilizada a API Java TV através do emulador XleTView, que apesar de
limitado, possibilitou simulações de como é uma aplicação sendo executada em um ambiente
de TV Digital. A partir das simulações foi possível observar algumas limitações de interface,
o que impacta na interatividade, mas que podem ser contornadas.
Recentemente a Sun Microsystems criou uma especificação de API similar a API Java
TV, chamada Java DTV. O Java DTV foi criado especificamente para a utilização no
SBTVD, com isso, o Java DTV passa a receber maior foco em pesquisas no Brasil. Uma
vantagem do Java DTV é que possui elementos utilizados no Java TV, como Xlets,
fornecendo assim algum conhecimento para os que já possuem experiência em Java TV.
Por ser um software livre, pesquisas sobre o XleTView e seu funcionamento podem
auxiliar no entendimento e desenvolvimento de emuladores de middleware para TV Digital,
isso é um grande benefício para o aprendizado. O estudo para a criação de um emulador para
baseado no Java DTV, apesar de bastante desafiador, é uma pesquisa interessante.
65
REFERÊNCIAS
FERNANDES, Jorge; LEMOS, Guido; SILVEIRA, Gledson. Introdução à Televisão Digital
Interativa: Arquitetura, Protocolos, Padrões e Práticas. In: CONGRESSO DA SOCIEDADE
BRASILEIRA DE COMPUTAÇÃO, 24., 2004, Salvador. Anais: Jornada de atualização em
informática. Salvador, 2004. Disponível em: <
http://www.cic.unb.br/~jhcf/MyBooks/itvdi/slides-
jai2004/IntroducaoATelevisaoDigitalInterativa_dia1.pdf>. Acesso em: 08 ago. 2008.
HAVI. The HAVi Specification. Disponível em:
<http://www.havi.org/techinfo/docs/Chapter8-HAVi1.1-May15.pdf>. Acesso em: 28 mai.
2009.
HOLZINGER, Andreas. Usability Engineering Methods for Software Developers.
Communications of the ACM. Volume 48, Nº 1. 2005.
HU, Osvaldo Ramos Tsan; RAUNHEITTE, Luís Tadeu Mendes. Processamento de Imagens:
Aplicações e Problemas. in: HU, Osvaldo Ramos Tsan. Processamento e Compressão Digital
de Imagens. São Paulo: Editora Mackenzie, 2004. p. 230-236.
LAUESEN, Soren. User Interface Design: A Software Engineering Perspective. Addison-
Wesley, 2005.
MONTEZ, Carlos; BECKER, Valdecir. TV Digital Interativa: conceitos, desafios e
perspectivas para o Brasil. 2. ed. Florianópolis: Editora da UFSC, 2005. 2ª edição.
Disponível em: <http://www.itvproducoesinterativas.com.br/pdfs/TV-Digita-
Interativa_2a_EDICAO.pdf>. Acesso em: 03/10/2008.
MONTEZ, Carlos; BECKER, Valdecir. TV Digital Interativa: Conceitos e Tecnologias.
Disponível em: <http://www.itvproducoesinterativas.com.br/pdfs/A-TV-Digital-Interativa-
Conceitos-Tecnologias.pdf>. Acesso em 12/03/2009.
MORRIS, Steven; SMITH-CHAIGNEAU, Anthony. Interactive TV Standards. Editora
Focal Press, 2005.
66
MORRIS, Steven. An Introduction to Xlets. Disponível em:
<http://www.interactivetvweb.org/tutorials/javatv/xlet_intro>. Acesso em: 27/05/2009.
MONTEZ, Carlos; PICCIONI, Carlos. Um Estudo sobre Emuladores de Aplicações para a
Televisão Digital Interativa. Universidade Federal de Santa Catarina, Florianópolis, 2004.
PAWLAN, Monica. Introduction to Digital TVApplications Programming. Sun
Microsystems. fev/2001. Acesso em:
<http://java.sun.com/developer/technicalArticles/javatv/apiintro/>. Disponível em: 28 mai.
2009.
PREECE, Jennifer; ROGERS, Yvonne; SHARP, Helen. Interaction Design: Beyond Human –
Computer Interaction. John Wiley & Sons, Inc; 2002.
SHNEIDERMAN, Ben. Designing the User Interface: Strategies for Effective Human-
Computer Interaction. 3.ed. Addison Wesley Longman.1998.
SILVA, Elton J. Sistemas Interativos: Introdução. Material da Disciplina Sistemas Interativos
do curso de Ciência da Computação na Universidade Federal de Ouro Preto. Disponível em:
<http://www.decom.ufop.brprofeltoncic261cap1.pdf>. Acesso em: 07 jun. 2008.
SOFTV INTERACTIVE. O que é IPTV. Disponível em: <http://www.softv.com.br>. Acesso
em: 28 abr. 2008.
SUN Microsystems, Disponível em:
<http://java.sun.com/javame/technology/javatv/overview.html>. Acesso em: 29/05/2009.
TORRES, Gabriel. Tudo sobre HDTV. Clube do Hardware, São Paulo, 20 abr. 2005.
Disponível em <http://www.clubedohardware.com.br/artigos/1011>. Acesso em: 06 set. 2008.
YAMADA, Fujio et al. Revista Mackenzie de Engenharia e Computação, São Paulo, Ano 5,
n. 5, 2004. Disponível em: <http://www.mackenzie.br/ano5_num5_2004.html>. Acesso em:
29 set. 2008.
67
APÊNDICE A
O conteúdo deste apêndice é o código-fonte da aplicação proposta desenvolvida em Java com
o apoio da API Java TV. Os códigos estão divididos em dois pacotes: aplicação e
emissora.aplicacao.
Pacote aplicação
68
AjustaComponentes.java
package aplicacao;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Rectangle;
/* Classe responsável por configurar parâmetros comuns dos componentes GUI
*/
public class AjustaComponentes {
public AjustaComponentes() {
}
public Component ajustaComponente(Component c, Color foreground, Color
background, Rectangle position, Font fonte) {
c.setForeground( foreground );
c.setBackground( background );
c.setBounds( position );
c.setFont( fonte );
c.setVisible( true );
return c;
}
}
69
Botao.java
package aplicacao;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import org.havi.ui.HTextButton;
import org.havi.ui.event.HFocusEvent;
/** Classe especializada de HTextButton, utilizada para definir botões
padrão na GUI. */
public class Botao extends HTextButton {
private String texto; // Define o conteúdo de um botão.
private int x, y,
largura,
altura,
arcWidth,
arcHeight;
private boolean selecionado;
private Color foregroundPressionado,
foregroundNaoPressionado,
backgroundPressionado,
backgroundNaoPressionado;
public Botao() {
super();
}
70
public Botao(String texto, int x, int y, int largura, int altura, Color
foregroundNaoPressionado, Color foregroundPressionado, Color
backgroundNaoPressionado, Color backgroundPressionado, int arcWidth, int
arcHeight) {
super(texto, x, y, largura, altura);
this.texto = texto;
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.arcWidth = arcWidth;
this.arcHeight = arcHeight;
this.foregroundPressionado = foregroundPressionado;
this.foregroundNaoPressionado = foregroundNaoPressionado;
this.backgroundPressionado = backgroundPressionado;
this.backgroundNaoPressionado = backgroundNaoPressionado;
this.setEnabled(true);
}
public Botao(String texto, Color foregroundNaoPressionado, Color
foregroundPressionado, Color backgroundNaoPressionado, Color
backgroundPressionado, int arcWidth, int arcHeight) {
super(texto);
this.texto = texto;
this.foregroundPressionado = foregroundPressionado;
this.foregroundNaoPressionado = foregroundNaoPressionado;
this.largura = Botao.WIDTH;
this.altura = Botao.HEIGHT;
this.arcWidth = arcWidth;
this.arcHeight = arcHeight;
this.backgroundPressionado = backgroundPressionado;
this.backgroundNaoPressionado = backgroundNaoPressionado;
this.setEnabled(true);
}
71
@Override
public void paint(Graphics g) {
Color corBackground, corForeground;
if (selecionado) {
corBackground = this.backgroundPressionado;
corForeground = this.foregroundPressionado;
} else {
corBackground = this.backgroundNaoPressionado;
corForeground = this.foregroundNaoPressionado;
}
g.setColor(corBackground);
g.fillRoundRect(0, 0, largura, altura, arcWidth, arcHeight); //
arredonda os cantos do retângulo
//desenha o label no centro do botão
Font f = getFont();
if (f != null) {
FontMetrics fm = getFontMetrics(getFont());
g.setColor(corForeground);
g.drawString(texto, largura / 2 - fm.stringWidth(texto) / 2,
altura / 2 + fm.getHeight() / 2 - fm.getMaxDescent());
}
}
@Override
public void processHFocusEvent(HFocusEvent evento) {
super.processHFocusEvent(evento);
if (evento.getID() == HFocusEvent.FOCUS_GAINED) {
this.selecionado = true;
repaint();
} else if (evento.getID() == HFocusEvent.FOCUS_LOST) {
this.selecionado = false;
repaint();
}
}
}
72
Comentarios.java
package aplicacao;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.TextArea;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HScene;
import org.havi.ui.event.HRcEvent;
import org.havi.ui.HStaticText;
/** Classe que define uma janela para exibição de comentários dos
telespectadores.
* Utiliza o controladores de acesso externo para acessar obter as
informacoes da emissora.
*/
class Comentarios extends HContainer implements KeyListener {
private int x, y, largura, altura;
private int numeroComentarios = 5;
private HScene cenario;
private Menu menu;
private HStaticText tituloComentarios;
private TextArea[] areaComentarios;
private Color tituloBackgroundColor, tituloForegroundColor;
private Font fonteTitulo;
private Font fonteObservacao;
private AjustaComponentes ajustador;
private String[] comentarios;
73
public Comentarios(int x, int y, int largura, int altura, HScene
cenario, Menu menu) {
super(x, y, largura, altura);
System.out.println("Tela de Comentarios.");
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.cenario = cenario;
this.menu = menu;
this.comentarios = new String[numeroComentarios];
this.areaComentarios = new TextArea[numeroComentarios];
ajustador = new AjustaComponentes();
this.tituloBackgroundColor = new DVBColor(255, 255, 255, 100);
this.tituloForegroundColor = DVBColor.BLACK;
this.fonteTitulo = new Font("Verdana", Font.BOLD, 40);
this.fonteObservacao = new Font("Verdana", Font.BOLD, 30);
tituloComentarios = (HStaticText) ajustador.
ajustaComponente(new HStaticText( "Comentarios" ),
tituloForegroundColor,
tituloBackgroundColor,
new Rectangle(10, 10, largura - 100, 60),
fonteTitulo);
this.add( tituloComentarios );
// Obtendo os cinco últimos comentários
System.out.println("Utilizando o controlador de acesso externo.");
74
ControladorDeAcessoExterno acessoExterno = new
ControladorDeAcessoExterno();
comentarios = acessoExterno.getComentarios();
int scrollBarsNone = TextArea.SCROLLBARS_NONE;
for(int i = 0, j = 0; i < numeroComentarios; i++) {
System.out.println("Comentario[" + i + "]: " + comentarios[i]);
if(!comentarios[i].equals("vazio")) {
areaComentarios[i] = new TextArea( comentarios[i], 10, 20,
scrollBarsNone );
areaComentarios[i].setBackground( Color.LIGHT_GRAY );
areaComentarios[i].setForeground( Color.BLACK );
areaComentarios[i].setBounds( 50, 80 * j + 80, 600, 60);
areaComentarios[i].requestFocusInWindow();
areaComentarios[i].setFocusable(false);
this.add(areaComentarios[i]);
j++;
}
}
HStaticText aviso = new HStaticText( "Clique em OK para voltar ao
Menu." );
ajustador.ajustaComponente( aviso, Color.WHITE, Color.BLACK,
new Rectangle(10, altura - 100, largura - 100, 60),
fonteObservacao); // Janela vai de [10, largura-100] na horizontal.
this.add( aviso );
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
75
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
if( e.getKeyChar() == HRcEvent.VK_ENTER ) {
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(this.menu);
this.cenario.add(this.menu);
this.cenario.repaint();
this.menu.setVisible(true);
this.menu.transferFocus();
} else if(e.getKeyChar() == HRcEvent.VK_ESCAPE) {
// Tecla EXIT pressionada
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(this.menu);
this.cenario.add(this.menu);
this.cenario.repaint();
this.menu.setVisible(true);
this.menu.transferFocus();
}
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
76
Confirmação.java
package aplicacao;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HScene;
import org.havi.ui.event.HRcEvent;
/**
* Classe utilizada para exibir uma janela de confirmação após voto.
*/
class Confirmacao extends HContainer implements KeyListener {
private HScene cenario;
private Votacao votacao;
private int x, y, largura, altura;
private int alpha = 200;
private Filme filme;
private Image imagem;
private MediaTracker tracker;
public Confirmacao(int x, int y, int largura, int altura, HScene
cenario, Votacao votacao, Filme filme) {
super(x, y, largura, altura);
System.out.println("Confirmacao inicializada.");
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.votacao = votacao;
this.cenario = cenario;
this.filme = filme;
tracker = new MediaTracker(this);
imagem = filme.getImagem();
tracker.addImage(imagem, 0);
}
77
@Override
public void paint(Graphics graphics) {
try {
graphics.setColor(new DVBColor(100, 100, 100, alpha));
graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
super.paint(graphics);
if (imagem != null) {
graphics.drawImage(imagem, 10, 10, 700, 560, null);
}
} catch(Exception e) {
e.printStackTrace();
}
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
if(e.getKeyChar() == HRcEvent.VK_ENTER) {
// Tecla ENTER pressionada
}
else if(e.getKeyChar() == HRcEvent.VK_ESCAPE) {
// Tecla EXIT pressionada
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(votacao);
this.cenario.add(votacao);
this.cenario.repaint();
this.votacao.setVisible(true);
this.votacao.transferFocus();
}
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
78
ConfirmacaoVoto.java
package aplicacao;
import java.awt.Color;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HScene;
import org.havi.ui.HSound;
import org.havi.ui.HStaticText;
import org.havi.ui.HTextButton;
import org.havi.ui.event.HRcEvent;
/**
* Classe que confirma os votos e os envia para a emissora através da
* classe ControladorDeAcessoExterno.
*/
public class ConfirmacaoVoto extends HContainer implements KeyListener {
private int x, y, largura, altura, larguraBotao, alturaBotao;
private HScene cenario;
private Votacao votacao;
private Menu menu;
private HTextButton botaoConfirmar, botaoRecusar;
private String textoConfirmar;
private String textoRecusar;
private String questao;
private String nomeFilme, comentario;
private Color corForegroundNaoPressionado;
private Color corForegroundPressionado;
private Color corBackgroundNaoPressionado;
private Color corBackgroundPressionado;
private AjustaComponentes ajustador;
private HSound somTecla, somVotado;
private String somURLTecla, somURLVotado;
private HStaticText mensagemConfirmacao;
79
public ConfirmacaoVoto (int x, int y, int largura, int altura, HScene
cenario, Menu menu, Votacao votacao, String nomeFilme, String comentario) {
super(x, y, largura, altura);
System.out.println("Menu inicializado.");
this.menu = menu;
this.votacao = votacao;
this.questao = "Deseja mesmo votar no filme: " + nomeFilme + "?";
this.nomeFilme = nomeFilme;
this.comentario = comentario;
this.textoConfirmar = "Sim";
this.textoRecusar = "Não";
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.cenario = cenario;
larguraBotao = 150;
alturaBotao = 30;
corForegroundNaoPressionado = DVBColor.WHITE;
corForegroundPressionado = DVBColor.YELLOW;
corBackgroundNaoPressionado = new DVBColor(0, 100, 255, 100);
corBackgroundPressionado = new DVBColor(0, 100, 255, 255);
int arcWidth = 25;
int arcHeight = 25;
ajustador = new AjustaComponentes();
HStaticText questaoConfirmacao = new HStaticText( questao );
ajustador.ajustaComponente(questaoConfirmacao, DVBColor.BLACK, new
DVBColor(255, 255, 255, 150), new Rectangle(10, 10, 400, 30), new
Font("Verdana", Font.BOLD, 16));
this.add( questaoConfirmacao );
botaoConfirmar = new Botao(textoConfirmar, 10, 20 + 30,
larguraBotao, alturaBotao, corForegroundNaoPressionado,
80
corForegroundPressionado, corBackgroundNaoPressionado,
corBackgroundPressionado, arcWidth, arcHeight);
this.add( botaoConfirmar );
botaoRecusar = new Botao(textoRecusar, 10, 60 + 30, larguraBotao,
alturaBotao, corForegroundNaoPressionado, corForegroundPressionado,
corBackgroundNaoPressionado, corBackgroundPressionado, arcWidth,
arcHeight);
this.add( botaoRecusar );
botaoConfirmar.setFocusTraversal(botaoRecusar, botaoRecusar,
botaoRecusar, botaoRecusar);
botaoConfirmar.addKeyListener( this );
botaoRecusar.setFocusTraversal( botaoConfirmar, botaoConfirmar,
botaoConfirmar, botaoConfirmar);
botaoRecusar.addKeyListener( this );
botaoRecusar.requestFocus();
this.somTecla = null;
this.somURLTecla = "file://E://Sons//Slider.wav";
this.somVotado = null;
this.somURLVotado = "file://E://Sons//startup_20.wav";
this.somTecla = new HSound();
this.somVotado = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
ControleDeSom.preparaSom(somVotado, somURLVotado);
}
/**
* Utiliza o Controlador de Acesso Externo para enviar o voto para a
emissora
* Devolve uma mensagem que é exibida ao usuário, podendo ser
* "Voto Computado" ou "Votacao já foi encerrada"
* @return confirmacao
*/
public String confirmar(){
System.out.println("Utilizando o controlador de acesso externo.");
ControladorDeAcessoExterno acessoExterno = new
ControladorDeAcessoExterno();
81
String confirmacao = acessoExterno.votar(nomeFilme, comentario);
return confirmacao;
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Realiza chamada a confirmacao de voto. Permitindo exibir a resposta
no
* menu que é a próxima janela a receber foco.
* @param e
*/
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
if(e.getKeyChar() == HRcEvent.VK_ENTER) {
if(e.getSource() == botaoConfirmar) {
System.out.println("botaoConfirmar Pressionado.");
this.somVotado.play();
// Obtem da emissora mensagem de confirmação de voto.
String mensagem = confirmar();
while (menu.getComponentCount() != 4) {
menu.remove(menu.getComponentCount() - 1);
}
mensagemConfirmacao = new HStaticText(mensagem);
mensagemConfirmacao = (HStaticText)
ajustador.ajustaComponente(mensagemConfirmacao, Color.WHITE, Color.BLACK,
new Rectangle(10, menu.getHeight() - 50,
menu.getWidth() - 10, 30), new Font("Verdana", Font.BOLD, 16));
this.cenario.removeKeyListener( this );
this.cenario.remove( this );
this.cenario.addKeyListener( menu );
menu.add(mensagemConfirmacao);
menu.repaint();
82
this.cenario.add( menu );
this.cenario.repaint();
this.menu.setVisible( true );
this.cenario.transferFocus();
}
else if(e.getSource() == botaoRecusar) {
System.out.println("botaoRecusar Pressionado.");
this.cenario.removeKeyListener( this );
this.cenario.remove( this );
this.votacao.restart();
this.cenario.addKeyListener( votacao );
this.cenario.add( votacao );
this.cenario.repaint();
this.votacao.setVisible( true );
this.cenario.transferFocus();
}
}
else if(e.getKeyChar() == HRcEvent.VK_UP || e.getKeyChar() ==
HRcEvent.VK_DOWN) {
this.somTecla.play();
}
this.somTecla = new HSound();
this.somVotado = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
ControleDeSom.preparaSom(somVotado, somURLVotado);
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
83
ContainerInicial.java
package aplicacao;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HDefaultTextLayoutManager;
import org.havi.ui.HScene;
import org.havi.ui.HStaticText;
/**
* Classe que permite acessar uma votação.
*/
class ContainerInicial extends HContainer {
private HScene cenario;
// Parâmetros para a mensagem de acessar a votação
private String acessarVotacaoString;
private HStaticText acessarVotacaoLabel;
private Color backgroundColor;
private Color foregroundColor;
private Font fonte;
public ContainerInicial(int x, int y, int largura, int altura, HScene
cenario) {
super(x, y, largura, altura);
this.cenario = cenario;
// Configurando parâmetros do texto:
this.acessarVotacaoString = "Pressione \"AZUL\" para acessar a
votação de filmes.";
this.backgroundColor = new DVBColor(255, 255, 255, 100);
this.foregroundColor = DVBColor.BLACK;
this.fonte = new Font("Verdana", Font.BOLD, 22);
acessarVotacaoLabel = new HStaticText(this.acessarVotacaoString);
84
acessarVotacaoLabel.setTextLayoutManager(new
HDefaultTextLayoutManager());
acessarVotacaoLabel.setBackground(this.backgroundColor);
acessarVotacaoLabel.setForeground(this.foregroundColor);
acessarVotacaoLabel.setFont(this.fonte);
this.setLayout(new BorderLayout());
this.add(acessarVotacaoLabel, BorderLayout.CENTER);
}
}
85
ControladorDeAcessoExterno.java
package aplicacao;
import java.net.*;
import java.io.*;
/**
* Classe responsável por abrir conexões e gerenciar dados entrada e saída
* das conexões.
*/
public class ControladorDeAcessoExterno {
private Socket clientSocket;
private String provedor;
private int porta;
private int numeroFilmes = 3;
private int numeroComentarios = 5;
/**
* Configura os parametros de localização da emissora.
*/
public ControladorDeAcessoExterno() {
clientSocket = null;
provedor = "localhost";
porta = 9995;
}
/**
* Realiza a conexão com a emissora e retorna o socket para a
aplicação.
* @return clientsocket
*/
public Socket conecta() {
try {
clientSocket = new Socket( provedor, porta );
System.out.println( "Conectado" );
} catch (UnknownHostException unknownHostException) {
unknownHostException.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
86
return clientSocket;
}
/**
* Desconecta-se da emissora.
*/
public boolean desconecta() {
try {
if (!clientSocket.isClosed()) {
clientSocket.close();
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
return clientSocket.isClosed();
}
/**
* Método chamado para efetivar o voto, recebe o nome do filme
escolhido
* e um comentário que pode ser vazio.
* @param nomeFilme
* @param comentario
* @return
*/
public String votar(String nomeFilme, String comentario) {
this.conecta();
if (clientSocket != null) {
try {
ObjectOutputStream oos = new ObjectOutputStream(
clientSocket.getOutputStream() );
ObjectInputStream ois = new ObjectInputStream(
clientSocket.getInputStream() );
oos.writeObject( "Votacao" );
oos.writeObject( nomeFilme );
oos.writeObject( comentario );
String mensagem = (String) ois.readObject();
System.out.print(mensagem);
this.desconecta();
return mensagem;
} catch (IOException ioe) {
87
ioe.printStackTrace();
} catch (ClassCastException cce) {
cce.printStackTrace();
} catch (ClassNotFoundException cnf) {
cnf.printStackTrace();
}
}
return "Sem conexão";
}
/**
* Obtem um vetor de filmes da emissora utilizando o Controlador de
Acesso
* Externo.
* @return filmes
*/
public Filme[] getFilmes() {
this.conecta();
Filme[] filmes;
filmes = new Filme[numeroFilmes];
if (clientSocket != null) {
try {
ObjectOutputStream oos = new ObjectOutputStream(
clientSocket.getOutputStream() );
ObjectInputStream ois = new ObjectInputStream(
clientSocket.getInputStream() );
oos.writeObject( "Filmes" );
for(int i = 0; i < numeroFilmes; i++) {
filmes[i] = (Filme) ois.readObject();
}
this.desconecta();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
return filmes;
}
88
/**
* Obtem os votos dos telespectadores da emissora
* utilizando o Controlador de Acesso Externo.
* @return
*/
public Integer[] getVotos() {
this.conecta();
Integer[] votos;
votos = new Integer[numeroFilmes];
if (clientSocket != null) {
try {
ObjectOutputStream oos = new ObjectOutputStream(
clientSocket.getOutputStream() );
ObjectInputStream ois = new ObjectInputStream(
clientSocket.getInputStream() );
oos.writeObject( "Resultados" );
for(int i = 0; i < numeroFilmes; i++) {
votos[i] = (Integer) ois.readObject();
}
this.desconecta();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
return votos;
}
/**
* Obtem os comentarios do telespectador a partir da emissora
utilizando
* o Controlador de Acesso Externo.
* @return
*/
public String[] getComentarios() {
this.conecta();
String[] comentarios;
comentarios = new String[numeroComentarios];
if (clientSocket != null) {
89
try {
ObjectOutputStream oos = new ObjectOutputStream(
clientSocket.getOutputStream() );
ObjectInputStream ois = new ObjectInputStream(
clientSocket.getInputStream() );
oos.writeObject( "Comentarios" );
for(int i = 0; i < numeroComentarios; i++) {
comentarios[i] = (String) ois.readObject();
}
this.desconecta();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
}
return comentarios;
}
}
90
ControleDeSom.java
package aplicacao;
import org.havi.ui.HSound;
/**
* Classe responsável por emitir sons a medida que eventos de GUI ocorrem.
*/
public class ControleDeSom {
public static void preparaSom(HSound som, String somURL) {
try {
som.dispose();
som.load(somURL);
}
catch (Exception e){
e.printStackTrace();
System.out.println("Arquivo nao encontrado!");
}
}
}
91
EscolherFilmesXlet.java
package aplicacao;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import org.havi.ui.HScene;
import org.havi.ui.HSceneFactory;
import org.havi.ui.HScreen;
import org.havi.ui.HSound;
import org.havi.ui.event.HRcEvent;
import xjavax.tv.xlet.Xlet;
import xjavax.tv.xlet.XletContext;
import xjavax.tv.xlet.XletStateChangeException;
/**
* Xlet que representa a aplicação.
*/
public class EscolherFilmesXlet implements Xlet, KeyListener {
private XletContext contexto;
private HScene cenario;
private ContainerInicial containerInicial;
private Menu menu;
private Dimension dimensao;
private Point ponto;
private int larguraDaCena;
private int alturaDaCena;
private HSound somTecla;
private String somURLTecla;
/**
* Método responsável por inicializar o Xlet após seu carregamento.
* O parâmetro XletContext permite a obtenção de dados do ambiente de
execução.
* @param context
* @throws xjavax.tv.xlet.XletStateChangeException
*/
public void initXlet(XletContext context) throws
XletStateChangeException {
92
System.out.println("Executando initXlet.");
/* Um XletContext é usado pelo Xlet para acessar propriedades
associadas com o seu runtime environment.
*/
this.contexto = context;
// Dimensão usada para o tamanho da cena:
this.larguraDaCena = 800;
this.alturaDaCena = 600;
this.dimensao = new Dimension(larguraDaCena, alturaDaCena);
// Ponto usado para a localização da cena:
int localizacaoDaCenaX = 0;
int localizacaoDaCenaY = 0;
this.ponto = new Point(localizacaoDaCenaX, localizacaoDaCenaY);
this.somTecla = null;
this.somURLTecla = "file://E://Sons//Slider.wav";
containerInicial = new ContainerInicial(50, 20, 600, 40, cenario);
}
/**
* Método responsável por colocar o Xlet no estado ativo.
* @throws xjavax.tv.xlet.XletStateChangeException
*/
public void startXlet() throws XletStateChangeException {
System.out.println("Executando startXlet.");
// Criando nova instância para a cena:
HSceneFactory fabricaCena = HSceneFactory.getInstance();
cenario =
fabricaCena.getFullScreenScene(HScreen.getDefaultHScreen().getDefaultHGraph
icsDevice());
cenario.setSize(this.dimensao);
cenario.setLocation(this.ponto);
cenario.addKeyListener(this);
cenario.add(containerInicial);
cenario.validate();
93
cenario.setVisible(true);
cenario.requestFocus();
somTecla = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
}
public void pauseXlet() {
System.out.println("Executando pauseXlet.");
}
public void destroyXlet(boolean arg0) throws XletStateChangeException {
System.out.println("Executando destroyXlet.");
if(cenario != null) {
cenario.setVisible(false);
cenario.removeAll();
cenario = null;
}
contexto.notifyDestroyed();
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
switch(e.getKeyChar()) {
case HRcEvent.VK_COLORED_KEY_3:
// Tecla AZUL pressionada
this.somTecla.play();
this.cenario.removeKeyListener(this);
this.cenario.remove(containerInicial);
this.menu = new Menu(10, 10, larguraDaCena - 530,
alturaDaCena - 330, cenario, containerInicial, this);
this.cenario.addKeyListener(menu);
this.cenario.add(menu);
this.cenario.repaint();
this.menu.setVisible(true);
this.menu.transferFocus();
94
break;
default:
System.out.println("Tecla desconhecida.");
// Outra tecla pressionada
}
somTecla = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
public int getLargura() {
return this.larguraDaCena;
}
public int getAltura() {
return this.alturaDaCena;
}
}
95
Filme.java
package aplicacao;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.Serializable;
/**
* Classe responsável por representar uma entidade do tipo Filme.
*/
public class Filme implements Serializable {
private String nome;
private String nomeDoArquivoDeImagem;
private String nomeDoArquivoDeCartaz;
private Image cartaz;
private Image imagem;
private String sinopse;
public Filme(String nome, String cartaz, String imagem, String sinopse)
{
this.nome = nome;
this.sinopse = "Sinopse: " + nome + "\n" + "\n" + sinopse;
this.nomeDoArquivoDeImagem = imagem;
this.nomeDoArquivoDeCartaz = cartaz;
//criaCartaz(cartaz);
//criaImagem(imagem);
}
public void criaImagem(String nomeDoArquivo) {
imagem = Toolkit.getDefaultToolkit().getImage(nomeDoArquivo);
}
public void criaCartaz(String nomeDoArquivo) {
cartaz = Toolkit.getDefaultToolkit().getImage(nomeDoArquivo);
}
public String getNome() {
return this.nome;
}
96
public String getNomeDoArquivoDeImagem() {
return this.nomeDoArquivoDeImagem;
}
public String getNomeDoArquivoDeCartaz() {
return this.nomeDoArquivoDeCartaz;
}
public Image getCartaz() {
return this.cartaz;
}
public Image getImagem() {
return this.imagem;
}
public String getSinopse() {
return this.sinopse;
}
}
97
Menu.java
package aplicacao;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HScene;
import org.havi.ui.HSound;
import org.havi.ui.event.HRcEvent;
/**
* Classe que possibilita a navegação entre outras classes do tipo
HContainer.
* Dentre as possíveis opções estão: Votacao, Resultados e Comentarios.
*/
public class Menu extends HContainer implements KeyListener {
private HScene cenario;
private HContainer inicio;
private EscolherFilmesXlet xlet;
private Votacao votacao;
private Resultados resultados;
private Comentarios comentarios;
private int x, y, largura, altura, larguraBotao, alturaBotao;
private Botao botaoVotar, botaoResultados, botaoComentarios, botaoSair;
private String textoVotar = "Votar em um filme";
private String textoResultados = "Resultados parciais";
private String textoComentarios = "Comentários";
private String textoSair = "Sair";
private Color corForegroundNaoPressionado;
private Color corForegroundPressionado;
private Color corBackgroundNaoPressionado;
private Color corBackgroundPressionado;
private HSound somTecla;
private String somURLTecla;
private AjustaComponentes ajustador;
98
/**
* Instancia um menu e configura os itens disponíveis.
* @param x
* @param y
* @param largura
* @param altura
* @param cenario
* @param inicio
* @param xlet
*/
public Menu(int x, int y, int largura, int altura, HScene cenario,
HContainer inicio, EscolherFilmesXlet xlet) {
super(x, y, largura, altura);
System.out.println("Menu inicializado.");
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.cenario = cenario;
this.inicio = inicio;
this.xlet = xlet;
ajustador = new AjustaComponentes();
larguraBotao = 150;
alturaBotao = 30;
int posicaoInicialXBotao = (this.largura / 2) - (larguraBotao / 2);
corForegroundNaoPressionado = DVBColor.WHITE;
corForegroundPressionado = DVBColor.YELLOW;
corBackgroundNaoPressionado = new DVBColor(0, 100, 255, 100);
corBackgroundPressionado = new DVBColor(0, 100, 255, 255);
int arcWidth = 25;
int arcHeight = 25;
botaoVotar = new Botao(textoVotar, posicaoInicialXBotao, 10,
larguraBotao, alturaBotao, corForegroundNaoPressionado,
99
corForegroundPressionado, corBackgroundNaoPressionado,
corBackgroundPressionado, arcWidth, arcHeight);
this.add(botaoVotar);
botaoResultados = new Botao(textoResultados, posicaoInicialXBotao,
50, larguraBotao, alturaBotao, corForegroundNaoPressionado,
corForegroundPressionado, corBackgroundNaoPressionado,
corBackgroundPressionado, arcWidth, arcHeight);
this.add(botaoResultados);
botaoComentarios = new Botao(textoComentarios,
posicaoInicialXBotao, 90, larguraBotao, alturaBotao,
corForegroundNaoPressionado, corForegroundPressionado,
corBackgroundNaoPressionado, corBackgroundPressionado, arcWidth,
arcHeight);
this.add(botaoComentarios);
botaoSair = new Botao(textoSair, posicaoInicialXBotao, 130,
larguraBotao, alturaBotao, corForegroundNaoPressionado,
corForegroundPressionado, corBackgroundNaoPressionado,
corBackgroundPressionado, arcWidth, arcHeight);
this.add(botaoSair);
botaoVotar.setFocusTraversal(botaoSair, botaoResultados, null,
null);
botaoVotar.addKeyListener(this);
botaoResultados.setFocusTraversal(botaoVotar, botaoComentarios,
null, null);
botaoResultados.addKeyListener(this);
botaoComentarios.setFocusTraversal(botaoResultados, botaoSair,
null, null);
botaoComentarios.addKeyListener(this);
botaoSair.setFocusTraversal(botaoComentarios, botaoVotar, null,
null);
botaoSair.addKeyListener(this);
botaoVotar.requestFocus();
100
this.somTecla = null;
this.somURLTecla = "file://E://Sons//Slider.wav";
this.somTecla = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
}
@Override
public void paint(Graphics g) {
g.setColor(new DVBColor(100, 100, 100, 100));
g.fillRect(0, 0, this.getWidth(), this.getHeight());
super.paint(g);
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Recebe o evento de entrada por controle remoto e trata de acordo
* com as opções disponíveis no menu.
* @param e
*/
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
if(e.getKeyChar() == HRcEvent.VK_ENTER) {
if(e.getSource() == botaoVotar) {
System.out.println("botaoVotar Pressionado.");
this.cenario.removeKeyListener( this );
this.cenario.remove( this );
this.votacao = new Votacao(0, 0, xlet.getLargura(),
xlet.getAltura(), cenario, this);
this.cenario.addKeyListener( votacao );
this.cenario.add( votacao );
this.cenario.repaint();
this.votacao.setVisible(true);
this.cenario.transferFocus();
}
else if(e.getSource() == botaoResultados) {
System.out.println("botaoResultados Pressionado.");
this.cenario.removeKeyListener( this );
this.cenario.remove( this );
101
this.resultados = new Resultados (0, 0, xlet.getLargura(),
xlet.getAltura(), cenario, this);
this.cenario.addKeyListener( resultados );
this.cenario.add( resultados );
this.cenario.repaint();
this.resultados.setVisible( true );
this.cenario.transferFocus();
}
else if(e.getSource() == botaoComentarios) {
System.out.println("botaoComentarios Pressionado.");
this.cenario.removeKeyListener( this );
this.cenario.remove( this );
this.comentarios = new Comentarios (0, 0,
xlet.getLargura(), xlet.getAltura(), cenario, this);
this.cenario.addKeyListener( comentarios );
this.cenario.add( comentarios );
this.cenario.repaint();
this.comentarios.setVisible( true );
this.cenario.requestFocus();
}
else if(e.getSource() == botaoSair) {
System.out.println("botaoSair Pressionado.");
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(xlet);
this.cenario.add(inicio);
this.cenario.repaint();
this.inicio.setVisible(true);
this.cenario.requestFocus();
}
}
else if(e.getKeyChar() == HRcEvent.VK_ESCAPE) {
// Tecla ENTER pressionada
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(xlet);
this.cenario.add(inicio);
this.cenario.repaint();
this.inicio.setVisible(true);
this.cenario.requestFocus();
}
102
else if(e.getKeyChar() == HRcEvent.VK_UP || e.getKeyChar() ==
HRcEvent.VK_DOWN) {
this.somTecla.play();
}
this.somTecla = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
103
ProcessadorDeTeclas.java
package aplicacao;
import java.util.Date;
/**
* Classe responsável por tratamento diferenciado das teclas do controle
remoto,
* simula um teclado de celular.
*/
public class ProcessadorDeTeclas {
private char charWithCode48[] = {'\u0000', '0'};
private char charWithCode49[] = {'.', ',', '!', '?', '1', '@', '%',
'$', ';', ':'};
private char charWithCode50[] = {'a', 'b', 'c', '2', 'A', 'B', 'C'};
private char charWithCode51[] = {'d', 'e', 'f', '3', 'D', 'E', 'F'};
private char charWithCode52[] = {'g', 'h', 'i', '4', 'G', 'H', 'I'};
private char charWithCode53[] = {'j', 'k', 'l', '5', 'J', 'K', 'L'};
private char charWithCode54[] = {'m', 'n', 'o', '6', 'M', 'N', 'O'};
private char charWithCode55[] = {'p', 'q', 'r', 's', '7', 'P', 'Q',
'R', 'S'};
private char charWithCode56[] = {'t', 'u', 'v', '8', 'T', 'U', 'V'};
private char charWithCode57[] = {'w', 'x', 'y', 'z', '9', 'w', 'x',
'y', 'z'};
private Date tempoAtual;
private Date tempoInicio;
private int indexCode;
private int lasCode;
private boolean mesmaTecla;
private StringBuffer texto;
private char ultimoCaractere;
public ProcessadorDeTeclas() {
tempoAtual = new Date();
tempoInicio = new Date();
}
/**
104
* Recebe o texto atual no buffer, o ultimo caractere digitado, o
codigo atual
* e o ultimo codigo, com base nisso gera uma alteração no buffer. Essa
classe
* é utilizada para tratamento de eventos quando a caixa de texto para
comentarios
* está disponível.
* @param lastCode
* @param code
* @param texto
* @param ultimoCaractere
* @return
*/
public StringBuffer trataTeclaPressionada(int lastCode, int code,
StringBuffer texto, char ultimoCaractere) {
this.lasCode = lastCode;
this.texto = texto;
this.ultimoCaractere = ultimoCaractere;
long diferenca = 0; // armazenará a diferença de tempo entre as
teclas pressionadas
tempoAtual.setTime(new Date().getTime());
diferenca = tempoAtual.getTime() - tempoInicio.getTime();
mesmaTecla = (lastCode == code);
if ((diferenca <= 3 * 1000) && (lastCode != 0)) { // Se a diferenca
de tempo for menor que ou igual a 3 segundos e o último codigo nao foi 0
(não iniciado) sobrescreve ultimo caractere
switch (code) {
case 151:
if (mesmaTecla) { // se mesmaTecla, sobrescreve, senão
não
} else {
texto.append(ultimoCaractere);
ultimoCaractere = '*';
}
break;
case 520:
if (mesmaTecla) {
} else {
texto.append(ultimoCaractere);
ultimoCaractere = '#';
}
105
break;
case 27:
if (mesmaTecla) {
} else {
texto.append(ultimoCaractere);
ultimoCaractere = '-';
}
break;
case 428:
if (mesmaTecla) {
} else {
texto.append(ultimoCaractere);
ultimoCaractere = '-';
}
break;
case 427:
if (mesmaTecla) {
} else {
texto.append(ultimoCaractere);
ultimoCaractere = '+';
}
break;
case 37:
if (mesmaTecla) {
texto.deleteCharAt(texto.length() - 1);
ultimoCaractere = '\u0000';
} else {
texto.deleteCharAt(texto.length() - 1);
ultimoCaractere = '\u0000';
}
break;
case 38:
if (mesmaTecla) {
} else {
texto.append(ultimoCaractere);
ultimoCaractere = '^';
}
break;
case 39:
if (mesmaTecla) {
} else {
106
texto.append(ultimoCaractere);
ultimoCaractere = '>';
}
break;
case 40:
if (mesmaTecla) {
} else {
texto.append(ultimoCaractere);
ultimoCaractere = 'v';
}
break;
case 48:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode48.length) ?
0 : indexCode; // evita ArrayIndexOutOfBoundsException
ultimoCaractere = charWithCode48[indexCode];
texto.deleteCharAt(texto.length() - 1);
if (ultimoCaractere == '\u0000') {
texto.append(" ");
} else {
texto.append("0");
}
} else {
indexCode = 0;
ultimoCaractere = charWithCode48[indexCode];
texto.append(" "); // " " aqui representa '/u0000'.
}
break;
case 49:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode49.length) ?
0 : indexCode; // evita ArrayIndexOutOfBoundsException
ultimoCaractere = charWithCode49[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
107
ultimoCaractere = charWithCode49[indexCode];
texto.append(ultimoCaractere);
}
break;
case 50:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode50.length) ?
0 : indexCode; // evita ArrayIndexOutOfBoundsException
ultimoCaractere = charWithCode50[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode50[indexCode];
texto.append(ultimoCaractere);
}
break;
case 51:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode51.length) ?
0 : indexCode;
ultimoCaractere = charWithCode51[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode51[indexCode];
texto.append(ultimoCaractere);
}
break;
case 52:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode52.length) ?
0 : indexCode;
108
ultimoCaractere = charWithCode52[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode52[indexCode];
texto.append(ultimoCaractere);
}
break;
case 53:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode53.length) ?
0 : indexCode;
ultimoCaractere = charWithCode53[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode53[indexCode];
texto.append(ultimoCaractere);
}
break;
case 54:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode54.length) ?
0 : indexCode;
ultimoCaractere = charWithCode54[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode54[indexCode];
texto.append(ultimoCaractere);
}
break;
case 55:
if (mesmaTecla) {
109
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode55.length) ?
0 : indexCode;
ultimoCaractere = charWithCode55[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode55[indexCode];
texto.append(ultimoCaractere);
}
break;
case 56:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode56.length) ?
0 : indexCode;
ultimoCaractere = charWithCode56[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode56[indexCode];
texto.append(ultimoCaractere);
}
break;
case 57:
if (mesmaTecla) {
System.out.println("Mesma tecla");
indexCode++;
indexCode = (indexCode == charWithCode57.length) ?
0 : indexCode;
ultimoCaractere = charWithCode57[indexCode];
texto.deleteCharAt(texto.length() - 1);
texto.append(ultimoCaractere);
} else {
indexCode = 0;
ultimoCaractere = charWithCode57[indexCode];
texto.append(ultimoCaractere);
110
}
break;
case 403:
ultimoCaractere = 'r';
break;
case 404:
ultimoCaractere = 'g';
break;
case 405:
ultimoCaractere = 'y';
break;
case 406:
ultimoCaractere = 'b';
break;
case 10:
ultimoCaractere = 'e';
break;
default:
ultimoCaractere = 'o';
}
} else {
System.out.println("Irei gerar um novo caracter");
tempoInicio.setTime(new Date().getTime()); // Atualiza a hora
de que uma tecla foi digitada para
// um novo caractere.
lastCode = code;
indexCode = 0;
switch (code) {
case 151:
ultimoCaractere = '*';
texto.append(ultimoCaractere);
break;
case 520:
ultimoCaractere = '#';
texto.append(ultimoCaractere);
break;
case 27:
ultimoCaractere = 'e';
texto.append(ultimoCaractere);
break;
111
case 428:
ultimoCaractere = '-';
texto.append(ultimoCaractere);
break;
case 427:
ultimoCaractere = '+';
texto.append(ultimoCaractere);
break;
case 37:
texto.deleteCharAt(texto.length() - 1);
ultimoCaractere = '\u0000';
break;
case 38:
ultimoCaractere = '^';
texto.append(ultimoCaractere);
break;
case 39:
ultimoCaractere = '>';
texto.append(ultimoCaractere);
break;
case 40:
ultimoCaractere = 'v';
texto.append(ultimoCaractere);
break;
case 48:
indexCode = 0;
ultimoCaractere = charWithCode48[indexCode];
texto.append(" "); // " " aqui representa '/u0000'.
break;
case 49:
ultimoCaractere = charWithCode49[indexCode];
texto.append(ultimoCaractere);
break;
case 50:
ultimoCaractere = charWithCode50[indexCode];
texto.append(ultimoCaractere);
break;
case 51:
ultimoCaractere = charWithCode51[indexCode];
texto.append(ultimoCaractere);
break;
112
case 52:
ultimoCaractere = charWithCode52[indexCode];
texto.append(ultimoCaractere);
break;
case 53:
ultimoCaractere = charWithCode53[indexCode];
texto.append(ultimoCaractere);
break;
case 54:
ultimoCaractere = charWithCode54[indexCode];
texto.append(ultimoCaractere);
break;
case 55:
ultimoCaractere = charWithCode55[indexCode];
texto.append(ultimoCaractere);
break;
case 56:
ultimoCaractere = charWithCode56[indexCode];
texto.append(ultimoCaractere);
break;
case 57:
ultimoCaractere = charWithCode57[indexCode];
texto.append(ultimoCaractere);
break;
case 403:
ultimoCaractere = 'r';
texto.append(ultimoCaractere);
break;
case 404:
ultimoCaractere = 'g';
texto.append(ultimoCaractere);
break;
case 405:
ultimoCaractere = 'y';
texto.append(ultimoCaractere);
break;
case 406:
texto.append(ultimoCaractere);
ultimoCaractere = 'b';
break;
case 10:
113
texto.append(ultimoCaractere);
ultimoCaractere = 'e';
break;
default:
texto.append(ultimoCaractere);
ultimoCaractere = 'o';
}
}
return texto;
}
public Date getTempoInicio() {
return this.tempoInicio;
}
public Date getTempoAtual() {
return this.tempoAtual;
}
public char getUltimoCaractere() {
return this.ultimoCaractere;
}
public int getLastCode() {
return this.lasCode;
}
}
114
Resultados.java
package aplicacao;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HScene;
import org.havi.ui.HTextButton;
import org.havi.ui.event.HRcEvent;
import org.havi.ui.HStaticText;
import java.text.DecimalFormat;
/**
* Classe responsável por exibir os resultados da votação.
* Utiliza o Controlador de Acesso Externo para recolher a informação da
emissora.
*/
class Resultados extends HContainer implements KeyListener {
private int x, y, largura, altura;
private HScene cenario;
private Menu menu;
private Filme[] filmes;
private HStaticText tituloResultados;
private Color tituloBackgroundColor, tituloForegroundColor;
private Font fonteTitulo;
private Font fonteFilmes;
private Font fonteObservacao;
private HTextButton botaoVoltar;
private AjustaComponentes ajustador;
private int numeroFilmes = 3;
115
private String nomeFilmes[];
/**
* Instancia a janela de resultados exibindo os nomes dos filmes da
votação
* e os resultados parciais.
* @param x
* @param y
* @param largura
* @param altura
* @param cenario
* @param menu
*/
public Resultados(int x, int y, int largura, int altura, HScene
cenario, Menu menu) {
super(x, y, largura, altura);
System.out.println("Tela de Resultados Parciais.");
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.cenario = cenario;
this.menu = menu;
this.nomeFilmes = new String[numeroFilmes];
ajustador = new AjustaComponentes();
/* Aqui pode ser criado um método configuraFonte */
this.tituloBackgroundColor = new DVBColor(255, 255, 255, 100);
this.tituloForegroundColor = DVBColor.BLACK;
this.fonteTitulo = new Font("Verdana", Font.BOLD, 40);
this.fonteObservacao = new Font("Verdana", Font.BOLD, 30);
this.fonteFilmes = new Font("Verdana", Font.BOLD, 20);
/* Aqui pode ser criado um método configuraComponente */
tituloResultados = new HStaticText( "Resultados Parciais" );
tituloResultados.setBounds(10, 10, largura - 100, 60); // Janela
vai de [10, largura-100] na horizontal.
tituloResultados.setVisible( true );
tituloResultados.setForeground( tituloForegroundColor );
116
tituloResultados.setBackground( tituloBackgroundColor );
tituloResultados.setFont( fonteTitulo );
this.add( tituloResultados );
HStaticText[] filmesVotacao = new HStaticText [nomeFilmes.length];
DecimalFormat df = new DecimalFormat("#,###.00");
/* Supondo que os números abaixo foram os recebidos da emissora em
um dado momento */
Float[] votos = new Float[3];
// Obtendo os filmes
System.out.println("Utilizando o controlador de acesso externo.");
ControladorDeAcessoExterno acessoExterno = new
ControladorDeAcessoExterno();
filmes = acessoExterno.getFilmes();
// Obtendo resultados
System.out.println("Utilizando o controlador de acesso externo.");
int totalVotos = 0;
Integer[] votosRecebidos;
votosRecebidos = acessoExterno.getVotos();
for(int i = 0; i < numeroFilmes; i++) {
totalVotos = totalVotos + votosRecebidos[i];
}
Float totalVotosf = new Integer(totalVotos).floatValue();
for(int i = 0; i < numeroFilmes; i++) {
nomeFilmes[i] = filmes[i].getNome();
votos[i] = new Integer(votosRecebidos[i]).floatValue() /
totalVotosf * 10;
}
System.out.println(votos[0] + " " + votos[1] + " " + votos[2] + " =
" + (votos[0] + votos[1] + votos[2]));
/* Imprime os nomes dos filmes da votação */
for (int i = 0; i < nomeFilmes.length; i++) {
filmesVotacao[i] = new HStaticText( nomeFilmes[i] );
117
filmesVotacao[i].setFont( fonteFilmes );
filmesVotacao[i].setBounds(10, 80 + (altura / 4) * i, largura /
3, 60); // Janela vai de [10, largura-100] na horizontal.
filmesVotacao[i].setVisible( true );
filmesVotacao[i].setForeground( tituloForegroundColor );
filmesVotacao[i].setBackground( tituloBackgroundColor );
this.add( filmesVotacao[i] );
}
Color[] coresBarra = new Color[3];
coresBarra[0] = Color.ORANGE;
coresBarra[1] = Color.ORANGE;
coresBarra[2] = Color.ORANGE;
setCoresBarras(coresBarra, votos);
HStaticText[] porcentagensVotacao = new
HStaticText[nomeFilmes.length];
for (int i = 0; i < votos.length; i++) {
porcentagensVotacao[i] = new HStaticText( df.format(votos[i] *
10 ) + "%" );
porcentagensVotacao[i] = (HStaticText)
ajustador.ajustaComponente(porcentagensVotacao[i],
Color.BLACK,coresBarra[i],
new Rectangle(10, 140 + (altura / 4) * i, (int)
((largura / 3) * (votos[i] / 10)), 30), null);
this.add( porcentagensVotacao[i] );
}
botaoVoltar = new HTextButton( "Clique em OK para voltar ao Menu."
);
botaoVoltar.addKeyListener( this );
HStaticText aviso = new HStaticText( "Clique em OK para voltar ao
Menu." );
ajustador.ajustaComponente( aviso, Color.WHITE, Color.BLACK,
new Rectangle(10, altura - 100, largura - 100, 60),
fonteObservacao); // Janela vai de [10, largura-100] na horizontal.
this.add( aviso );
this.add( botaoVoltar );
118
}
public void setCoresBarras(Color[] cores, Float[] porcentagens) {
int indiceMaior;
int indiceMenor;
int indiceMedio;
indiceMenor = indiceMedio = indiceMaior = 0;
for (int i = 1; i < porcentagens.length; i++) {
if (porcentagens[indiceMaior].compareTo(porcentagens[i]) < 0) {
indiceMaior = i;
}
if (porcentagens[indiceMaior].compareTo(porcentagens[i]) > 0) {
indiceMenor = i;
}
}
cores[indiceMaior] = Color.GREEN;
cores[indiceMenor] = Color.RED;
}
@Override
public void paint(Graphics graphics) {
System.out.println("Metodo paint() de Resultados: " +
graphics.toString());
super.paint( graphics );
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
if( e.getKeyChar() == HRcEvent.VK_ENTER ) {
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(this.menu);
this.cenario.add(this.menu);
119
this.cenario.repaint();
this.menu.setVisible(true);
this.menu.transferFocus();
} else if(e.getKeyChar() == HRcEvent.VK_ESCAPE) {
// Tecla EXIT pressionada
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(this.menu);
this.cenario.add(this.menu);
this.cenario.repaint();
this.menu.setVisible(true);
this.menu.transferFocus();
}
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
120
Votacao.java
package aplicacao;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.TextArea;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Date;
import org.dvb.ui.DVBColor;
import org.havi.ui.HContainer;
import org.havi.ui.HScene;
import org.havi.ui.HSound;
import org.havi.ui.event.HRcEvent;
/**
* Classe responsável por exibir os filmes da votação e suas sinopses.
* Permite também a votação.
*/
class Votacao extends HContainer implements KeyListener {
private HScene cenario;
private Menu menu;
private ConfirmacaoVoto confirmacao;
private Filme[] filmes;
private Filme eleito;
private Image[] cartazes;
private Image imagemCentral;
private Botao[] botaoFilmes;
private MediaTracker tracker;
private TextArea sinopse, comentario;
private String textoFixo;
private StringBuffer texto;
private char ultimoCaractere;
private int alpha = 200;
private int numeroFilmes = 3;
private int campo;
private int alturaDaImagem;
121
private int larguraDaImagem;
private int indexCode;
private int lastCode;
private int x, y, largura, altura;
private boolean filmeVotado = false;
private boolean votoComentado;
private Dimension size;
private Color corForegroundNaoPressionado;
private Color corForegroundPressionado;
private Color corBackgroundNaoPressionado;
private Color corBackgroundPressionado;
private HSound somTecla;
private String somURLTecla;
private ProcessadorDeTeclas processadorDeTeclas;
public Votacao(int x, int y, int largura, int altura, HScene cenario,
Menu menu) {
super(x, y, largura, altura);
System.out.println("Votacao inicializada.");
this.x = x;
this.y = y;
this.largura = largura;
this.altura = altura;
this.menu = menu;
this.cenario = cenario;
this.texto = new StringBuffer();
processadorDeTeclas = new ProcessadorDeTeclas();
tracker = new MediaTracker(this);
// Get the size of this component so that we can clear it properly.
size = getSize();
campo = (int) (size.getHeight() / numeroFilmes) - 10;
alturaDaImagem = (int) campo - 10;
larguraDaImagem = (int) (alturaDaImagem * 0.66);
corForegroundNaoPressionado = DVBColor.WHITE;
corForegroundPressionado = DVBColor.BLACK;
corBackgroundNaoPressionado = new DVBColor(0, 255, 100, 150);
122
corBackgroundPressionado = new DVBColor(0, 255, 0, 255);
int arcWidth = 50;
int arcHeight = 50;
// Obtendo os filmes
System.out.println("Utilizando o controlador de acesso externo.");
ControladorDeAcessoExterno acessoExterno = new
ControladorDeAcessoExterno();
filmes = acessoExterno.getFilmes();
cartazes = new Image[numeroFilmes];
for (int i = 0; i < numeroFilmes; i++) {
System.out.println("NomeDoArquivoDeCartaz: " +
filmes[i].getNomeDoArquivoDeCartaz());
filmes[i].criaCartaz(filmes[i].getNomeDoArquivoDeCartaz());
filmes[i].criaImagem(filmes[i].getNomeDoArquivoDeImagem());
cartazes[i] = filmes[i].getCartaz();
tracker.addImage(cartazes[i], i);
}
eleito = null;
botaoFilmes = new Botao[numeroFilmes];
for (int i = 0; i < numeroFilmes; i++) {
botaoFilmes[i] = new Botao(new Integer(i + 1).toString(), 20,
(campo * i) + 60, 40, alturaDaImagem - 120, corForegroundNaoPressionado,
corForegroundPressionado, corBackgroundNaoPressionado,
corBackgroundPressionado, arcWidth, arcHeight);
this.add(botaoFilmes[i]);
}
for (int i = 0; i < numeroFilmes; i++) {
botaoFilmes[i].setFocusTraversal((i == 0) ?
botaoFilmes[numeroFilmes - 1] : botaoFilmes[i - 1], (i == numeroFilmes - 1)
? botaoFilmes[0] : botaoFilmes[i + 1], null, null);
botaoFilmes[i].addKeyListener(this);
}
botaoFilmes[0].requestFocus();
this.escolheFilme(0);
try {
123
tracker.waitForAll();
} catch (InterruptedException e) {
for (int i = 0; i < 3; i++) {
cartazes[i] = null;
}
System.out.println("InterruptedException e: " +
e.getMessage());
}
this.somTecla = null;
this.somURLTecla = "file://E://Sons//Slider.wav";
this.somTecla = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
}
@Override
public void paint(Graphics graphics) {
try {
graphics.setColor(new DVBColor(100, 100, 100, alpha));
graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
super.paint(graphics);
if (cartazes != null) {
for (int i = 0; i < numeroFilmes; i++) {
graphics.drawImage(cartazes[i], 80, (campo * i) + 10,
larguraDaImagem, alturaDaImagem, null);
}
}
if (imagemCentral != null) {
graphics.drawImage(imagemCentral, larguraDaImagem + 100,
10, 490, (campo * 2) - 10, null);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void escolheFilme(int id) {
System.out.println("botaoFilmes[" + id + "] Selecionado.");
if (sinopse != null) {
124
this.remove(sinopse);
}
if (imagemCentral != null) {
tracker.removeImage(imagemCentral, numeroFilmes, 490, campo -
10);
}
imagemCentral = filmes[id].getImagem();
tracker.addImage(imagemCentral, numeroFilmes);
repaint();
sinopse = new TextArea(filmes[id].getSinopse(), 0, 0,
TextArea.SCROLLBARS_NONE);
sinopse.setBackground(Color.LIGHT_GRAY);
sinopse.setForeground(Color.BLACK);
sinopse.setBounds(larguraDaImagem + 100, (campo * 2) + 10, 490,
campo - 10);
sinopse.requestFocusInWindow();
sinopse.setFocusable(false);
this.add(sinopse);
}
/**
* Inicializa componente GUI para fornecimento de comentários.
*/
public void initComentario() {
textoFixo = "Justifique seu voto (opcional) e/ou clique OK para
finalizar: \n";
int scrollBarsNone = TextArea.SCROLLBARS_NONE;
comentario = new TextArea(textoFixo + texto.toString(), 10, 20,
scrollBarsNone);
comentario.setBackground(Color.LIGHT_GRAY);
comentario.setForeground(Color.BLACK);
comentario.setBounds(10, campo + 10, larguraDaImagem + 80,
alturaDaImagem * 2 + 10);
botaoFilmes[0].setVisible(false);
botaoFilmes[1].setVisible(false);
botaoFilmes[2].setVisible(false);
if (cartazes[0] != null) {
125
tracker.removeImage(cartazes[0], 0, larguraDaImagem,
alturaDaImagem);
}
cartazes[0] = eleito.getCartaz();
tracker.addImage(cartazes[0], 0);
repaint();
this.add(comentario);
}
public void removeComentario() {
this.remove(comentario);
this.add(botaoFilmes[1]);
this.add(botaoFilmes[2]);
}
public void keyTyped(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Realiza o voto a partir do evento obtido ou possibilita a entrada
* de comentários.
* @param e
*/
public void keyPressed(KeyEvent e) {
System.out.println(this.getClass() + ": Tecla Pressionada.");
if (e.getKeyChar() == HRcEvent.VK_ENTER) {
if (filmeVotado == true) {
if (!votoComentado) {
votoComentado = true;
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
confirmacao = new ConfirmacaoVoto(0, 0, this.largura,
this.altura, cenario, this.menu, this, eleito.getNome(), texto.toString());
this.cenario.addKeyListener(confirmacao);
this.cenario.add(confirmacao);
this.cenario.repaint();
confirmacao.setVisible(true);
this.cenario.transferFocus();
126
} else {
System.out.println("Voto já foi efetuado e
comentado.");
}
} else {
filmeVotado = true;
texto = new StringBuffer("");
ultimoCaractere = '\u0000';
int idFilmeVotado = 0;
if (e.getSource() == botaoFilmes[0]) {
idFilmeVotado = 0;
} else if (e.getSource() == botaoFilmes[1]) {
idFilmeVotado = 1;
} else if (e.getSource() == botaoFilmes[2]) {
idFilmeVotado = 2;
}
eleito = filmes[idFilmeVotado];
System.out.println("botaoFilmes[" + idFilmeVotado + "]
Votado.");
System.out.println("Filme: " + eleito.getNome());
botaoFilmes[0].requestFocus();
this.initComentario();
}
} else if (e.getKeyChar() == HRcEvent.VK_ESCAPE) {
// Tecla EXIT pressionada
this.cenario.removeKeyListener(this);
this.cenario.remove(this);
this.cenario.addKeyListener(menu);
this.cenario.add(menu);
this.cenario.repaint();
this.menu.setVisible(true);
this.menu.transferFocus();
} else if (e.getKeyChar() == HRcEvent.VK_UP && !filmeVotado) {
// Tecla UP
this.somTecla.play();
int idFilme = 0;
if (e.getSource() == botaoFilmes[0]) {
idFilme = 2;
127
} else if (e.getSource() == botaoFilmes[1]) {
idFilme = 0;
} else if (e.getSource() == botaoFilmes[2]) {
idFilme = 1;
}
this.escolheFilme(idFilme);
} else if (e.getKeyChar() == HRcEvent.VK_DOWN && !filmeVotado) {
// Tecla DOWN
this.somTecla.play();
int idFilme = 0;
if (e.getSource() == botaoFilmes[0]) {
idFilme = 1;
} else if (e.getSource() == botaoFilmes[1]) {
idFilme = 2;
} else if (e.getSource() == botaoFilmes[2]) {
idFilme = 0;
}
this.escolheFilme(idFilme);
} else {
// Qualquer outra tecla foi pressionada
// Se o filme já foi votado, a tecla é tratada como texto de
comentario.
if (filmeVotado) {
int code = e.getKeyCode();
texto = processadorDeTeclas.trataTeclaPressionada(lastCode,
code, texto, ultimoCaractere);
Date tempoInicio = processadorDeTeclas.getTempoInicio();
Date tempoAtual = processadorDeTeclas.getTempoAtual();
ultimoCaractere = processadorDeTeclas.getUltimoCaractere();
lastCode = processadorDeTeclas.getLastCode();
comentario.setText(null); // Limpa a tela e reescreve como
está no StringBuffer
System.out.println("TempoAtual apos alteracao: " +
tempoAtual.getTime());
System.out.println("TempoInicio apos alteracao: " +
tempoInicio.getTime());
long diferenca = tempoAtual.getTime() -
tempoInicio.getTime();
System.out.println("Diferenca apos alteracao: " +
diferenca);
128
System.out.println("StringBuffer texto: " +
texto.toString());
if (ultimoCaractere == '\u0000' && texto.length() == 0) {
texto.append(textoFixo + "");
} else {
comentario.append(textoFixo + texto.toString());
}
lastCode = code;
}
}
this.somTecla = new HSound();
ControleDeSom.preparaSom(somTecla, somURLTecla);
}
public void keyReleased(KeyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
void restart() {
this.votoComentado = false;
this.filmeVotado = false;
this.botaoFilmes[0].requestFocus();
if (cartazes[0] != null) {
tracker.removeImage(cartazes[0], 0, larguraDaImagem,
alturaDaImagem);
}
cartazes[0] = filmes[0].getCartaz();
tracker.addImage(cartazes[0], 0);
this.escolheFilme(0);
this.botaoFilmes[0].setVisible(true);
this.botaoFilmes[1].setVisible(true);
this.botaoFilmes[2].setVisible(true);
removeComentario();
}
}
129
Pacote emissora.aplicacao
130
ProcessadorDeVotos.java
package emissora.aplicacao;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.*;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import aplicacao.Filme;
/**
* Classe responsável por processar votos recebidos da Xlet.
* Não apenas votos, mas também consultas de resultados e comentários.
*/
public class ProcessadorDeVotos {
static boolean votacaoEncerrada = false;
public static void main(String[] args) {
ControleVotacao controleVotacao = new ControleVotacao();
VotacaoFilmesDAO votacaoDAO = null;
ServerSocket socketLadoServidor = null;
Socket socketLadoCliente = null;
int numeroFilmes = 3;
Filme[] filmes = new Filme[numeroFilmes];
int codigoFilmes[] = new int[numeroFilmes];
ObjectInputStream ois;
ObjectOutputStream oos;
String operacao, nomeFilme, comentario, codigoFilme;
Integer[] votosFilme;
votosFilme = new Integer[numeroFilmes];
131
boolean votoRealizado = false;
int codUsuario = 0;
codigoFilmes[0] =
Integer.parseInt(JOptionPane.showInputDialog("Código do primeiro filme",
null));
codigoFilmes[1] =
Integer.parseInt(JOptionPane.showInputDialog("Código do segundo filme",
null));
codigoFilmes[2] =
Integer.parseInt(JOptionPane.showInputDialog("Código do terceiro filme",
null));
try {
Thread controle = new Thread(controleVotacao);
controle.start();
while (true) {
votacaoDAO = VotacaoFilmesDAO.getInstance();
socketLadoServidor = new ServerSocket(9995);
System.out.println("Aguardando votos para
processar...");
socketLadoCliente = socketLadoServidor.accept();
System.out.println("Nova conexao com o cliente: " +
socketLadoCliente.getInetAddress().getHostAddress());
System.out.println("IP Local: " +
socketLadoCliente.getInetAddress().toString());
ois = new ObjectInputStream(
socketLadoCliente.getInputStream() );
oos = new ObjectOutputStream(
socketLadoCliente.getOutputStream() );
try {
operacao = (String) ois.readObject();
if (operacao.equals("Resultados")) {
System.out.println("Recebendo resultados");
for (int i = 0; i < numeroFilmes; i++) {
132
votosFilme[i] = (Integer)
votacaoDAO.obtemVotosFilme(Integer.toString(codigoFilmes[i]));
oos.writeObject(votosFilme[i]);
}
} else if (operacao.equals("Votacao")){
if (votacaoEncerrada == false ) {
System.out.println("Avaliando voto");
nomeFilme = (String) ois.readObject();
comentario = (String) ois.readObject();
System.out.println( nomeFilme );
codigoFilme =
votacaoDAO.obtemCodigoFilme(nomeFilme);
votoRealizado = false;
String nomeUsuario = "Telespectador";
codUsuario++;
votacaoDAO.registraUsuario(Integer.toString(codUsuario), nomeUsuario);
Voto voto = new
Voto(Integer.toString(codUsuario), codigoFilme, comentario);
votoRealizado = votacaoDAO.registraVoto(voto );
System.out.println("Resultado da insercao: " +
votoRealizado);
String mensagem = "Voto computado!";
oos.writeObject(mensagem);
} else {
nomeFilme = (String) ois.readObject();
comentario = (String) ois.readObject();
String mensagem = "A votação ja foi
encerrada!";
System.out.println(mensagem);
oos.writeObject(mensagem);
}
} else if (operacao.equals("Filmes")) {
System.out.println("Enviando filmes");
for(int i = 0; i < numeroFilmes; i++) {
133
filmes[i] =
votacaoDAO.obtemFilme(codigoFilmes[i]);
oos.writeObject(filmes[i]);
}
} else if (operacao.equals("Comentarios")) {
System.out.println("Recebendo comentarios");
List votos = new ArrayList();
votos =
votacaoDAO.obtemComentarios(Integer.toString(codigoFilmes[0]));
Iterator votosIterator =
votos.iterator();
int i = 5;
while(votosIterator.hasNext()) {
Voto voto = (Voto) votosIterator.next();
String nomeUsuario =
votacaoDAO.obtemNomeUsuario(voto.getCodUsuario());
Filme filme =
votacaoDAO.obtemFilme(Integer.parseInt(voto.getCodigoFilme()));
String texto;
if(voto.getComentario().equals("")) {
texto = "vazio";
}
else {
texto = "Usuario: " + nomeUsuario +
"\t\t\t\t\tFilme escolhido: " + filme.getNome() + "\nComentario: " +
voto.getComentario();
}
oos.writeObject( texto);
i--;
}
while(i > 0) {
oos.writeObject("vazio");
i--;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch( IOException ioe ) {
ioe.printStackTrace();
} catch( SQLException sqlException) {
sqlException.printStackTrace();
134
} finally {
oos.close();
ois.close();
socketLadoCliente.close();
socketLadoServidor.close();
}
}
} catch(IOException ioe) {
ioe.printStackTrace();
} finally {
}
}
/**
* Thread utilizada para receber eventos de finalização de votações.
*/
static class ControleVotacao implements Runnable {
private JFrame frame;
private JLabel mensagem;
private JButton botaoFinalizar;
/**
* Cria uma JFrame com um botão de finalizar votação atual.
*/
public ControleVotacao() {
frame = new JFrame("Controle De Votacao");
frame.setSize(320, 180);
frame.setLayout(new FlowLayout());
frame.setVisible( true );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
mensagem = new JLabel("Clique em Finalizar quando desejar
encerrar a votacao.");
mensagem.setVisible( true );
botaoFinalizar = new JButton("Finalizar");
botaoFinalizar.setVisible( true );
frame.add( mensagem );
frame.add( botaoFinalizar );
}
135
/**
* Adiciona o Listener ao botão.
*/
public void run() {
this.botaoFinalizar.addActionListener( new FinalizarListener()
);
}
/**
* Listener que recebe evento do botão e então altera o valor
* boolean votacaoEncerrada.
*/
class FinalizarListener implements ActionListener {
public void actionPerformed(ActionEvent evento) {
if (votacaoEncerrada == false) {
votacaoEncerrada = true;
System.out.println("Votacao encerrada");
} else {
System.out.println("A votacao já havia sido
encerrada.");
}
}
}
}
}
136
VotacaoFilmesDAO.java
package emissora.aplicacao;
import aplicacao.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Classe responsável pelo acesso a base de dados.
*/
public class VotacaoFilmesDAO {
private static VotacaoFilmesDAO votacaoFilmesDAO;
private VotacaoFilmesDAO() {
}
public static VotacaoFilmesDAO getInstance() {
if (votacaoFilmesDAO == null) {
votacaoFilmesDAO = new VotacaoFilmesDAO();
}
return votacaoFilmesDAO;
}
public Connection getConnection () {
Connection con = null;
try {
Class.forName("com.mysql.jdbc.Driver");
con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/VOTACAO", "root",
"administrador");
} catch (ClassNotFoundException cnfException) {
cnfException.printStackTrace();
} catch (SQLException sqlException) {
137
sqlException.printStackTrace();
}
return con;
}
public Filme obtemFilme(int id) {
Connection con = this.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT nome,
descricao, arquivoImagem, arquivoCartaz FROM Filme WHERE codigo = ?");
ps.setString(1, Integer.toString(id));
ResultSet rs = ps.executeQuery();
if (rs.next()) {
String nomeFilme = rs.getString("nome");
String sinopse = rs.getString("descricao");
String arquivoImagem = rs.getString("arquivoImagem");
String arquivoCartaz = rs.getString("arquivoCartaz");
return new Filme(nomeFilme, arquivoCartaz, arquivoImagem,
sinopse);
} else {
return null;
}
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
return null;
}
public void registraUsuario(String codigoUsuario, String nomeUsuario)
throws SQLException {
Connection con = this.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO usuario
VALUES (?, ?)");
ps.setString(1, codigoUsuario);
ps.setString(2, nomeUsuario);
ps.execute();
}
138
public boolean validaUsuario(String query, String username, String
password) {
Connection con = this.getConnection();
try {
PreparedStatement ps = con.prepareStatement(query);
ps.setString(1, username);
ps.setString(2, password);
ps.execute();
ResultSet rs = ps.getResultSet();
if (rs.next()) {
// Usuário autenticado.
return true;
}
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
return false;
}
public boolean registraVoto (Voto voto) throws SQLException {
String codigoUsuario = voto.getCodUsuario();
String codigoFilme = voto.getCodigoFilme();
String comentario = voto.getComentario();
Connection con = this.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO voto
VALUES (?, ?, ?)");
ps.setString(1, codigoUsuario);
ps.setString(2, codigoFilme);
ps.setString(3, comentario);
boolean execute = ps.execute();
return execute;
}
public String obtemCodigoFilme (String nomeFilme) {
Connection con = this.getConnection();
try {
139
PreparedStatement ps = con.prepareStatement("SELECT codigo FROM
Filme WHERE nome = ?");
ps.setString(1, nomeFilme);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return rs.getString(1);
} else {
return null;
}
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
return null;
}
public Integer obtemVotosFilme (String nomeFilme) {
Connection con = this.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT count(*)
FROM Voto WHERE codigo = ?");
ps.setString(1, nomeFilme);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return rs.getInt(1);
} else {
return null;
}
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
return null;
}
public List<Voto> obtemComentarios (String nomeFilme) {
Connection con = this.getConnection();
List votos = new ArrayList();
140
try {
PreparedStatement ps = con.prepareStatement("SELECT * FROM Voto
ORDER BY codigoUsuario DESC LIMIT 5");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String codigoUsuario = rs.getString("codigoUsuario");
String codigoFilme = rs.getString("codigo");
String comentario = rs.getString("comentario");
Voto voto = new Voto(codigoUsuario, codigoFilme,
comentario);
votos.add(voto);
}
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
return votos;
}
String obtemNomeUsuario(String codUsuario) {
Connection con = this.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT nome FROM
Usuario WHERE codigo = ?");
ps.setString(1, codUsuario);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return rs.getString(1);
} else {
return null;
}
} catch (SQLException sqlException) {
sqlException.printStackTrace();
}
return null;
}
}
141
Voto.java
package emissora.aplicacao;
/**
* Classe representando a entidade voto.
*/
public class Voto {
String codUsuario;
String codigoFilme;
String comentario;
public Voto(String codUsuario, String codigoFilme, String comentario) {
this.codUsuario = codUsuario;
this.codigoFilme = codigoFilme;
this.comentario = comentario;
}
public String getCodUsuario() {
return this.codUsuario;
}
public String getCodigoFilme() {
return this.codigoFilme;
}
public String getComentario() {
return this.comentario;
}
}