UNIVERSIDADE FEDERAL DE SANTA CATARINA JNC MOBILE – SISTEMA DE ACESSO REMOTO PARA DISPOSITIVOS MÓVEIS Andrei Luciano Krause Rafael Augusto da Silva Florianópolis – SC 2005/1 UNIVERSIDADE FEDERAL DE SANTA CATARINA DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA CURSO DE CIÊNCIAS DA COMPUTAÇÃO JNC MOBILE – SISTEMA DE ACESSO REMOTO PARA DISPOSITIVOS MÓVEIS Andrei Luciano Krause Rafael Augusto da Silva Trabalho de conclusão de curso apresentado como parte dos requisitos para a obtenção do grau de Bacharel em Ciências da Computação. Florianópolis – SC 2005/1 Andrei Luciano Krause Rafael Augusto da Silva JNC MOBILE – SISTEMA DE ACESSO REMOTO PARA DISPOSITIVOS MÓVEIS Trabalho de conclusão de curso apresentado como parte dos requisitos para a obtenção do grau de Bacharel em Ciências da Computação. Orientador: Prof. Dr. José Eduardo De Lucca Banca examinadora Prof. MSc. Fernando Augusto da Silva Cruz Prof. Dr. Mário Antônio Ribeiro Dantas AGRADECIMENTOS Agradeço aos meus pais, à minha noiva Vanessa e aos meus amigos Rafael Augusto da Silva e Augusto Boal. Todos foram fundamentais. Andrei Luciano Krause Aos meus pais pelo incentivo. Ao professor De Lucca pela confiança e apoio. Ao amigo Andrei pela grande parceria. Em especial à minha esposa Renata, pelo auxílio, compreensão e companheirismo. Muito obrigado! Rafael Augusto da Silva iii RESUMO Os dispositivos móveis figuram atualmente no mercado como mercadorias em franca expansão. Desta forma, é necessário que os serviços oferecidos por estes aparelhos, sejam cada vez mais de excelência, proporcionando o máximo de utilidade aos usuários. O objetivo desta pesquisa é justamente apresentar um software capaz de oferecer o poder de processamento de uma estação de trabalho com a praticidade, mobilidade e conectividade dos dispositivos móveis como aparelhos celulares. A ferramenta neste documento apresentada, possibilita o acesso remoto de um computador através de um simples telefone celular, oferecendo ao seu usuário, a experiência de utilizar softwares disponíveis apenas para máquinas com processamento mais robusto. Conheça também as ferramentas que possibilitam a concepção deste novo paradigma de programação e criação de softwares. PALAVRAS-CHAVE: Computação Móvel. Computação Remota. J2ME. Dispositivos Móveis. VNC. iv ABSTRACT The mobile devices appear currently in the market as merchandises in frank expansion. Of this form, it is necessary that the services offered for these devices, are each time more than excellency, providing the maximum of utility to the users. The objective of this research is exactly to present a software capable to offer the power of processing of a workstation with the practice, mobility and connectivity of the mobile devices as cell phones. The tool in this presented document, makes possible the remote access of a computer through a simple cellular telephone, offering its user, the experience to use softwares available only for machines with more robust processing. It also knows the tools that make possible the conception of this new paradigm of programming and software development. KEYWORDS: Mobile computation. Remote computation. J2ME. Móbile devices. VNC. v LISTA DE FIGURAS Figura 1 – Plataforma J2ME.................................................................................. Figura 2 – Arquitetura Eclipse ............................................................................... Figura 3 – IDE AJDT do Eclipse............................................................................ Figura 4 – Acesso remoto com VNC ..................................................................... Figura 5 – Acesso remoto através de dispositivo móvel ....................................... Figura 6 – Acesso remoto através de dispositivo móvel com servidor bridge ....... Figura 7 – Compactação da imagem enviada ao cliente....................................... Figura 8 – Programa servidor................................................................................ Figura 9 – Programa cliente – Celular................................................................... Figura 10 – Teclas do celular para o servidor VNC............................................... Figura 11 – Tela do VNC para celular – módulo PC ............................................. Figura 12 – Telas do VNC para celular – módulo J2ME – Celular ........................ Figura 13 – Telas do VNC para celular – módulo J2ME – Celular ........................ Figura 14 – Telas do VNC para celular – módulo J2ME – Celular ........................ Figura 15 – Telas do VNC para celular – módulo J2ME – Celular ........................ Figura 16 – Classes da aplicação cliente .............................................................. Figura 17 – Classes da aplicação servidor............................................................ Figura 18 – Classes da aplicação servidor............................................................ Figura 19 – Diagrama de seqüência UML ............................................................. Figura 20 – Ambiente de programação ................................................................. vi 19 23 26 27 29 30 30 35 36 38 38 39 40 40 41 42 43 44 45 46 SUMÁRIO RESUMO .............................................................................................. iv ABSTRACT .......................................................................................... v LISTA DE FIGURAS ............................................................................ vi 1 INTRODUÇÃO................................................................................ 1.1 Delimitação do tema ................................................................... 1.2 Objetivo geral .............................................................................. 1.3 Objetivos específicos ................................................................. 1.4 Justificativa.................................................................................. 1.5 Problema ...................................................................................... 1.6 Metodologia ................................................................................. 09 09 10 10 11 11 12 2 DISPOSITIVOS, TECNOLOGIAS E SISTEMAS MÓVEIS............. 2.1 Computação móvel ..................................................................... 2.2 Dispositivos móveis.................................................................... 2.2.1 Notebooks, laptops e palmtops ................................................... 2.2.2 PDAs (Personal Digital Assistants) ............................................. 2.2.3 Celulares ..................................................................................... 2.3 Protocolos de comunicação sem fio ......................................... 2.4 Java 2 Micro Edition – J2ME ...................................................... 2.4.1 Arquitetura J2ME......................................................................... 2.4.2 Configurações ............................................................................. 2.4.3 Perfis ........................................................................................... 2.4.4 Pacotes ....................................................................................... 2.5 Eclipse.......................................................................................... 2.5.1 Plataforma Eclipse....................................................................... 2.5.2 Arquitetura ................................................................................... 2.5.3 IDEs............................................................................................. 2.6 Virtual Network Computing – VNC ............................................ 13 13 14 14 15 16 17 18 18 19 20 21 21 22 23 25 26 vii 3 JNC MOBILE - SISTEMA DE ACESSO REMOTO PARA DISPOSITIVOS MÓVEIS................................................................ 3.1 Descrição do sistema ................................................................. 3.2 RFB Protocol ............................................................................... 3.2.1 Entrada ........................................................................................ 3.2.2 Representação dos pixels ........................................................... 3.2.3 Raw Encoding ............................................................................. 3.2.4 Copy Rectangle Encoding ........................................................... 3.2.5 Mensagens de protocolo ............................................................. 3.2.6 Diretivas do protocolo auxiliar ..................................................... 3.3 Desenvolvimento da aplicação .................................................. 3.3.1 Programa servidor ....................................................................... 3.3.2 Programa cliente ......................................................................... 3.3.3 Telas do sistema ........................................................................ 3.3.4 Diagrama de classes ................................................................... 3.3.5 Diagrama de seqüência UML ...................................................... 3.3.6 Ambiente de desenvolvimento ................................................... 29 29 31 31 32 32 32 32 33 34 35 36 37 41 45 45 4 TRABALHOS FUTUROS ............................................................... 47 5 CONSIDERAÇÕES FINAIS............................................................ 49 REFERÊNCIAS .................................................................................... 51 APÊNDICES......................................................................................... 53 APÊNDICE A – Código Fonte da Aplicação Cliente ........................ 54 APÊNDICE B – Código Fonte da Aplicação Servidor...................... 67 APÊNDICE C – Artigo ......................................................................... 101 viii 9 1 INTRODUÇÃO Nesta pesquisa o leitor irá realizar sua leitura em quatro capítulos. O primeiro capítulo tem por motivação apresentar os objetivos da pesquisa, delimitar o tema por esta proposto, justificar e apresentar a metodologia empregada neste estudo. Dando continuidade ao documento, tem-se o segundo capítulo, que aborda as questões referentes aos dispositivos móveis escolhidos, a computação móvel e as tecnologias e ferramentas empregadas para o desenvolvimento da pesquisa. Assim, é chegada a hora de apresentar o desenvolvimento da aplicação, como se deu o processo de implementação e uma explicação mais apurada de seu funcionamento. Por fim, o quarto capítulo, onde são apresentados alguns trabalhos futuros derivados desta pesquisa. 1.1 Delimitação do tema Com a popularização dos dispositivos móveis, um novo paradigma de serviços foi criado. Assim, para atender e suportar estes serviços os dispositivos móveis, que têm na forma dos telefones celulares seus mais evidentes representantes, sofreram transformações para poder corresponder aos anseios gerados por estes novos serviços. Aparelhos que eram utilizados apenas para fazer ligações, passaram rapidamente a figurar como agendas eletrônicas, câmeras fotográficas digitais, gravadores de som digital, e mais recentemente, no Brasil, computadores de mão. 10 Mesmo com estas funcionalidades sendo oferecidas, o poder computacional destes dispositivos ainda não proporciona uma experiência muito confortável, limitando os serviços à sua capacidade reduzida de memória e poder de processamento. Uma maneira de oferecer poder computacional e proporcionar acesso a serviços exclusivos das estações de trabalho é o acesso remoto via dispositivos móveis a estações de trabalho. Com o poder de mobilidade e conectividade dos dispositivos móveis, aliados a inovadora tecnologia J2ME da Sun, esta pesquisa visa apresentar uma solução capaz de conectar remotamente uma estação de trabalho a um aparelho móvel. 1.2 Objetivo geral Desenvolver um sistema de acesso remoto para dispositivos móveis possibilitando o gerenciamento de estações de trabalho à distância. 1.3 Objetivos específicos • Identificar a melhor linguagem de programação para produção de sistemas para dispositivos móveis. • Definir um tipo de dispositivo móvel para desenvolvimento da aplicação. • Criar um software cliente para dispositivos móveis capaz de gerenciar uma estação de trabalho a partir de um software servidor. 11 1.4 Justificativa Como os dispositivos móveis atuais não proporcionam poder computacional equiparado as estações de trabalho, e a facilidade de mobilidade e conectividade proporcionada por aparelhos móveis é fato, a motivação desta pesquisa tem seu alicerce em tentar unir o poder computacional das estações de trabalho, com a facilidade de acesso a serviços dos dispositivos móveis. Para tal, é apresentado como solução para este problema, o desenvolvimento de uma aplicação cliente – servidor, onde um dispositivo móvel realiza uma conexão remota a uma estação de trabalho. 1.5 Problema Com o crescimento do número de dispositivos móveis no cotidiano da sociedade, e do incremento de funcionalidades destes aparelhos, os anseios por serviços mais robustos e específicos tornam-se necessários. Um relevante serviço para profissionais da área de TI (Tecnologia e Informação) seria a capacidade de gerenciarem remotamente diferentes dispositivos fixos, como estações de trabalho a partir de seus celulares, PDAs (Personal Digital Assistants), entre outros. Assim, para esta pesquisa defini-se o seguinte questionamento: como desenvolver um sistema de acesso remoto para dispositivos móveis possibilitando o gerenciamento de estações de trabalho à distância? 12 1.6 Metodologia Esta pesquisa, segundo sua natureza, classifica-se como aplicada, pois objetiva gerar conhecimentos para aplicação prática dirigidos à solução de problemas específicos. Envolve verdades e interesses locais. (GIL, 1991) Quanto a abordagem do problema a pesquisa é caracterizada como qualitativa que, segundo Gil (1991, p. 41) “possui uma relação dinâmica entre o mundo real e o sujeito, isto é, um vínculo indissociável entre o mundo objetivo e a subjetividade do sujeito que não pode ser traduzido em números”. A interpretação dos fenômenos e a atribuição dos significados são básicos no processo de pesquisa qualitativa. De acordo com os objetivos a pesquisa é considerada explicativa, pois visa identificar os fatores que determinam ou contribuem para a ocorrência dos fenômenos. “Aprofunda o conhecimento da realidade porque explica arazão, o ‘porquê’ das coisas” (GIL, 1991, p. 42) Por fim, do ponto de vista dos procedimentos técnicos, a pesquisa é de cunho: bibliográfico, elaborada a partir de material já publicado (sites e livros); documental, a partir de materiais que não receberam tratamento analítico (Manual de dispositivos móveis); e experimental, através da determinação do objeto de estudo, da seleção das variáveis, das formas de controle e da observação dos efeitos produzidos. (GIL, 1991) 13 2 DISPOSITIVOS, TECNOLOGIAS E SISTEMAS MÓVEIS 2.1 Computação móvel Em decorrência dos anos 90, o mercado foi invadido por um volume crescente de desenvolvimento em áreas de tecnologia celular móvel, redes sem fios e comunicação via satélites. De acordo com a popularização tomada por estas tecnologias, o acesso a informações remotas cresce vertiginosamente através de novos serviços oferecidos aos usuários. A evolução e popularização de dispositivos móveis como celulares, notebooks, PDAs (Personal Digital Assistants), dispositivos dedicados móveis (GPS – Global Positional System), entre outros, torna possível a determinação do seguinte conceito: “Computação móvel pode ser representada como um novo paradigma computacional que permite que usuários desse ambiente tenham acesso a serviços independentemente de sua localização, podendo inclusive, estar em movimento.” (FIGUEIREDO; NAKAMURA, 2003, p.16) As palavras chaves para computação móvel são: processamento, mobilidade e comunicação. De acordo com Mateus e Loureiro (1998 apud FIGUEIREDO; NAKAMURA, 2003, p.17) a computação móvel é denominada a quarta revolução da computação, logo após o advento dos grandes centros de processamento na década de sessenta, o surgimento dos terminais uma década mais tarde, e as redes de computadores nos anos oitenta. Ampliando o conceito de computação distribuída, graças a comunicação sem fio, que elimina a necessidade do usuário estar conectado à uma infra-estrutura estática. 14 2.2 Dispositivos móveis Para estar de acordo com a definição de computação móvel apresentada no capítulo anterior, os dispositivos móveis devem possuir tamanho reduzido bem como capacidade de trocar informações via rede, realizar processamento, ser de fácil transporte e não fazer uso de cabos tanto para conectar-se à rede de dados como a um suporte de energia. Os dispositivos mais utilizados para o propósito de computação móvel são: • Notebooks, Laptos, Palmtops; • PDAs (Personal Digital Assistants); • Celulares (Smartphones). Segue abaixo um breve discurso sobre estes dispositivos. 2.2.1 Notebooks, laptops e palmtops Equipamentos como notebooks e laptops podem ser considerados verdadeiras estações de trabalho móvel, pois com o avanço tecnológico no processo de miniaturização de componentes, hoje é possível encontrar estes aparelhos com capacidades semelhantes e em alguns casos superiores ao desempenho de estações de trabalho fixas. E com um forte aliado, proporções de tamanho bem inferiores a um desktop completo. Mesmo com recursos comparáveis ao de uma estação de trabalho comum, notebooks e laptops ainda não são a solução de mobilidade ideal, pois necessitam quase sempre de uma base onde possam ser apoiados para operarem, possuem baterias com duração pequena (aproximadamente três horas de uso ininterrupto), o que faz com que o usuário esteja sempre em busca de um acesso a energia elétrica. 15 Já os Palmtops, resolvem alguns destes empecilhos, por serem semelhantes aos notebooks e laptops, entretanto, mesmo assim, não correspondem a uma experiência móvel confortável. Limitando ainda mais as capacidades de processamento e armazenamento, bem como dificultando os métodos de entrada e saída de dados. 2.2.2 PDAs (Personal Digital Assistants) Um PDA típico, pode assumir as funções de um telefone celular, aparelho de fax, Web browser e organizador pessoal. São conhecidos também como handhelds (dispositivos de mão). Infelizmente devido ao tamanho reduzido, suas características de processamento e armazenamento ficam comprometidas, assim como suas opções de entrada e saída nada confortáveis (os dados são inseridos com o auxílio de uma caneta e um software para reconhecimento de escrita, por exemplo). Estes aparelhos têm como objetivo real, substituir agendas eletrônicas, oferecendo recursos mais avançados para este propósito e agregar serviços de telefonia, fax, Internet, em um único dispositivo. Seu uso também pode ser observado em linhas de montagem ou restaurantes, onde simples softwares para conferência e controle podem ser facilmente utilizados para automatizar serviços em um ambiente onde não há espaço físico para suportar uma estação de trabalho. Imagine um garçom anotando seu pedido em um notebook apoiado sobre os pratos de sua mesa. Os PDAs são reconhecidos por proporcionar entretenimento multimídia com qualidade muito satisfatória, reproduzindo vídeos e áudio, batendo fotos, etc. As baterias também figuram como problema nestes dispositivos, mas agora sua duração pode ir de muitas horas até alguns dias. 16 2.2.3 Celulares Desenvolvidos inicialmente com o único propósito de levar a comunicação além das barreiras da telefonia fixa convencional, os celulares chegaram para transpor barreiras e permitir que qualquer indivíduo em qualquer lugar do planeta, possa comunicar-se com qualquer outro indivíduo em um ponto qualquer do globo. Entretanto, com o avanço tecnológico e a evolução das gerações da telefonia celular estes aparelhos adquiriram um novo status no qual passam a figurar como dispositivos capazes de processamento e armazenamento de dados, principalmente junto a Internet, conforme tabela 1. Geração 1G 2G 2,xG 3G Características Transmissão de Dados Analógica (AMPS); Transmissão Digital de Dados (TDMA, CDMA e GSM); Disponibilização de aplicações pré-3G Taxas de 9600bps Taxas de 9600bps a 14400bps; Taxas de até 2Mbps; Surgimento de aplicações WAP. Surgimento de aplicações multimídia. Evolução CDMA e GSM; 4G Elevação das taxas de transmissão de dados; Tecnologias e aplicações ainda em discussão. Quadro 1 – Gerações da telefonia celular Fonte: Figueiredo e Nakamura, 2003, p.19 As características e problemas apresentados pelos celulares assemelham-se com as citadas nos PDAs. Porém, com um revés a mais, a interação com o dispositivo é ainda maior, limitando-se na maioria dos casos, as teclas do aparelho. A solução parece ter sido incorporar aos telefones celulares as funções de um PDA, 17 gerando assim um novo dispositivo reconhecido pelo nome de Smartphone. É apostando no custo reduzido destes aparelhos e nos serviços por eles oferecidos que procura-se realizar uma experiência móvel de qualidade e de uso satisfatório. 2.3 Protocolos de comunicação sem fio São duas as principais tecnologias para redes sem fio, que têm sido utilizadas em soluções de computação móvel, o padrão IEEE 802.11 (redes infraestruturdas) e o padrão Bluetooth (redes AdHoc). a) IEEE 802.11: O IEEE (Institute of Electrical and Electronics Engineers Inc.) é o órgão responsável por padronizar as camadas físicas e de enlace para redes sem fio. Seu padrão, o 802.11 ou Wi-Fi como também é chamado, em sua concepção original, prevê velocidades de operação de 1 e 2Mbps, já a versão 802.11b, proporciona velocidades de até 11Mbps, e por fim, a versão 802.11g, sugere velocidades de até 54Mbps. Mecanismos de autenticação e criptografia são suportados através do WEP (Wired Equivalent Privacy), entretanto por motivos de falta de segurança, estuda-se a adoção de uma nova versão, o WPA (Wi-Fi Protected Access). É a tecnologia ideal para substituir infra-estrutura cabeada. b) Bluetooth: Padronizado pelo Bluetooth SIG, que é composto por empresas tais como Lucent, Microsoft, IBM, Intel, Motorola, Toshiba, Nokia e mais de outras 2000 companhias, o Bluetooth é um sistema para comunicações de pequeno alcance (menos de 10 metros). Surgiu da necessidade de se eliminar cabos de conexão entre equipamentos. Fazendo uso de micro-rádios embutidos em um chip, e utilizando uma tecnologia denominada transmissão por salto de freqüência, é capaz de operar na faixa de freqüência de 2,4 Ghz. Opera no modo “full duplex”, 18 recebe e envia ao mesmo tempo, e possui taxas de transferência de até 1Mbps com baixo consumo de energia. Promete tornar-se padrão de mercado devido as possibilidades de aplicação e por ser suportado por dispositivos de diversos fabricantes. 2.4 Java 2 Micro Edition – J2ME Basicamente J2ME é um termo que refere-se a uma coleção de APIs e máquinas virtuais que tornam possível o uso de Java em dispositivos móveis. Com o J2ME é possível levar ao mundo dos dispositivos móveis, os benefícios da tecnologia Java, como flexibilidade na interface com o usuário, um modelo de segurança eficaz, suporte a diferentes tipos de aplicações , entre outros. A plataforma J2ME está presente na maioria dos dispositivo móveis atuais, facilitando ao usuário a aquisição de novos serviços e mais inteligentes. Assim, a plataforma J2ME segue como propenso padrão a ser adotado no desenvolvimento de aplicações mobile. 2.4.1 Arquitetura J2ME Toda a arquitetura J2ME define, configurações, perfis e pacotes opcionais, como elementos de uma aplicação Java completa. Assim, a plataforma é capaz de atender aos requerimentos de diferentes dispositivos e mercados. Cada combinação destes elementos otimiza a capacidade de processamento, armazenamento e interfaces de entrada e saída para cada dispositivo particularmente. O resultado é uma plataforma de desenvolvimento Java comum, capaz de atender a diferentes tipos de equipamentos e fabricantes. 19 Figura 1 – Plataforma J2ME Fonte: Sun Microsystems, 2005 2.4.2 Configurações As configurações consistem de uma máquina virtual e de um pequeno conjunto de classes. Este conjunto provê as funcionalidades básicas de uma faixa de dispositivos que compartilham características como conexão de rede e gerenciamento de memória. Existem duas configurações em J2ME: a) Connected Limited configurações. Device Desenvolvida Configuration para (CLDC): dispositivos com a menor conexões das duas de rede 20 intermitentes, processadores lentos e memória limitada. Usada em dispositivos com CPUs de 16 ou 32 bits e com no mínimo de 128KB a 512KB de memória disponível para suportar a plataforma Java e aplicações associadas. Os equipamentos que costumam utilizar esta configuração são os telefones celulares, PDAs e pagers. b) Connected Device Configuration (CDC): esta configuração é disponibilizada em dispositivos mais robustos, com CPUs de 32 bits ou mais e com no mínimo 2Mb de memória disponível. Encontra-se em PDAs de alta perfomance, gateways residenciais entre outros. Nesta configuração tem-se uma máquina virtual Java completa, bem como muito mais recursos do J2SE. 2.4.3 Perfis Para proporcionar uma solução completa, as configurações devem estar vinculadas a APIs de alto nível, ou a perfis, para ser possível definir o modelo de ciclo de vida da aplicação, a interface com o usuário e o tipo de acesso a dispositivos específicos. Assim, tem-se como principais perfis os que seguem: a) Mobile Information Device Profile (MIDP): desenvolvido para telefones celulares e PDAs. Oferece o núcleo de funcionalidades requeridas por aplicações móveis, incluindo interface com usuário, conectividade, armazenamento e gerenciamento da aplicação. O MIDP em conjunto com o CLDC, representa uma solução completa que maximiza as capacidades do dispositivo e minimiza o consumo de memória e energia. b) Foundation Profile (FP): este é o perfil de mais baixo nível para o CDC. Ele permite uma implementação do CDC em sistemas embarcados sem o uso de interface com o usuário. Em caso de necessidade de implementar uma interface 21 com o usuário, este perfil pode ser combinado com outros dois, o Personal Profile e o Personal Basis Profile. c) Personal Profile (PP): utilizado em dispositivos que exigem uma GUI completa ou suporte a applets para internet, como PDAs de alta perfomance e consoles de vídeo game. Inclui todas as libraries do AWT (Java Abstract Window Toolkit). d) Personal Basis Profile (PBP): é um subconjunto do perfil Personal Profile. Provê suporte a aplicações network-connected em dispositivos que suportam gráficos em nível básico ou que requeiram o uso de ferramentas gráficas específicas. Exemplos, tv set-top boxes, quiosques de informações e outros. 2.4.4 Pacotes A plataforma J2ME pode ser estendida combinando-se vários pacotes opcionais com CLDC ou CDC e seus perfis. Criados para mercados específicos, vários pacotes apresentam APIs defaults para uso em tecnologias conhecidas e tecnologias em desenvolvimento ou expansão, como o suporte a Bluetooth, Web services, etc. Assim, os fabricantes de dispositivos podem inserir em seus produtos os pacotes necessários para suportar as funcionalidades oferecidas por seus dispositivos. 2.5 ECLIPSE Criado pela extinta OTI (Object Technology International), famosa por sua tecnologia de orientação a objetos para Smalltalk e Java, o Eclipse apresenta um novo modelo de software open source. Com a aquisição da OTI pela IBM, o lançamento do Eclipse deu-se com o anúncio da doação de quarenta milhões de 22 dólares (valor estimado da versão 1.0 do Eclipse) da IBM para a comunidade open source, sob uma licença open source (a CPL). Desta forma, o Eclipse tornou-se um dos principais exemplos de softwares open source com estrutura de softwares proprietários. Outros casos que podem ser citados são: Linux, MySQL (MySQL AG), NetBeans e OpenOffice (Sun), entre outros. O projeto Eclipse fez com que o modelo “livre+comercial” chegasse a uma nova ordem de grandeza, pois nunca um software open source obteve tanto investimento e de forma continuada. Os objetivos do projeto são sem fins lucrativos, descrevendo um modelo muito semelhante a iniciativas de organismos responsáveis por padronizações como a OMG ou a W3C. Entretanto, órgãos como a OMG e o W3C, produzem apenas especificações, já a Fundação Eclipse cria produtos. Assim, surge uma nova tendência na evolução do open source. 2.5.1 Plataforma Eclipse O Eclipse costuma ser visto como apenas uma IDE Java. E efetivamente, é este papel que presta o principal pacote oferecido pela plataforma, o Eclipse SDK. Porém, o objetivo real e concreto da plataforma, é oferecer suporte a criação de diversas ferramentas. Com um microkernel capaz de gerenciar plug-ins, toda a funcionalidade real da ferramenta é fornecida por essas extensões. Baseado nesta afirmação, a plataforma adquire uma arquitetura peculiar, a qual é melhor explorada no item a seguir. 23 2.5.2 Arquitetura Os principais componentes da arquitetura do Eclipse podem ser contemplados na figura a seguir. Figura 2 – Arquitetura Eclipse Fonte: Java Magazine, 2005 A plataforma é o “coração” dos IDEs. Os plug-ins assinalados em amarelo, são específicos da linguagem Java, dependentes do JDT o compilador Java utilizado pelo Eclipse, direta ou indiretamente. Segue uma breve descrição dos principais componentes da arquitetura: a) Runtime de plataforma: é o responsável por inicializar e gerenciar plug-ins. É o programa principal. b) Workspace: gerente de recursos (arquivos e diretórios). Do ponto de vista do usuário final, mostra-se como uma estrutura de diretórios que contém os projetos 24 do Eclipse. Cabe ao Workspace então, gerenciar esta estrutura de diretórios, implementando recursos como marcadores, além de projetos e eventos de alteração de recursos (que são utilizados pelo componente Team para manutenção do histórico local e pelos compiladores para compilação incremental). O uso de GUIs (interfaces gráficas), não é usado em momento algum nestes processos. c) SWT e JFace: são de toolkits de GUI. O toolkit principal é o SWT, cabendo ao JFace, o papel de framework MVC que permite programação de alto nível. d) Workbench: implementa as entidades básicas de GUI, como a estrutura de Perspectivas, Views e Editores, menus, caixas de configuração, e outros recursos genéricos de interfaces gráficas. Oferece suporte a todas as funcionalidades de GUI do Workspace. e) Team: realiza o controle de versões e histórico de alterações de recursos. Não oferece suporte a um gerenciador de versões específico, mas possui subsídios para que plug-ins possam ser criados para qualquer gerenciador. Estende o Workspace para gerar versionamento local de recursos, sem utilizar servidor de repositório. f) Debug: define a arquitetura, conceitos e suporte GUI fundamentais para depuração de programas, tais como, processos, breakpoints, visualização de variáveis, filtros, etc. g) Help: compõe-se de um servidor e um visualizador de help próprios, que permite construir help on-line a partir de conteúdo HTML. Recursos como pesquisa, navegação e indexação também são providos pelo Help. h) Update: onde ocorre o gerenciamento de atualizações automáticas. 25 2.5.3 IDEs A plataforma Eclipse oferece diversos IDEs para diferentes tipos de desenvolvimento. Assim, para construção deste projeto, foi necessário a escolha e utilização de algumas possibilidades oferecidas pela plataforma. A seguir, segue uma lista com os principais IDEs e ferramentas oferecidas pelo Eclipse, com destaque para as utilizadas neste projeto. a) JDT (Java Development Tooling): é a parte do projeto Eclipse mais conhecida. O JDT é o IDE para aplicações Java. Possui suporte aos projetos Java, edição e compilação dos fontes, depuração de aplicações, assistentes para criação de classes e interfaces e etc. Para a concepção deste projeto foi esta a IDE Eclipse utilizada. b) PDE (Plug-in Development Environment): esta IDE suporta a criação de plug-ins para o Eclipse em Java. Oferece assistentes para criação dos plug-ins, editores para configuração dos mesmos, deployment, gerador de testes, entre outros. c) CDT (C/C++ Development Tools): viabiliza a construção de projetos para as linguagens C/C++. Atualmente esta IDE é voltada para a plataforma Linux e ferramentas GNU. d) AJDT (Aspect Development Tools): implementa suporte a Programação Orientada a Aspectos (AOP). e) COBOL: como pode-se esperar pelo nome, esta IDE traz suporte a antiga programação praticada nos mainframes, o COBOL. Na figura a seguir, é possível se ter uma idéia de como a plataforma Eclipse apresenta-se graficamente, a imagem traz o IDE AJDT em funcionamento. 26 Figura 3 – IDE AJDT do Eclipse Fonte: Java Magazine, 2005 2.6 Virtual Network Computing – VNC O VNC foi criado pelo Laboratório de Pesquisas da Olivetti & Oracle. No ano de 1999, a AT&T adquiriu o laboratório, e posteriormente em 2002, fechou a divisão de pesquisas do mesmo. Seu nome deriva de um computador com rede ATM chamado Videotile, que consistia apenas de um LCD com uma caneta e uma rápida conexão de rede ATM. Assim o VNC é essencialmente uma versão deste computador. Com o VNC, é possível controlar remotamente uma estação de trabalho apenas com o uso de um simples programa cliente ou visualizador como também é 27 chamado. Outra característica interessante é o fato de não ser necessário que os dispositivos utilizados (cliente – servidor) sejam do mesmo tipo e/ou possuam mesmo sistema operacional. Figura 4 – Acesso remoto com VNC Fonte: Real VNC, 2005 Um software de controle remoto como o VNC, possui uma gama muito grande de benefícios, pois torna possível controlar uma estação de trabalho através de uma rede seja ela fixa ou sem fio, como se o indivíduo estivesse operando pessoalmente a estação acessada remotamente. Como destaque de uso pessoal desta ferramenta, pode-se imaginar o seguinte cenário: auxiliar ou realizar uma tarefa de atualização de software na estação de trabalho de uma pessoa que mora em um outro país. Com o uso do VNC, é possível que você mesmo realize a tarefa no computador da pessoa que 28 solicitou auxílio, enquanto esta acompanha todos os passos em frente seu computador, como se ela mesma estivesse realizando todo o procedimento. Existem dezenas de implementações deste conceito, utilizando o mesmo protocolo (RFB - vide seção 3.2 adiante), o que permite a interoperação de clientes e servidores de versões/origem distintas. São exemplos de implementações do VNC os seguintes softwares: a) realVNC [http://www.realvnc.com/]: programa original. b) tightVNC [http://www.tightvnc.com/]: otimizado para low-bandwidth. c) tridiaVNC [http://www.tridiavnc.com/]: mais opções de gerenciamento. d) ultraVNC [http://www.ultravnc.com/]: possui vários extras, transferência de arquivos, chat, drivers de vídeo, etc. e) win2VNC [http://sourceforge.net/projects/win2vnc/]: um desktop virtual entre duas estações de trabalho. Assim, por constatar as facilidades que tal software proporciona, esta pesquisa propõe-se à apresentar uma solução cliente para ser embarcada em dispositivos móveis, para propiciar as facilidades oferecidas pelo VNC com a liberdade e facilidade de operar-lo através de um equipamento móvel. 29 3 JNC MOBILE - SISTEMA DE ACESSO REMOTO PARA DISPOSITIVOS MÓVEIS 3.1 Descrição do sistema O JNC Mobile, tem como proposta, apresentar um software cliente para dispositivos móveis capaz de controlar remotamente uma estação de trabalho ou outro dispositivo móvel, que esteja configurado com um servidor VNC e com um servidor Bridge escrito em Java, que realizará a comunicação entre as aplicações cliente e servidor VNC. Figura 5 – Acesso remoto através de dispositivo móvel Fonte: Elaborada pelos autores, 2005 O dispositivo móvel escolhido para a implementação e testes do software foi um telefone celular. Ainda, devido a não padronização entre os diferentes fabricantes de celulares, a Nokia foi escolhida como fabricante para realização dos testes em aparelhos emulados. Como o servidor VNC é fornecido apenas em linguagem C++, e todo o projeto visa o uso da tecnologia Java, e o conhecimento dos desenvolvedores em C++ não é satisfatório, a solução encontrada foi o desenvolvimento de um servidor na linguagem Java, onde as requisições do cliente são recepcionadas por este 30 servidor bridge e encaminhadas ao servidor VNC. Desta forma também foi obtida uma certa liberdade de como os dados devem chegar ao servidor VNC, possibilitando o tratamento de requisições e desvios de controle por parte do servidor bridge. Figura 6 – Acesso remoto através de dispositivo móvel com servidor bridge Fonte: Elaborada pelos autores, 2005 As requisições recebidas pelo servidor bridge são passadas ao servidor VNC através do Protocolo RFB (Remote Frame Buffer). Por sua vez, o servidor VNC retorna ao bridge o status (imagem) do desktop, e este encarrega-se de transmitir a informação ao dispositivo móvel. O servidor bridge acumula além da responsabilidade de tradutor entre o programa cliente e o servidor VNC, a função de compactação da imagem enviada ao cliente. Figura 7 – Compactação da imagem enviada ao cliente Fonte: Elaborada pelos autores, 2005 31 A imagem fornecida pelo servidor – PC – é capturada pelo – Bridge – que verifica as coordenadas que estão sendo requisitadas pelo dispositivo móvel e as converte para que estas possam ser exibidas na tela. Por exemplo: o celular envia, após efetuar conexão, comandos de zoom mais e comandos de mudança de posição da tela, ao receber a requisição, o servidor Bridge captura a tela do PC, “corta” a parte que o cliente requisitou e redimensiona para o tamanho da tela do dispositivo móvel. Assim, conclui-se o processo cliente – servidor bridge – servidor VNC. 3.2 RFB Protocol O protocolo RFB (Remote Frame Buffer) foi desenvolvido pela AT&T para ser usado em seu programa de Virtual Networking Computer (VNC), porém atualmente, vários outros programas utilizam-se do protocolo RFB para interagir com servidores VNC. O princípio básico do protocolo RFB é: - Desenhe uma imagem a partir das coordenadas 0,0 até as coordenadas x,x. Para otimizar a tarefa principal que o protocolo RFB se propõe a realizar, é disponibilizado um conjunto de diretivas que possibilitam configurar o tipo de codificação e compactação em que a imagem será transmitida e exibida. 3.2.1 Entrada O protocolo entende que A “Entrada” de dados será baseada em teclado e mouse de dois botões, portanto, para enviar eventos de teclado e mouse é necessário que se implemente tal interface. 32 No caso de dispositivos móveis que não possuem estes recursos, é necessário emulá-los a partir de recursos disponíveis, ou seja, o teclado numérico e as teclas de direção. Para deixar o software mais compatível com outros dispositivos móveis, optou-se por não utilizar as teclas de direção, e sim, emulá-las através das teclas numéricas. 3.2.2 Representação dos pixels Logo após a autenticação do cliente, o servidor verifica qual o tipo de codificação será utilizada, para isso o protocolo RFB oferece 5 tipos de codificações: Raw Encoding, Copy Rectangle Encoding, RRE encoding, CoRRE encoding e Hextile encoding, porém apenas duas são relevantes para o trabalho em questão. 3.2.3 Raw Encoding Consiste em escrever linha por linha os pixeis da imagem, é a forma mais demorada (n x n pixels = n * n operações), porém é a mais simples. 3.2.4 Copy Rectangle Encoding Desenha apenas as partes da imagem que foram modificadas, por exemplo: - Redesenhe apenas o retângula x=15, y=15, largura =40, altura=30. 3.2.5 Mensagens de protocolo O protocolo RFB fornece um sistema de mensagens que permitem os programas se comunicarem de forma simples e segura, o funcionamento de um 33 programa que se conecta à um servidor VNC consiste em basicamente dois estágios: a) Fase de Conexão ou Handshaking: consiste em verificar a versão do protocolo, autenticação, inicialização do cliente e inicialização do servidor. b) Fase normal de processamento: é nesta fase que são enviadas mensagens cliente-servidor, todas as mensagens contém o tipo de dados e o conteúdo da mensagem propriamente dito. As diretivas do protocolo RFB tiveram que ser parcialmente implementadas pela equipe deste projeto para que o servidor bridge (em JAVA) tivesse a possibilidade de acessar os comando e ler as informações vindas do Servidor VNC. Foram utilizadas também, algumas classes JAVA disponibilizadas na internet: a) RFBProtocol.java [http://www.tightvnc.com]: classe que implementa o protocolo entre o servidor Bridge e o servidor VNC. b) DesCipher.java [http://www.acme.com]: utilizada para cifrar a senha enviada ao servidor VNC pelo servidor Bridge . c) AnimatedMemoryImageSource.java [http://www.tightvnc.com]: responsável por manipular a imagem enviada pelo servidor VNC. Todas estas classes são regidas pela GPL (General Public License), atestando assim seu uso livre. 3.2.6 Diretivas do protocolo auxiliar Um protocolo auxiliar teve de ser implementado para que o dispositivo móvel tivesse acesso ao servidor bridge, sendo assim algumas diretivas foram definidas e lidas pelo programa através de variáveis statics do JAVA: 34 Quadro 2 – Diretivas do protocolo auxiliar Fonte: Elaborado pelos autores, 2005 3.3 Desenvolvimento da aplicação Para o desenvolvimento desta aplicação foram criados dois aplicativos, um servidor, que deve ser instalado na estação de trabalho a ser controlada remotamente, e um cliente, instalado no dispositivo móvel. A seguir segue uma descrição mais apurada destas aplicações. 35 3.3.1 Programa servidor Esta parte da aplicação deve ser instalada na máquina que se deseja controlar remotamente. Na seqüência é apresentada uma figura com as classes que compõe a aplicação servidor. Figura 8 - Programa servidor Fonte: elaborada pelos autores, 2005. Breve descrição das funcionalidades de cada classe: a) DP: contém apenas constantes do protocolo auxiliar implementado pela equipe, esta classe deve ser igual para os dois programas – cliente, servidor – para que não haja conflitos de ações entre os programas. b) RFBProtocol: classe adaptada de versão encontrada na internet, serve para comunicar-se com o servidor VNC original, contém programação de baixo nível (bytes, hexadecimal, deslocamento de bits). c) TratadorDeComandos: funciona como um processador de protocolo de ações do cliente, tratando e devolvendo os dados requisitados, é nesta classe que é utilizado o protocolo auxiliar. d) PainelDeAutenticacao: classe de Interface com o usuário, contém os campos para entrada de dados como: endereço do servidor, porta, senha, etc... e) AnimatedMemoryImageSource: classe adaptada que facilita o redimensionamento de imagens. 36 f) DesCipher: classe para a cifragem de senha. g) Log: utilizado principalmente na fase de desenvolvimento para acompanhar as ações que estavam sendo realizadas, é uma boa alternativa quando o debug não é necessário. h) TratadorDeImagem: utilizada para tratamento da imagem recebida do servidor, o objeto criado a partir desta classe gerencia a posição e o ZOOM que deve ser levado em conta na hora de fornecer a imagem ao cliente. i) TratadorDoMouse: classe utilizada pelo tratador da imagem para calcular o redimensionamento e posicionamento da imagem, a cada ação no celular o tratador de mouse é acionado para informar que houve uma mudança na posição ou no zoom da figura. 3.3.2 Programa cliente Através desta aplicação é que o dispositivo acessa remotamente o programa servidor instalado na estação de trabalho alvo. A exemplo da aplicação servidor, segue a listagem de classes do programa e suas descrições. Figura 9 - Programa cliente – Celular Fonte: elaborada pelos autores, 2005. 37 Breve descrição das funcionalidades de cada classe: a) Protocol: classe que sobre escreve a classe da J2ME do celular, é uma tentativa de tornar a aplicação compatível com a MIDP 1.0, já que esta versão não suporta sockets. b) Conexao: responsável por manter a conexão com o servidor “ponte”, utiliza a classe DP, implementando o protocolo auxiliar. c) Cliente: contém a inicialização do programa, determina o tamanho da tela, e a conexão a ser feita, atribui propriedades as telas. d) Log: muito utilizado na fase de implementação, já que as ferramentas usadas para desenvolvimento não possuíam um fácil debuger para J2ME. e) Main: apenas para iniciar a aplicação, padrões para MIDP. f) TelaAjuda: contém uma pequena figura com a explicação dos comandos. g) TelaInicial: campos para entrada do endereço do servidor “ponte” e senha. h) TelaPrincipal: contém a estrutura onde será exibida a tela do desktop compartilhado. 3.3.3 Telas do sistema A seguir estão as definições das teclas do celular, o que elas representam para o servidor VNC: 38 Figura 10 – Teclas do celular para o servidor VNC Fonte: elaborada pelos autores, 2005. Tela do VNC para celular – módulo PC: Figura 11 - Tela do VNC para celular – módulo PC Fonte: elaborada pelos autores, 2005. 39 Na tela apresentada são informados os dados para que o Servidor VNC fique disponível para os dispositivos móveis, a seguir a descrição dos campos: a) Host VNC: Endereço IP ou nome do computador onde o servidor VNC se encontra rodando, inclusive para acesso via PC. b) Senha: Senha para acesso ao serviço VNC. c) Porta: É a porta na qual está rodando o serviço VNC. d) Senha externa: É a senha que terá que ser informada no celular para acessar o serviço. e) Porta externa: É a porta na qual rodará o serviço, a qual deverá ser informada no celular. Telas do VNC para celular – módulo J2ME - Celular: Figura 12 - Telas do VNC para celular – módulo J2ME - Celular Fonte: elaborada pelos autores, 2005. Tela onde são informados os dados para conexão com o computador que disponibilizará o serviço VNC para dispositivos móveis, é nescessário informar o endereço e a senha. 40 Figura 13 - Telas do VNC para celular – módulo J2ME - Celular Fonte: elaborada pelos autores, 2005. Esta tela mostra a tela do computador que está com o serviço VNC rodando, após a conexão é mostrada a tela completa, sem efeitos de ZOOM ou deslocamento da tela. Figura 14 - Telas do VNC para celular – módulo J2ME - Celular Fonte: elaborada pelos autores, 2005. Nesta figura se observa a tela do computador remoto após serem enviados alguns comandos de ZOOM e deslocamento de tela, facilitando assim a visualização dos itens que estão disponíveis no computador. 41 Figura 15 - Telas do VNC para celular – módulo J2ME - Celular Fonte: elaborada pelos autores, 2005. Tela do celular mostrando o computador remoto, neste caso foi utilizado ZOOM máximo para exibição. 3.3.4 Diagrama de classes Será apresentado a seguir o diagrama de classes para as aplicações cliente e servidor. 42 a) Aplicação cliente: Figura 16 – Classes da aplicação cliente Fonte: elaborada pelos autores, 2005. 43 b) Aplicação servidor: Figura 17 – Classes da aplicação servidor Fonte: elaborada pelos autores, 2005. 44 Figura 18 – Classes da aplicação servidor Fonte: elaborada pelos autores, 2005. 45 3.3.5 Diagrama de seqüência UML Figura 19 – Diagrama de seqüência UML Fonte: elaborada pelos autores, 2005. 3.3.6 Ambiente de desenvolvimento Para o desenvolvimento da aplicação, o seguinte ambiente de programação foi elaborado sobre um sistema operacional Windows XP: a) J2SE (SDK) 1.5.0_02: esta é a plataforma Java fundamental. Neste pacote encontram-se as classes Java necessárias para a criação do sistema, compilador Java, a extensão J2ME, que evidentemente permite o uso de Java em aplicações para dispositivos móveis, e outros requerimentos para desenvolvimento de projetos em linguagem Java. b) Wireless Toolkit 2.2 (WTK): Pode ser definido como uma “caixa de ferramentas” para desenvolvimento de aplicações J2ME. O conjunto de serviços oferece: ambiente para emulação, opções para documentação, exemplos de aplicações, etc. otimização de desempenho, 46 c) VNC: uma versão free do VNC foi utilizada para servir de servidor principal. Assim,o servidor Bridge criado na pesquisa realizou a interface entre o servidor VNC e o cliente instalado no dispositivo móvel. d) Eclipse 3.1: É a versão utilizada da plataforma Eclipse. O IDE escolhido foi o JDT, como já foi explanado anteriormente. Apenas a ferramenta Eclipse já oferece um total ambiente de programação, e com certeza foi um dos softwares utilizados que mais contribuiu para o desenvolvimento rápido e eficaz do JNC Móbile. Segue abaixo uma figura demonstrando o ambiente de desenvolvimento. Figura 20 - Ambiente de programação Fonte: elaborada pelos autores, 2005. 47 4 TRABALHOS FUTUROS Como trabalhos futuros, um grande número de opções pode ser explorado. Entretanto, surge como mais claro para os autores, a abordagem dos seguintes tópicos possíveis: a) Possibilitar o cadastro de tarefas automáticas no servidor Bridge: ao instalar o servidor bridge na estação de trabalho a ser controlada remotamente, o usuário poderá cadastrar tarefas junto a esta máquina que posteriormente poderão ser executadas pela aplicação cliente disponível no dispositivo móvel. Assim, tarefas como shutdown, restart, ativar desfragmentador de disco, uma rotina de trabalho, rodar anti-vírus, entre outras, poderá ser facilmente executadas com uma simples seleção em um menu de tarefas da aplicação cliente. Com esta funcionalidade, a experiência de uso do JNC se tornará muito mais amigável e interessante. b) Permitir a entrada de texto a partir do cliente: com esta funcionalidade o usuário será capaz de digitar palavras utilizando-se do teclado de seu aparelho móvel. Assim, torna-se possível a escrita de textos ou comandos no servidor, apenas digitando as letras da mesma maneira que se faz com a escrita de mensagens em aparelhos celulares. c) Construir um servidor completo em Java: infelizmente ainda é necessário para a aplicação descrita nesta pesquisa, o uso de um servidor VNC escrito em C++. Desta forma, o uso de um servidor bridge tornou-se indispensável. Então, como trabalho futuro, espera-se que apenas um servidor seja requerido para o funcionamento de todo o sistema, o que facilitaria sua instalação e configuração. d) Implementar um protocolo genérico para controle remoto: como trabalho mais audacioso, os pesquisadores propõe a implementação de um protocolo para controle remoto genérico. Assim, um único protocolo poderia ser utilizado para 48 tratar o envio e recebimento de textos, imagens, comandos para dispositivos diversos, como câmeras de vídeo, comandos para robôs domésticos, etc. Este protocolo visaria tornar possível padronizar a utilização de recursos, agilizando o trabalho de empresas de software no desenvolvimento de aplicações de caráter remoto. 49 5 CONSIDERAÇÕES FINAIS O mercado de dispositivos móveis está crescendo vertiginosamente. O público foi acometido por uma onda de consumo onde todo equipamento ou serviço deve ser móvel e de conectividade imediata. Aparelhos como DVDs, videogames, computadores, assumiram novos conceitos ao serem miniaturizados e munidos de conexão sem fios a diferentes tipos de mídia, seja esta a Internet ou outro dispositivo. Desta forma, um novo tipo de relacionamento entre máquinas e a sociedade está se formando. Para facilitar está transição, e dispor-se de maneira competitiva e atual, os pesquisadores buscaram com êxito, conhecer e conceber soluções para dispositivos móveis. Objetivos como identificar qual tecnologia empregar para solução de problemas móveis, foram prontamente atendidos ao definir-se o uso da tecnologia Java 2 ME. Tecnologia que já vem embutida na maioria dos dispositivos móveis do mercado e que visa marcar presença em mais de 90% destes dispositivos até 2007. A escolha de aparelhos celulares para a concepção do sistema deu-se principalmente a três fatores: são dispositivos genuinamente móveis; quando se trata de se discutir dispositivos móveis, quase sempre são os primeiros a serem lembrados como pertencentes a esta classe, estando assim fortemente ligados ao que o público associa como solução móvel; era o dispositivo móvel ao alcance dos pesquisadores para o desenvolvimento da pesquisa. O uso de uma tecnologia nascida para realizar esta tarefa, como é o caso do J2ME, e a utilização de ferramentas como o Wireless Toolkit da Sun, e o Eclipse, somente não foram maiores facilitadores da pesquisa por conta da incompatibilidade existente entre os aparelhos celulares. Este problema de padrões na indústria 50 parece estar se resolvendo com a iniciativa de atualização do profile do J2ME MIDP, que agora figura em sua segunda versão. Entretanto, infelizmente não havia a disposição para experimento neste trabalho um dispositivo móvel provido desta funcionalidade. Vale lembrar que a incompatibilidade existe até mesmo entre aparelhos do mesmo fabricante, dificultando ainda mais a criação e difusão de soluções para dispositivos móveis como celulares. Excluindo-se estes obstáculos, a pesquisa alcançou seus objetivos. A implementação de um sistema para acesso remoto via dispositivos móveis foi realizada com sucesso. Os pesquisadores tornaram possível o controle de uma estação de trabalho utilizando-se apenas um simples aparelho celular. Desta maneira, um imprevisto que clame por um acesso a uma máquina, devidamente ligada e conectada a Internet e com o JNC disponível, pode facilmente ser acessada de qualquer local e com a maior discrição possível atualmente, fazendo com que seu usuário manipule apenas seu simples aparelho telefônico. É importante lembrar que a fluidez do uso da aplicação é fortemente comprometido por limitações de acessibilidade impostas pelos aparelhos celulares, dispõe-se apenas das teclas do aparelho, e o visor reduzido também torna a visualização de um desktop completo um desafio. Mas como caráter principalmente acadêmico que tem esta pesquisa, e com o alcance dos objetivos almejados pelos pesquisadores, é com satisfação que se apresenta o JNC Mobile como uma solução real para acesso remoto para dispositivos móveis. 51 REFERÊNCIAS AN INTRODUCTION to J2ME. Wikipedia. Disponível em: <http://en.wikipedia.org/wiki/An_Introduction_to_J2ME> Acesso: 27 mar. 2005. CARNIEL, Juliano D.; KÜHL, Daniel. J2ME: como começar? Web Móbile. Rio de Janeiro. Ano 1. ed. 2. p. 58-66. Mar. 2005. DOEDERLEIN, Osvaldo. O projeto Eclipse: arquitetura, subprojetos, planos e ferramentas. Java Magazine. Rio de Janeiro. Ano 3. ed. 23. p. 28-44. abr. 2005. FIGUEIREDO, Carlos M. S.; NAKAMURA, Eduardo. Computação móvel: novas oportunidades e novos desafios. T&C Amazônia. Ano 1. n. 2. Jun. 2003. GIL, Antônio Carlos. Como elaborar projetos de pesquisa. 3 ed. São Paulo: Atlas, 1991. JAVATM 2 Platform, Micro Edition. Sun Microsystems. Disponível em: <http://java.sun.com/> Acesso: 27 mar. 2005. JAVA 2 Platform, Micro Edition (J2ME); JSR 68 Overview. Sun Microsystems. Disponível em: <http://java.sun.com/> Acesso: 27 mar. 2005. META VNC - a window aware VNC. Meta VNC. Disponível em: <http://metavnc.sourceforge.net/> Acesso: 27 mar. 2005. 52 MOBILE Information Device Profile (MIDP); JSR 37, JSR 118 Overview. Sun Microsystems. Disponível em: <http://java.sun.com/products/midp/> Acesso: 27 mar. 2005. TAUBER, Daniel. What's J2ME? OnJava. 2001. Disponível em: <http://www.onjava.com/pub/a/onjava/2001/03/08/J2ME.html> Acesso: 27 mar. 2005. THE J2ME Frequently Asked Questions List. BellSouthpwp. Disponível em: <http://bellsouthpwp.net/m/c/mcpierce/j2mefaq.html> Acesso: 27 mar. 2005. VIRTUAL Network Computing. Wikipedia. Disponível em: <http://pt.wikipedia.org/wiki/Virtual_Network_Computing> Acesso: 27 mar. 2005 WHAT is VNC. RealVNC. Disponível em: <http://www.realvnc.com/what.html> Acesso: 27 mar. 2005. APÊNDICES APÊNDICE A – Código Fonte da Aplicação Cliente Conexao.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:42 package rede; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import javax.microedition.io.Connector; import javax.microedition.io.HttpConnection; import javax.microedition.lcdui.Image; import ui.Log; import ui.TelaPrincipal; public class Conexao extends Thread { private int comando; private int largura; private int altura; private TelaPrincipal tela; private String host; private String senha; public Conexao(String _host, String _senha) { host = _host; senha = _senha; } public void run() { iniciaValores(); while (true) { long numMillisecondsToSleep = 500; // 1/5 segundos try { Thread.sleep(numMillisecondsToSleep); } catch (InterruptedException e) { e.printStackTrace(); } if (tela != null) { atualizaTela(); } } } public void iniciaValores() { HttpConnection c = null; InputStream input = null; try { String urlConexao = host + "/" + largura + "x" + altura; Log.info(urlConexao); c = (HttpConnection) Connector.open(urlConexao, Connector.READ_WRITE); c.setRequestMethod(HttpConnection.GET); Log.info("pass2"); input = c.openInputStream(); Log.info("pass3"); } catch (Exception e) { e.printStackTrace(); } finally { if (input != null) try { input.close(); } catch (IOException e) { e.printStackTrace(); } if (c != null) try { c.close(); } catch (IOException e) { e.printStackTrace(); } } enviaComando(DP.INICIA_TRATADOR_DE_IMAGENS); atualizaTela(); } public boolean alterou() { return true; } public void enviaComando(int _comando) { comando = _comando; Page 1 of 3 Conexao.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 5/7/2005 19:42 } public void atualizaTela() { try { HttpConnection c; c = (HttpConnection) Connector.open(host + "/" + comando, Connector.READ_WRITE); comando = DP.GET_IMAGEM; c.setRequestMethod(HttpConnection.GET); Log.info("pass2"); InputStream input = c.openInputStream(); Log.info(c.getType()); Log.info("pass3"); Image im; tela.setImagem(getImage(input)); tela.repaint(); c.close(); } catch (Exception e) { e.printStackTrace(); } } private Image getImage(InputStream iStrm) throws IOException { Image im = null; try { Log.info("carregando imagem"); int bufferSize = 256; byte byteInput[] = new byte[bufferSize]; ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream(1024); int size = 0; while ((size = iStrm.read(byteInput, 0, bufferSize)) != -1) { Log.info("escrevendo"); imageBuffer.write(byteInput, 0, size); } // get byte from buffer stream byte byteImage[] = imageBuffer.toByteArray(); Log.info("read byte " + byteImage.length); // convert byte to image ... im = Image.createImage(byteImage, 0, byteImage.length); return im; // ByteArrayOutputStream bStrm = new ByteArrayOutputStream(); // // int ch; // while ((ch = iStrm.read()) != -1) // bStrm.write(ch); // // // Place into image array // byte imageData[] = bStrm.toByteArray(); // // // Create the image from the byte array // Log.info(imageData.length); // im = Image.createImage(imageData, 0, imageData.length); } catch (Exception e) { e.printStackTrace(); } finally { // Clean up if (iStrm != null) iStrm.close(); } return (im == null ? null : im); } public void fechar() { enviaComando(DP.FINALIZAR_CONEXAO); } public int getAltura() { return altura; } public void setAltura(int altura) { this.altura = altura; } public int getLargura() { return largura; Page 2 of 3 Conexao.java 153 154 155 156 157 158 159 160 161 162 163 164 165 166 5/7/2005 19:42 } public void setLargura(int largura) { this.largura = largura; } public TelaPrincipal getTela() { return tela; } public void setTela(TelaPrincipal tela) { this.tela = tela; } } Page 3 of 3 DP.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 5/7/2005 19:42 package rede; public class DP { public static public static public static public static public static public static public static public static public static public static public static public static public static public static public static public static public static } final final final final final final final final final final final final final final final final final int int int int int int int int int int int int int int int int int INICIA_TRATADOR_DE_IMAGENS = 10; CONEXAO_OK = 11; GET_IMAGEM = 12; FINALIZAR_CONEXAO = 13; CMD_BT_MOUSE1 = 14; CMD_BT_MOUSE2 = 15; CMD_TELA_PARA_CIMA = 16; CMD_TELA_PARA_BAIXO = 17; CMD_TELA_PARA_DIREITA = 18; CMD_TELA_PARA_ESQUERDA = 19; CMD_MOUSE_PARA_CIMA = 20; CMD_MOUSE_PARA_BAIXO = 21; CMD_MOUSE_PARA_DIREITA = 22; CMD_MOUSE_PARA_ESQUERDA = 23; CMD_ZOOM_MAIS = 24; CMD_ZOOM_MENOS = 25; IMAGEM_RECEBIDA = 26; Page 1 of 1 Cliente.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:42 package ui; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.midlet.MIDlet; import rede.Conexao; public class Cliente implements CommandListener { private Display display; private Command cmOk; private Command cmVoltar; private Command cmSair; private Command cmAjuda; private Conexao conexao; private TelaAjuda telaAjuda; private TelaPrincipal telaPrincipal; private TelaInicial telaInicial; private MIDlet midletPrincipal; public Cliente(Display d, MIDlet m) { midletPrincipal = m; display = d; startApp(); } private void criaComandos() { cmOk = new Command("Ok", Command.SCREEN, 2); cmVoltar = new Command("Voltar", Command.BACK, 1); cmSair = new Command("Sair", Command.EXIT, 1); cmAjuda = new Command("Ajuda", Command.HELP, 2); } private void preparaTelas() { telaAjuda = new TelaAjuda("Ajuda"); telaAjuda.addCommand(cmOk); telaAjuda.addCommand(cmVoltar); telaAjuda.setCommandListener(this); telaPrincipal = new TelaPrincipal(); telaPrincipal.addCommand(cmSair); telaPrincipal.addCommand(cmAjuda); telaPrincipal.setCommandListener(this); telaInicial = new TelaInicial("Mobile VNC"); telaInicial.addCommand(cmSair); telaInicial.addCommand(cmOk); telaInicial.setCommandListener(this); } public void startApp() { criaComandos(); preparaTelas(); display.setCurrent(telaInicial); } public void pauseApp() { } public void destroyApp(boolean unconditional) { } public void commandAction(Command comando, Displayable tela) { if (comando == cmVoltar) { display.setCurrent(telaPrincipal); } if (comando == cmOk) { if (telaAjuda.isShown()) { display.setCurrent(telaPrincipal); } if (telaInicial.isShown()) { iniciaConexao(); } } if (comando == cmAjuda) { display.setCurrent(telaAjuda); } if (comando == cmSair) { Page 1 of 2 Cliente.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 5/7/2005 19:42 conexao.fechar(); destroyApp(false); midletPrincipal.notifyDestroyed(); } } private synchronized void iniciaConexao() { Log.info("Conectando em..." + telaInicial.getTxtEndereco().getString()); conexao = new Conexao(telaInicial.getTxtEndereco().getString(), telaInicial.getTxtSenha().getString()); conexao.setLargura(telaPrincipal.getWidth()); conexao.setAltura(telaPrincipal.getHeight()); conexao.start(); telaPrincipal.setConexao(conexao); display.setCurrent(telaPrincipal); } } Page 2 of 2 Log.java 1 2 3 4 5 6 7 8 9 10 11 12 5/7/2005 19:43 package ui; public class Log { public synchronized static void info(String texto) { // Log.info("Info: "+texto); } public synchronized static void erro(String texto) { Log.info("Erro: " + texto); } } Page 1 of 1 Main.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 5/7/2005 19:43 package ui; import javax.microedition.lcdui.Display; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class Main extends MIDlet { public Main() { super(); } protected void startApp() throws MIDletStateChangeException { Cliente c = new Cliente(Display.getDisplay(this), this); } protected void pauseApp() { } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { } } Page 1 of 1 TelaAjuda.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 5/7/2005 19:43 package ui; import java.io.IOException; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.Image; public class TelaAjuda extends Form { public TelaAjuda(String nome) { super(nome); Image imagemDeAjuda = Image.createImage(5, 5); Log.info("Carregando imagem de ajuda"); try { imagemDeAjuda = Image.createImage("/ajuda.jpg"); } catch (IOException e) { e.printStackTrace(); } Log.info("Finalizando carregamento"); append(imagemDeAjuda); } } Page 1 of 1 TelaInicial.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 5/7/2005 19:44 package ui; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.TextField; public class TelaInicial extends Form { private TextField txtEndereco; private TextField txtSenha; public TelaInicial(String nome) { super(nome); txtEndereco = new TextField("Endereço", "http://192.168.152.38:8080", 40, TextField.ANY); txtSenha = new TextField("Senha", "testevnc", 8, TextField.ANY); append(txtEndereco); append(txtSenha); } public TextField getTxtEndereco() { return txtEndereco; } public TextField getTxtSenha() { return txtSenha; } } Page 1 of 1 TelaPrincipal.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:44 package ui; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import rede.Conexao; import rede.DP; public class TelaPrincipal extends Canvas { private Conexao conexao; private int keyCode; private boolean movimentaMouse; private Image imagem; public TelaPrincipal() { imagem = Image.createImage(132, 100); } public void keyReleased(int keyCode) { this.keyCode = keyCode; } public void keyRepeated(int keyCode) { this.keyCode = keyCode; } public void keyPressed(int keyCode) { this.keyCode = keyCode; Log.info("codigo=" + keyCode); switch (keyCode) { case KEY_NUM1: // Clique botao esquerdo do mouse enviaComando(DP.CMD_BT_MOUSE1); break; case KEY_NUM2: // Movimenta tela/mouse para cima if (movimentaMouse) { enviaComando(DP.CMD_MOUSE_PARA_CIMA); } else { enviaComando(DP.CMD_TELA_PARA_CIMA); } break; case KEY_NUM3: // Clique botao direito do mouse enviaComando(DP.CMD_BT_MOUSE2); break; case KEY_NUM4: // Movimenta tela/mouse para esquerda if (movimentaMouse) { enviaComando(DP.CMD_MOUSE_PARA_ESQUERDA); } else { enviaComando(DP.CMD_TELA_PARA_ESQUERDA); } break; case KEY_NUM5: break; case KEY_NUM6: // Movimenta tela/mouse para direita if (movimentaMouse) { enviaComando(DP.CMD_MOUSE_PARA_DIREITA); } else { enviaComando(DP.CMD_TELA_PARA_DIREITA); } break; case KEY_NUM7: // Zoom menos enviaComando(DP.CMD_ZOOM_MENOS); break; case KEY_NUM8: // Movimenta tela/mouse para baixo if (movimentaMouse) { enviaComando(DP.CMD_MOUSE_PARA_BAIXO); } else { enviaComando(DP.CMD_TELA_PARA_BAIXO); } break; case KEY_NUM9: // Zoom mais enviaComando(DP.CMD_ZOOM_MAIS); break; case KEY_NUM0: // Troca movimento de tela/mouse movimentaMouse = !movimentaMouse; break; default: break; Page 1 of 2 TelaPrincipal.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 5/7/2005 19:44 } } public Conexao getConexao() { return conexao; } public void setConexao(Conexao conexao) { this.conexao = conexao; conexao.setTela(this); } protected void paint(Graphics g) { g.drawImage(imagem, 0, 0, Graphics.LEFT | Graphics.TOP); } private synchronized void enviaComando(int comando) { Log.info("Comando=" + comando); conexao.enviaComando(comando); } public Image getImagem() { return imagem; } public void setImagem(Image imagem) { this.imagem = imagem; } } Page 2 of 2 APÊNDICE B – Código Fonte da Aplicação Servidor DP.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 5/7/2005 19:32 package app.rede; public class DP { public static public static public static public static public static public static public static public static public static public static public static public static public static public static public static public static public static } final final final final final final final final final final final final final final final final final int int int int int int int int int int int int int int int int int INICIA_TRATADOR_DE_IMAGENS = 10; CONEXAO_OK = 11; GET_IMAGEM = 12; FINALIZAR_CONEXAO = 13; CMD_BT_MOUSE1 = 14; CMD_BT_MOUSE2 = 15; CMD_TELA_PARA_CIMA = 16; CMD_TELA_PARA_BAIXO = 17; CMD_TELA_PARA_DIREITA = 18; CMD_TELA_PARA_ESQUERDA = 19; CMD_MOUSE_PARA_CIMA = 20; CMD_MOUSE_PARA_BAIXO = 21; CMD_MOUSE_PARA_DIREITA = 22; CMD_MOUSE_PARA_ESQUERDA = 23; CMD_ZOOM_MAIS = 24; CMD_ZOOM_MENOS = 25; IMAGEM_RECEBIDA = 26; Page 1 of 1 LeitorDeComando.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:33 package app.rede; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import app.util.Log; public class LeitorDeComando { ServerSocket serverSocket = null; public LeitorDeComando(int porta) { try { serverSocket = new ServerSocket(porta, 100); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } public void fechaFechaConexao() { if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } Socket socket = null; private OutputStream output = null; private Request request = null; public int getComando() { InputStream input = null; Log.info("aguardando"); try { socket = serverSocket.accept(); Log.info("conectado"); input = socket.getInputStream(); output = socket.getOutputStream(); request = new Request(input); int comando = request.parse(); return comando; } catch (IOException e) { e.printStackTrace(); } return 0; } public TelaCelular getTelaCelular() { InputStream input = null; Log.info("aguardando"); try { socket = serverSocket.accept(); Log.info("conectado"); input = socket.getInputStream(); output = socket.getOutputStream(); request = new Request(input); TelaCelular tela = request.getTela(); Response response = new Response(output); response.setRequest(request); response.enviaTelaDeBoasVinas(); socket.close(); return tela; } catch (IOException e) { e.printStackTrace(); } return null; } public void enviaImagem(BufferedImage imagem) { try { Response response = new Response(output); response.setRequest(request); Page 1 of 2 LeitorDeComando.java 77 78 79 80 81 82 83 84 5/7/2005 19:33 response.sendStaticResource(imagem); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } Page 2 of 2 Request.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 5/7/2005 19:34 package app.rede; import java.io.IOException; import java.io.InputStream; import app.util.Log; public class Request { private InputStream input; private String uri; public Request(InputStream input) { this.input = input; } public int parse() { StringBuffer request = new StringBuffer(2048); int i; byte[] buffer = new byte[2048]; try { i = input.read(buffer); } catch (IOException e) { e.printStackTrace(); i = -1; } for (int j = 0; j < i; j++) { request.append((char) buffer[j]); } uri = parseUri(request.toString()); Log.info("uri=" + uri); int comando = Integer.parseInt(uri.toString().substring(1)); return comando; } public TelaCelular getTela() { // Read a set of characters from the socket StringBuffer request = new StringBuffer(2048); int i; byte[] buffer = new byte[2048]; try { i = input.read(buffer); } catch (IOException e) { e.printStackTrace(); i = -1; } for (int j = 0; j < i; j++) { request.append((char) buffer[j]); } uri = parseUri(request.toString()); Log.info("URI=" + uri); String[] valores = uri.substring(1).split("x"); TelaCelular tela = new TelaCelular(); tela.setLargura(Integer.parseInt(valores[0].trim())); tela.setAltura(Integer.parseInt(valores[1].trim())); return tela; } private String parseUri(String requestString) { int index1, index2; index1 = requestString.indexOf(' '); if (index1 != -1) { index2 = requestString.indexOf(' ', index1 + 1); if (index2 > index1) return requestString.substring(index1 + 1, index2); } return null; } public String getUri() { return uri; } } Page 1 of 1 Response.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 5/7/2005 19:34 package app.rede; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import javax.imageio.ImageIO; import app.util.Log; public class Response { private static final int BUFFER_SIZE = 1024; Request request; OutputStream output; public Response(OutputStream output) { this.output = output; } public void setRequest(Request request) { this.request = request; } public void sendStaticResource(BufferedImage imagemCelular) { int leido = 0; byte datosBytes[] = new byte[256]; try { String respuesta = "HTTP/1.0 200 OK\n"; respuesta += "Date: Mon, 5 Nov 2008 23:59:59GMT\n"; respuesta += "Content-Type: image/jpeg\n"; respuesta += "\r\n"; output.write(respuesta.getBytes()); output.flush(); Log.info("enviando imagem"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write((RenderedImage) imagemCelular, "jpeg", baos); byte[] bytes = baos.toByteArray(); ImageIO.write((RenderedImage) imagemCelular, "jpeg", output); System.out.println(output.toString()); System.out.println("terminando envio"); } catch (Exception e) { e.printStackTrace(); } } public void enviaTelaDeBoasVinas() { try { String respuesta = "HTTP/1.0 200 OK\n"; respuesta += "Date: Mon, 5 Nov 2008 23:59:59GMT\n"; respuesta += "Content-Type: text/playn\n"; respuesta += "\r\n"; output.write(respuesta.getBytes()); output.flush(); String boasVinas = "Conectado!!!"; output.write(boasVinas.getBytes(), 0, boasVinas.getBytes().length); output.flush(); } catch (Exception e) { e.printStackTrace(); } } } Page 1 of 1 RFBProtocol.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:34 //Classe retirada do site http://www.tightvnc.com/ com licensa GPL //e modificada para atender as necessidades do programa //Copyright (C) 2001,2002 HorizonLive.com, Inc. All Rights Reserved. //Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved. //Copyright (C) 2000 Tridia Corporation. All Rights Reserved. //Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. package app.rede; import java.awt.Event; import java.awt.event.MouseEvent; import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import app.util.DesCipher; public class RFBProtocol { final String versionMsg = "RFB 003.003\n"; final int ConnFailed = 0, NoAuth = 1, VncAuth = 2; final int VncAuthOK = 0, VncAuthFailed = 1, VncAuthTooMany = 2; private static final boolean COMPARTILHAR_DESKTOP = true; final static int FramebufferUpdate = 0, SetColourMapEntries = 1, Bell = 2, ServerCutText = 3; final int SetPixelFormat = 0, FixColourMapEntries = 1, SetEncodings = 2, FramebufferUpdateRequest = 3, KeyEvent = 4, PointerEvent = 5, ClientCutText = 6; final static int EncodingRaw = 0, EncodingCopyRect = 1, EncodingRRE = 2, EncodingCoRRE = 4, EncodingHextile = 5; final int HextileRaw = (1 << 0); final int HextileBackgroundSpecified = (1 << 1); final int HextileForegroundSpecified = (1 << 2); final int HextileAnySubrects = (1 << 3); final int HextileSubrectsColoured = (1 << 4); String vncHost; int vncPort; Socket sock; DataInputStream is; OutputStream os; public boolean inNormalProtocol = false; // // Constructor. Just make TCP connection to RFB server. // public RFBProtocol(String vncHost, int vncPort) { this.vncHost = vncHost; this.vncPort = vncPort; try { sock = new Socket(vncHost, vncPort); is = new DataInputStream(new BufferedInputStream(sock .getInputStream(), 16384)); os = sock.getOutputStream(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void close() { try { sock.close(); } catch (Exception e) { e.printStackTrace(); } } // // Read server's protocol version message // int serverMajor, serverMinor; void readVersionMsg() throws IOException { byte[] b = new byte[12]; is.readFully(b); if ((b[0] != 'R') || (b[1] != 'F') || (b[2] != 'B') || (b[3] != ' ') || (b[4] < '0') || (b[4] > '9') || (b[5] < '0') || (b[5] > '9') Page 1 of 8 RFBProtocol.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 5/7/2005 19:34 || (b[6] < '0') || (b[6] > '9') || (b[7] != '.') || (b[8] < '0') || (b[8] > '9') || (b[9] < '0') || (b[9] > '9') || (b[10] < '0') || (b[10] > '9') || (b[11] != '\n')) { throw new IOException("Host " + vncHost + " port " + vncPort + " is not an RFB server"); } serverMajor = (b[4] - '0') * 100 + (b[5] - '0') * 10 + (b[6] - '0'); serverMinor = (b[8] - '0') * 100 + (b[9] - '0') * 10 + (b[10] - '0'); } public boolean connectAndAuthenticate(String password) throws IOException { boolean authenticationDone = false; readVersionMsg(); System.out.println("RFB server supports protocol version " + serverMajor + "." + serverMinor); writeVersionMsg(); switch (readAuthScheme()) { case NoAuth: System.out.println("No authentication needed"); authenticationDone = true; break; case VncAuth: byte[] challenge = new byte[16]; is.readFully(challenge); String pw = password; if (pw.length() > 8) pw = pw.substring(0, 8); // truncate to 8 chars byte[] key = new byte[8]; pw.getBytes(0, pw.length(), key, 0); for (int i = pw.length(); i < 8; i++) { key[i] = (byte) 0; } DesCipher des = new DesCipher(key); des.encrypt(challenge, 0, challenge, 0); des.encrypt(challenge, 8, challenge, 8); os.write(challenge); int authResult = is.readInt(); switch (authResult) { case VncAuthOK: System.out.println("VNC authentication succeeded"); authenticationDone = true; break; case VncAuthFailed: System.out.println("VNC authentication failed"); break; case VncAuthTooMany: throw new IOException("VNC authentication failed - " + "too many tries"); default: throw new IOException("Unknown VNC authentication result " + authResult); } break; } return authenticationDone; } // // Write our protocol version message // void writeVersionMsg() throws IOException { byte[] b = new byte[12]; versionMsg.getBytes(0, 12, b, 0); os.write(b); } // // Find out the authentication scheme. // int readAuthScheme() throws IOException { int authScheme = is.readInt(); switch (authScheme) { case ConnFailed: int reasonLen = is.readInt(); byte[] reason = new byte[reasonLen]; is.readFully(reason); Page 2 of 8 RFBProtocol.java 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 5/7/2005 19:34 throw new IOException(new String(reason, 0)); case NoAuth: case VncAuth: return authScheme; default: throw new IOException("Unknown authentication scheme from RFB " + "server " + authScheme); } } // // Do the rest of the protocol initialisation. // public void doProtocolInitialisation(int[] encodings, int nEncodings) throws IOException { System.out.println("sending client init"); writeClientInit(); readServerInit(); System.out.println("Desktop name is " + desktopName); System.out.println("Desktop size is " + framebufferWidth + " x " + framebufferHeight); setEncodings(encodings, nEncodings); } // // setEncodings() - send the current encodings from the options frame // to the RFB server. // void setEncodings(int[] encodings, int nEncodings) { try { if (inNormalProtocol) { writeSetEncodings(encodings, nEncodings); } } catch (Exception e) { e.printStackTrace(); } } // // Write the client initialisation message // void writeClientInit() throws IOException { if (COMPARTILHAR_DESKTOP) { os.write(1); } else { os.write(0); } } // // Read the server initialisation message // public String desktopName; public int framebufferWidth, framebufferHeight; int bitsPerPixel, depth; boolean bigEndian, trueColour; int redMax, greenMax, blueMax, redShift, greenShift, blueShift; void readServerInit() throws IOException { framebufferWidth = is.readUnsignedShort(); framebufferHeight = is.readUnsignedShort(); bitsPerPixel = is.readUnsignedByte(); depth = is.readUnsignedByte(); bigEndian = (is.readUnsignedByte() != 0); trueColour = (is.readUnsignedByte() != 0); redMax = is.readUnsignedShort(); greenMax = is.readUnsignedShort(); blueMax = is.readUnsignedShort(); redShift = is.readUnsignedByte(); greenShift = is.readUnsignedByte(); blueShift = is.readUnsignedByte(); byte[] pad = new byte[3]; is.read(pad); int nameLength = is.readInt(); byte[] name = new byte[nameLength]; is.readFully(name); desktopName = new String(name, 0); Page 3 of 8 RFBProtocol.java 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 5/7/2005 19:34 inNormalProtocol = true; } // // Read the server message type // int readServerMessageType() throws IOException { return is.read(); } // // Read a FramebufferUpdate message // int updateNRects; void readFramebufferUpdate() throws IOException { is.readByte(); updateNRects = is.readUnsignedShort(); } // Read a FramebufferUpdate rectangle header int updateRectX, updateRectY, updateRectW, updateRectH, updateRectEncoding; void readFramebufferUpdateRectHdr() throws IOException { updateRectX = is.readUnsignedShort(); updateRectY = is.readUnsignedShort(); updateRectW = is.readUnsignedShort(); updateRectH = is.readUnsignedShort(); updateRectEncoding = is.readInt(); if ((updateRectX + updateRectW > framebufferWidth) || (updateRectY + updateRectH > framebufferHeight)) { throw new IOException("Framebuffer update rectangle too large: " + updateRectW + "x" + updateRectH + " at (" + updateRectX + "," + updateRectY + ")"); } } // Read CopyRect source X and Y. int copyRectSrcX, copyRectSrcY; void readCopyRect() throws IOException { copyRectSrcX = is.readUnsignedShort(); copyRectSrcY = is.readUnsignedShort(); } // // Read a ServerCutText message // String readServerCutText() throws IOException { byte[] pad = new byte[3]; is.read(pad); int len = is.readInt(); byte[] text = new byte[len]; is.readFully(text); return new String(text, 0); } // // Write a FramebufferUpdateRequest message // void writeFramebufferUpdateRequest(int x, int y, int w, int h, boolean incremental) throws IOException { byte[] b = new byte[10]; b[0] = (byte) FramebufferUpdateRequest; b[1] = (byte) (incremental ? 1 : 0); b[2] = (byte) ((x >> 8) & 0xff); b[3] = (byte) (x & 0xff); b[4] = (byte) ((y >> 8) & 0xff); b[5] = (byte) (y & 0xff); b[6] = (byte) ((w >> 8) & 0xff); b[7] = (byte) (w & 0xff); b[8] = (byte) ((h >> 8) & 0xff); b[9] = (byte) (h & 0xff); os.write(b); } // // Write a SetPixelFormat message // Page 4 of 8 RFBProtocol.java 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 5/7/2005 19:34 void writeSetPixelFormat(int bitsPerPixel, int depth, boolean bigEndian, boolean trueColour, int redMax, int greenMax, int blueMax, int redShift, int greenShift, int blueShift) throws IOException { byte[] b = new byte[20]; b[0] = (byte) SetPixelFormat; b[4] = (byte) bitsPerPixel; b[5] = (byte) depth; b[6] = (byte) (bigEndian ? 1 : 0); b[7] = (byte) (trueColour ? 1 : 0); b[8] = (byte) ((redMax >> 8) & 0xff); b[9] = (byte) (redMax & 0xff); b[10] = (byte) ((greenMax >> 8) & 0xff); b[11] = (byte) (greenMax & 0xff); b[12] = (byte) ((blueMax >> 8) & 0xff); b[13] = (byte) (blueMax & 0xff); b[14] = (byte) redShift; b[15] = (byte) greenShift; b[16] = (byte) blueShift; os.write(b); } // // Write a FixColourMapEntries message. The values in the red, green and // blue arrays are from 0 to 65535. // void writeFixColourMapEntries(int firstColour, int nColours, int[] red, int[] green, int[] blue) throws IOException { byte[] b = new byte[6 + nColours * 6]; b[0] = (byte) FixColourMapEntries; b[2] = (byte) ((firstColour >> 8) & 0xff); b[3] = (byte) (firstColour & 0xff); b[4] = (byte) ((nColours >> 8) & 0xff); b[5] = (byte) (nColours & 0xff); for (int i = 0; i < nColours; i++) { b[6 + i * 6] = (byte) ((red[i] >> 8) & 0xff); b[6 + i * 6 + 1] = (byte) (red[i] & 0xff); b[6 + i * 6 + 2] = (byte) ((green[i] >> 8) & 0xff); b[6 + i * 6 + 3] = (byte) (green[i] & 0xff); b[6 + i * 6 + 4] = (byte) ((blue[i] >> 8) & 0xff); b[6 + i * 6 + 5] = (byte) (blue[i] & 0xff); } os.write(b); } // // Write a SetEncodings message // void writeSetEncodings(int[] encs, int len) throws IOException { byte[] b = new byte[4 + 4 * len]; b[0] = (byte) SetEncodings; b[2] = (byte) ((len >> 8) & 0xff); b[3] = (byte) (len & 0xff); for (int i = 0; i < len; i++) { b[4 + 4 * i] = (byte) ((encs[i] >> 24) & 0xff); b[5 + 4 * i] = (byte) ((encs[i] >> 16) & 0xff); b[6 + 4 * i] = (byte) ((encs[i] >> 8) & 0xff); b[7 + 4 * i] = (byte) (encs[i] & 0xff); } os.write(b); } // // Write a ClientCutText message // public void writeClientCutText(String text) throws IOException { byte[] b = new byte[8 + text.length()]; b[0] = (byte) ClientCutText; b[4] = (byte) ((text.length() >> 24) & 0xff); b[5] = (byte) ((text.length() >> 16) & 0xff); b[6] = (byte) ((text.length() >> 8) & 0xff); b[7] = (byte) (text.length() & 0xff); text.getBytes(0, text.length(), b, 8); os.write(b); } // // A buffer for putting pointer and keyboard events before being sent. This Page 5 of 8 RFBProtocol.java 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 5/7/2005 19:34 // is to ensure that multiple RFB events generated from a single Java Event // will all be sent in a single network packet. The maximum possible // length is 4 modifier down events, a single key event followed by 4 // modifier up events i.e. 9 key events or 72 bytes. // byte[] eventBuf = new byte[72]; int eventBufLen; // // Write a pointer event message. We may need to send modifier key events // around it to set the correct modifier state. Also buttons 2 and 3 are // represented as having ALT and META modifiers respectively. // int pointerMask = 0; void writePointerEvent(int tipoEventoMouse, int botao, int x, int y) throws IOException { int mask2 = 4; if (tipoEventoMouse == MouseEvent.MOUSE_PRESSED) { if (botao == MouseEvent.BUTTON2) { pointerMask = mask2; } else { pointerMask = 1; } } else { if (tipoEventoMouse == MouseEvent.MOUSE_RELEASED) { pointerMask = 0; } } eventBufLen = 0; if (x < 0) x = 0; if (y < 0) y = 0; eventBuf[eventBufLen++] = (byte) PointerEvent; eventBuf[eventBufLen++] = (byte) pointerMask; eventBuf[eventBufLen++] = (byte) ((x >> 8) & 0xff); eventBuf[eventBufLen++] = (byte) (x & 0xff); eventBuf[eventBufLen++] = (byte) ((y >> 8) & 0xff); eventBuf[eventBufLen++] = (byte) (y & 0xff); if (pointerMask == 0) { writeModifierKeyEvents(0); } os.write(eventBuf, 0, eventBufLen); } // // Write a key event message. We may need to send modifier key events // around it to set the correct modifier state. Also we need to translate // from the Java key values to the X keysym values used by the RFB protocol. // public void sendCtrlAltDel() { try { Event ctrlAltDelEvent = new Event(null, 0, null); ctrlAltDelEvent.key = 127; ctrlAltDelEvent.modifiers = Event.CTRL_MASK | Event.ALT_MASK; ctrlAltDelEvent.id = Event.KEY_PRESS; writeKeyEvent(ctrlAltDelEvent); ctrlAltDelEvent.id = Event.KEY_RELEASE; writeKeyEvent(ctrlAltDelEvent); } catch (Exception e) { e.printStackTrace(); } } void writeKeyEvent(Event evt) throws IOException { int key = evt.key; boolean down = false; if ((evt.id == Event.KEY_PRESS) || (evt.id == Event.KEY_ACTION)) down = true; if ((evt.id == Event.KEY_ACTION) || (evt.id == Event.KEY_ACTION_RELEASE)) { // // A KEY_ACTION event should be one of the following. If not then // just // ignore the event. // Page 6 of 8 RFBProtocol.java 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 5/7/2005 19:34 switch (key) { case Event.HOME: key = 0xff50; break; case Event.LEFT: key = 0xff51; break; case Event.UP: key = 0xff52; break; case Event.RIGHT: key = 0xff53; break; case Event.DOWN: key = 0xff54; break; case Event.PGUP: key = 0xff55; break; case Event.PGDN: key = 0xff56; break; case Event.END: key = 0xff57; break; case Event.F1: key = 0xffbe; break; case Event.F2: key = 0xffbf; break; case Event.F3: key = 0xffc0; break; case Event.F4: key = 0xffc1; break; case Event.F5: key = 0xffc2; break; case Event.F6: key = 0xffc3; break; case Event.F7: key = 0xffc4; break; case Event.F8: key = 0xffc5; break; case Event.F9: key = 0xffc6; break; case Event.F10: key = 0xffc7; break; case Event.F11: key = 0xffc8; break; case Event.F12: key = 0xffc9; break; default: return; } } else { // // A "normal" key press. Ordinary ASCII characters go straight // through. // For CTRL-<letter>, CTRL is sent separately so just send <letter>. // Backspace, tab, return, escape and delete have special keysyms. // Anything else we ignore. // if (key < 32) { if ((evt.modifiers & Event.CTRL_MASK) != 0) { key += 96; } else { Page 7 of 8 RFBProtocol.java 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 5/7/2005 19:34 switch (key) { case 8: key = 0xff08; break; case 9: key = 0xff09; break; case 10: key = 0xff0d; break; case 27: key = 0xff1b; break; } } } else if (key >= 127) { if (key == 127) { key = 0xffff; } else { // JDK1.1 on X incorrectly passes some keysyms straight // through, so // we do too. JDK1.1.4 seems to have fixed this. if ((key < 0xff00) || (key > 0xffff)) return; } } } eventBufLen = 0; writeModifierKeyEvents(evt.modifiers); writeKeyEvent(key, down); // // Always release all modifiers after an "up" event // if (!down) { writeModifierKeyEvents(0); } os.write(eventBuf, 0, eventBufLen); } // // Add a raw key event with the given X keysym to eventBuf. // void writeKeyEvent(int keysym, boolean down) throws IOException { eventBuf[eventBufLen++] = (byte) KeyEvent; eventBuf[eventBufLen++] = (byte) (down ? 1 : 0); eventBuf[eventBufLen++] = (byte) 0; eventBuf[eventBufLen++] = (byte) 0; eventBuf[eventBufLen++] = (byte) ((keysym >> 24) & 0xff); eventBuf[eventBufLen++] = (byte) ((keysym >> 16) & 0xff); eventBuf[eventBufLen++] = (byte) ((keysym >> 8) & 0xff); eventBuf[eventBufLen++] = (byte) (keysym & 0xff); } // // Write key events to set the correct modifier state. // int oldModifiers; void writeModifierKeyEvents(int newModifiers) throws IOException { if ((newModifiers & Event.CTRL_MASK) != (oldModifiers & Event.CTRL_MASK)) writeKeyEvent(0xffe3, (newModifiers & Event.CTRL_MASK) != 0); if ((newModifiers & Event.SHIFT_MASK) != (oldModifiers & Event.SHIFT_MASK)) writeKeyEvent(0xffe1, (newModifiers & Event.SHIFT_MASK) != 0); if ((newModifiers & Event.META_MASK) != (oldModifiers & Event.META_MASK)) writeKeyEvent(0xffe7, (newModifiers & Event.META_MASK) != 0); if ((newModifiers & Event.ALT_MASK) != (oldModifiers & Event.ALT_MASK)) writeKeyEvent(0xffe9, (newModifiers & Event.ALT_MASK) != 0); oldModifiers = newModifiers; } } Page 8 of 8 TelaCelular.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 5/7/2005 19:35 package app.rede; public class TelaCelular { private int altura; private int largura; public int getAltura() { return altura; } public void setAltura(int altura) { this.altura = altura; } public int getLargura() { return largura; } public void setLargura(int largura) { this.largura = largura; } } Page 1 of 1 TratadorDeComandos.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:35 package app.rede; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.awt.image.DirectColorModel; import java.io.IOException; import app.util.AnimatedMemoryImageSource; import app.util.Log; import app.util.TratadorDeImagem; import app.util.TratadorDoMouse; public class TratadorDeComandos extends Thread { private String senhaLocal; private TratadorDeImagem tratadorDeImagens; private TratadorDoMouse tratadorDoMouse; private int portaLocal; private String senhaExterna; private boolean botao1DoMousePressionado; private boolean botao2DoMousePressionado; private int portaExterna; private LeitorDeComando leitor; int largura = 0; int altura = 0; private BufferedImage imagemOriginal; private BufferedImage imagemCelular; private int[] encodings = new int[10]; private RFBProtocol protocoloRFB; private DirectColorModel cm; private Color[] colors; private byte[] pixels; private Graphics pig; private Graphics sg; private int comandoDoCelular; private Image paintImage; private boolean connected; private boolean needToResetClip; private int nVezes = 0; private String hostRodandoVNC; private boolean mouseAtivado; public TratadorDeComandos(String _hostRodandoVNC, String _senhaLocal, int _portaLocal, String _senhaExterna, int _portaExterna) { senhaLocal = _senhaLocal; senhaExterna = _senhaExterna; portaExterna = _portaExterna; portaLocal = _portaLocal; hostRodandoVNC = _hostRodandoVNC; } private void aguardaConexaoComCelular() { try { leitor = new LeitorDeComando(portaExterna); Log.info("Aguardando conexao na porta " + portaExterna); TelaCelular telaCelular = leitor.getTelaCelular(); largura = telaCelular.getLargura(); altura = telaCelular.getAltura(); } catch (Exception e) { e.printStackTrace(); } } public void run() { Log.info("Iniciando tratamento de comandos"); while (true) { try { aguardaConexaoComCelular(); // Fazendo conexão local protocoloRFB = new RFBProtocol(hostRodandoVNC, portaLocal); // protocoloRFB = new RFBProtocol("localhost", portaLocal); protocoloRFB.connectAndAuthenticate(senhaLocal); protocoloRFB.writeClientInit(); protocoloRFB.readServerInit(); Page 1 of 4 TratadorDeComandos.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 5/7/2005 19:35 Log.info("Nome: " + protocoloRFB.desktopName); Log.info("Resolução: " + protocoloRFB.framebufferWidth + " x " + protocoloRFB.framebufferHeight); protocoloRFB.setEncodings(encodings, 1); protocoloRFB.writeSetPixelFormat(8, 8, false, true, 7, 7, 3, 0, 3, 6); cm = new DirectColorModel(8, 7, (7 << 3), (3 << 6)); colors = new Color[256]; for (int i = 0; i < 256; i++) { colors[i] = new Color(cm.getRGB(i)); } pixels = new byte[protocoloRFB.framebufferWidth * protocoloRFB.framebufferHeight]; AnimatedMemoryImageSource amis = new AnimatedMemoryImageSource( protocoloRFB.framebufferWidth, protocoloRFB.framebufferHeight, cm, pixels); Image rawPixelsImage = Toolkit.getDefaultToolkit().createImage( amis); imagemOriginal = new BufferedImage( protocoloRFB.framebufferWidth, protocoloRFB.framebufferHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g = imagemOriginal.createGraphics(); pig = imagemOriginal.createGraphics(); sg = imagemOriginal.createGraphics(); processaProtocolo(); Log.info("Finalizando conexao"); leitor.fechaFechaConexao(); } catch (IOException e1) { e1.printStackTrace(); } } } private synchronized void processaProtocolo() throws IOException { protocoloRFB.writeFramebufferUpdateRequest(0, 0, protocoloRFB.framebufferWidth, protocoloRFB.framebufferHeight, true); while (comandoDoCelular != DP.FINALIZAR_CONEXAO) { int msgType = protocoloRFB.readServerMessageType(); Log.info("Mensagem do Servidor: " + msgType); // --------------------------------switch (msgType) { case RFBProtocol.FramebufferUpdate: protocoloRFB.readFramebufferUpdate(); for (int i = 0; i < protocoloRFB.updateNRects; i++) { protocoloRFB.readFramebufferUpdateRectHdr(); switch (protocoloRFB.updateRectEncoding) { case RFBProtocol.EncodingRaw: desenhaImagem(protocoloRFB.updateRectX, protocoloRFB.updateRectY, protocoloRFB.updateRectW, protocoloRFB.updateRectH); break; default: throw new IOException("Unknown RFB rectangle encoding " + protocoloRFB.updateRectEncoding); } } break; case RFBProtocol.SetColourMapEntries: throw new IOException( "Can't handle SetColourMapEntries message"); case RFBProtocol.Bell: System.out.print((char) 7); break; case RFBProtocol.ServerCutText: String s = protocoloRFB.readServerCutText(); break; case -1: // EOF, disconnect connected = false; break; default: throw new IOException("Unknown RFB message type " + msgType); } // --------------------------------Page 2 of 4 TratadorDeComandos.java 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 5/7/2005 19:35 comandoDoCelular = leitor.getComando(); switch (comandoDoCelular) { case DP.CMD_ZOOM_MENOS: tratadorDeImagens.zoomMenos(tratadorDoMouse); break; case DP.CMD_ZOOM_MAIS: tratadorDeImagens.zoomMais(tratadorDoMouse); break; case DP.CMD_TELA_PARA_CIMA: tratadorDeImagens.moveParaCima(); break; case DP.CMD_TELA_PARA_BAIXO: tratadorDeImagens.moveParaBaixo(); break; case DP.CMD_TELA_PARA_ESQUERDA: tratadorDeImagens.moveParaEsquerda(); break; case DP.CMD_TELA_PARA_DIREITA: tratadorDeImagens.moveParaDireita(); break; case DP.CMD_MOUSE_PARA_BAIXO: tratadorDoMouse.moveParaBaixo(); processaEventoDoMouse(MouseEvent.MOUSE_MOVED, 0); break; case DP.CMD_MOUSE_PARA_CIMA: tratadorDoMouse.moveParaCima(); processaEventoDoMouse(MouseEvent.MOUSE_MOVED, 0); break; case DP.CMD_MOUSE_PARA_DIREITA: tratadorDoMouse.moveParaDireita(); processaEventoDoMouse(MouseEvent.MOUSE_MOVED, 0); break; case DP.CMD_MOUSE_PARA_ESQUERDA: tratadorDoMouse.moveParaEsquerda(); processaEventoDoMouse(MouseEvent.MOUSE_MOVED, 0); break; case DP.CMD_BT_MOUSE1: if (botao1DoMousePressionado) { processaEventoDoMouse(MouseEvent.MOUSE_RELEASED, MouseEvent.BUTTON1); } else { processaEventoDoMouse(MouseEvent.MOUSE_PRESSED, MouseEvent.BUTTON1); } botao1DoMousePressionado = !botao1DoMousePressionado; break; case DP.CMD_BT_MOUSE2: if (botao2DoMousePressionado) { processaEventoDoMouse(MouseEvent.MOUSE_RELEASED, MouseEvent.BUTTON2); } else { processaEventoDoMouse(MouseEvent.MOUSE_PRESSED, MouseEvent.BUTTON2); } botao2DoMousePressionado = !botao2DoMousePressionado; break; case DP.INICIA_TRATADOR_DE_IMAGENS: iniciaTratador(); break; default: break; } sendImage(); // TODO ver tempo entre atualizações protocoloRFB.writeFramebufferUpdateRequest(0, 0, protocoloRFB.framebufferWidth, protocoloRFB.framebufferHeight, false); /* * long numMillisecondsToSleep = 250; // 1/4 segundos try { * Thread.sleep(numMillisecondsToSleep); } catch * (InterruptedException e) { e.printStackTrace(); } */ } } private void desenhaImagem(int x, int y, int w, int h) throws IOException { Page 3 of 4 TratadorDeComandos.java 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 5/7/2005 19:35 // TODO verificar se precisa desenhar cada um Log.info("Desenhando x=" + x + " y=" + y + " w=" + w + " h=" + h); Graphics2D g = imagemOriginal.createGraphics(); for (int j = 0; j < protocoloRFB.framebufferHeight; j++) { for (int k = 0; k < protocoloRFB.framebufferWidth; k++) { int pixel = protocoloRFB.is.read(); g.setColor(colors[pixel]); g.fillRect(k, j, 1, 1); } } g.drawImage(imagemOriginal, 0, 0, null); if (imagemCelular != null) { imagemCelular.getGraphics().drawImage(imagemOriginal, 0, 0, tratadorDeImagens.getLargura(), tratadorDeImagens.getAltura(), tratadorDeImagens.getRetX(), tratadorDeImagens.getRetY(), tratadorDeImagens.getRetX2(), tratadorDeImagens.getRetY2(), null); } nVezes++; } public synchronized void iniciaTratador() { tratadorDeImagens = new TratadorDeImagem(largura, altura, protocoloRFB.framebufferWidth, protocoloRFB.framebufferHeight); tratadorDoMouse = new TratadorDoMouse(protocoloRFB.framebufferWidth, protocoloRFB.framebufferHeight); imagemCelular = new BufferedImage(tratadorDeImagens.getLargura(), tratadorDeImagens.getAltura(), BufferedImage.TYPE_INT_RGB); } private synchronized void sendImage() { try { leitor.enviaImagem(imagemCelular); } catch (Exception e) { e.printStackTrace(); } } public void processaEventoDoMouse(int tipoEvento, int botao) { if (protocoloRFB.inNormalProtocol) { synchronized (protocoloRFB) { try { protocoloRFB.writePointerEvent(tipoEvento, botao, tratadorDoMouse.getX(), tratadorDoMouse.getY()); } catch (Exception e) { e.printStackTrace(); } protocoloRFB.notify(); } } } } Page 4 of 4 PainelDeAutenticacao.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:36 package app.ui; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JTextField; import app.rede.TratadorDeComandos; import app.util.Log; public class PainelDeAutenticacao extends JFrame { private javax.swing.JPanel jContentPane = null; private JTextField txtSenhaLocal = null; private JButton jButton = null; private JLabel jLabel = null; private JTextField txtSenhaExterna = null; private JLabel jLabel1 = null; private JTextField txtPortaLocal = null; private JTextField txtPortaExterna = null; private JLabel jLabel2 = null; private JLabel jLabel3 = null; private JButton jButton1 = null; private TratadorDeComandos tratadorDeComandos; private JTextField txtHost = null; private JLabel jLabel4 = null; private JTextField getTxtSenhaLocal() { if (txtSenhaLocal == null) { txtSenhaLocal = new JTextField(); txtSenhaLocal.setBounds(136, 45, 146, 20); txtSenhaLocal.setText("testevnc"); } return txtSenhaLocal; } private JButton getJButton() { if (jButton == null) { jButton = new JButton(); jButton.setBounds(184, 183, 95, 26); jButton.setText("Iniciar"); jButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { tratadorDeComandos = new TratadorDeComandos(txtHost .getText(), txtSenhaLocal.getText(), Integer .parseInt(txtPortaLocal.getText()), txtSenhaExterna .getText(), Integer.parseInt(txtPortaExterna .getText())); tratadorDeComandos.start(); jButton.setEnabled(false); } }); } return jButton; } private void iniciarServidor() { } private JTextField getTxtSenhaExterna() { if (txtSenhaExterna == null) { txtSenhaExterna = new JTextField(); txtSenhaExterna.setBounds(135, 102, 150, 20); txtSenhaExterna.setText("x"); } return txtSenhaExterna; } private JTextField getTxtPortaLocal() { if (txtPortaLocal == null) { txtPortaLocal = new JTextField(); txtPortaLocal.setBounds(136, 68, 66, 20); txtPortaLocal.setText("5900"); } return txtPortaLocal; } Page 1 of 3 PainelDeAutenticacao.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 5/7/2005 19:36 private JTextField getTxtPortaExterna() { if (txtPortaExterna == null) { txtPortaExterna = new JTextField(); txtPortaExterna.setBounds(136, 128, 69, 20); txtPortaExterna.setText("8080"); } return txtPortaExterna; } private JButton getJButton1() { if (jButton1 == null) { jButton1 = new JButton(); jButton1.setBounds(61, 183, 92, 27); jButton1.setText("Fechar"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { Log.info("Saindo da aplicação"); System.exit(0); } }); } return jButton1; } /** * This method initializes jTextField * * @return javax.swing.JTextField */ private JTextField getTxtHost() { if (txtHost == null) { txtHost = new JTextField(); txtHost.setBounds(136, 19, 144, 20); txtHost.setText("192.168.152.38"); } return txtHost; } public static void main(String[] args) { PainelDeAutenticacao painel = new PainelDeAutenticacao(); painel.initialize(); } private void initialize() { this.setSize(365, 270); this.setContentPane(getJContentPane()); this.setTitle("VNC para celular - módulo PC"); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Log.info("fechando aplicação"); System.exit(0); } }); this.show(); } private javax.swing.JPanel getJContentPane() { if (jContentPane == null) { jLabel4 = new JLabel(); jLabel3 = new JLabel(); jLabel2 = new JLabel(); jLabel1 = new JLabel(); jLabel = new JLabel(); jContentPane = new javax.swing.JPanel(); jContentPane.setLayout(null); jLabel.setBounds(79, 45, 45, 20); jLabel.setText("Senha:"); jLabel1.setBounds(28, 98, 92, 25); jLabel1.setText("Senha Externa:"); jLabel2.setBounds(82, 71, 39, 16); jLabel2.setText("Porta:"); jLabel3.setBounds(30, 129, 95, 17); jLabel3.setText("Porta Externa:"); jLabel4.setBounds(62, 19, 59, 17); jLabel4.setText("Host VNC:"); jContentPane.add(getTxtSenhaLocal(), null); Page 2 of 3 PainelDeAutenticacao.java 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 5/7/2005 19:36 jContentPane.add(getJButton(), null); jContentPane.add(jLabel, null); jContentPane.add(getTxtSenhaExterna(), null); jContentPane.add(jLabel1, null); jContentPane.add(getTxtPortaLocal(), null); jContentPane.add(getTxtPortaExterna(), null); jContentPane.add(jLabel2, null); jContentPane.add(jLabel3, null); jContentPane.add(getJButton1(), null); jContentPane.add(getTxtHost(), null); jContentPane.add(jLabel4, null); } return jContentPane; } } // @jve:decl-index=0:visual-constraint="10,10" Page 3 of 3 AnimatedMemoryImageSource.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 5/7/2005 19:38 // // Código com licensa GPL; // Retirado do site http://www.tightvnc.com/ // package app.util; import java.awt.image.*; public class AnimatedMemoryImageSource implements ImageProducer { int width; int height; ColorModel cm; byte[] pixels; ImageConsumer ic; public AnimatedMemoryImageSource(int w, int h, ColorModel c, byte[] p) { width = w; height = h; cm = c; pixels = p; } public void addConsumer(ImageConsumer c) { if (ic == c) return; if (ic != null) { ic.imageComplete(ImageConsumer.IMAGEERROR); } ic = c; ic.setDimensions(width, height); ic.setColorModel(cm); ic.setHints(ImageConsumer.RANDOMPIXELORDER); ic.setPixels(0, 0, width, height, cm, pixels, 0, width); ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); } public boolean isConsumer(ImageConsumer c) { return (ic == c); } public void removeConsumer(ImageConsumer c) { if (ic == c) ic = null; } public void requestTopDownLeftRightResend(ImageConsumer c) { } public void startProduction(ImageConsumer c) { addConsumer(c); } void newPixels(int x, int y, int w, int h) { if (ic != null) { ic.setPixels(x, y, w, h, cm, pixels, width * y + x, width); ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); } } } Page 1 of 1 DesCipher.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:38 //Boa parte do código foi desenvolvido por //Retirado do site www.acme.com package app.util; Dave Zimmerman <[email protected]> public class DesCipher { public DesCipher(byte[] key) { setKey(key); } // Key routines. private int[] encryptKeys = new int[32]; private int[] decryptKeys = new int[32]; // / Set the key. public void setKey(byte[] key) { deskey(key, true, encryptKeys); deskey(key, false, decryptKeys); } // Turn an 8-byte key into internal keys. private void deskey(byte[] keyBlock, boolean encrypting, int[] KnL) { int i, j, l, m, n; int[] pc1m = new int[56]; int[] pcr = new int[56]; int[] kn = new int[32]; for (j = 0; j < 56; ++j) { l = pc1[j]; m = l & 07; pc1m[j] = ((keyBlock[l >>> 3] & bytebit[m]) != 0) ? 1 : 0; } for (i = 0; i < 16; ++i) { if (encrypting) m = i << 1; else m = (15 - i) << 1; n = m + 1; kn[m] = kn[n] = 0; for (j = 0; j < 28; ++j) { l = j + totrot[i]; if (l < 28) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for (j = 28; j < 56; ++j) { l = j + totrot[i]; if (l < 56) pcr[j] = pc1m[l]; else pcr[j] = pc1m[l - 28]; } for (j = 0; j < 24; ++j) { if (pcr[pc2[j]] != 0) kn[m] |= bigbyte[j]; if (pcr[pc2[j + 24]] != 0) kn[n] |= bigbyte[j]; } } cookey(kn, KnL); } private int int int for void cookey(int[] raw, int KnL[]) { raw0, raw1; rawi, KnLi; i; (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) { raw0 = raw[rawi++]; raw1 = raw[rawi++]; KnL[KnLi] = (raw0 & 0x00fc0000) << 6; KnL[KnLi] |= (raw0 & 0x00000fc0) << 10; KnL[KnLi] |= (raw1 & 0x00fc0000) >>> 10; KnL[KnLi] |= (raw1 & 0x00000fc0) >>> 6; ++KnLi; KnL[KnLi] = (raw0 & 0x0003f000) << 12; KnL[KnLi] |= (raw0 & 0x0000003f) << 16; KnL[KnLi] |= (raw1 & 0x0003f000) >>> 4; KnL[KnLi] |= (raw1 & 0x0000003f); Page 1 of 5 DesCipher.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 5/7/2005 19:38 ++KnLi; } } // Block encryption routines. private int[] tempInts = new int[2]; // / Encrypt a block of eight bytes. public void encrypt(byte[] clearText, int clearOff, byte[] cipherText, int cipherOff) { squashBytesToInts(clearText, clearOff, tempInts, 0, 2); des(tempInts, tempInts, encryptKeys); spreadIntsToBytes(tempInts, 0, cipherText, cipherOff, 2); } // / Decrypt a block of eight bytes. public void decrypt(byte[] cipherText, int cipherOff, byte[] clearText, int clearOff) { squashBytesToInts(cipherText, cipherOff, tempInts, 0, 2); des(tempInts, tempInts, decryptKeys); spreadIntsToBytes(tempInts, 0, clearText, clearOff, 2); } // The DES function. private void des(int[] inInts, int[] outInts, int[] keys) { int fval, work, right, leftt; int round; int keysi = 0; leftt = inInts[0]; right = inInts[1]; work = ((leftt >>> 4) ^ right) & 0x0f0f0f0f; right ^= work; leftt ^= (work << 4); work = ((leftt >>> 16) ^ right) & 0x0000ffff; right ^= work; leftt ^= (work << 16); work = ((right >>> 2) ^ leftt) & 0x33333333; leftt ^= work; right ^= (work << 2); work = ((right >>> 8) ^ leftt) & 0x00ff00ff; leftt ^= work; right ^= (work << 8); right = (right << 1) | ((right >>> 31) & 1); work = (leftt ^ right) & 0xaaaaaaaa; leftt ^= work; right ^= work; leftt = (leftt << 1) | ((leftt >>> 31) & 1); for (round = 0; round < 8; ++round) { work = (right << 28) | (right >>> 4); work ^= keys[keysi++]; fval = SP7[work & 0x0000003f]; fval |= SP5[(work >>> 8) & 0x0000003f]; fval |= SP3[(work >>> 16) & 0x0000003f]; fval |= SP1[(work >>> 24) & 0x0000003f]; work = right ^ keys[keysi++]; fval |= SP8[work & 0x0000003f]; fval |= SP6[(work >>> 8) & 0x0000003f]; fval |= SP4[(work >>> 16) & 0x0000003f]; fval |= SP2[(work >>> 24) & 0x0000003f]; leftt ^= fval; work = (leftt << 28) | (leftt >>> 4); work ^= keys[keysi++]; fval = SP7[work & 0x0000003f]; fval |= SP5[(work >>> 8) & 0x0000003f]; fval |= SP3[(work >>> 16) & 0x0000003f]; fval |= SP1[(work >>> 24) & 0x0000003f]; work = leftt ^ keys[keysi++]; fval |= SP8[work & 0x0000003f]; fval |= SP6[(work >>> 8) & 0x0000003f]; fval |= SP4[(work >>> 16) & 0x0000003f]; fval |= SP2[(work >>> 24) & 0x0000003f]; right ^= fval; } right = (right << 31) | (right >>> 1); work = (leftt ^ right) & 0xaaaaaaaa; leftt ^= work; right ^= work; Page 2 of 5 DesCipher.java 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 5/7/2005 19:38 leftt = (leftt << 31) | (leftt >>> 1); work = ((leftt >>> 8) ^ right) & 0x00ff00ff; right ^= work; leftt ^= (work << 8); work = ((leftt >>> 2) ^ right) & 0x33333333; right ^= work; leftt ^= (work << 2); work = ((right >>> 16) ^ leftt) & 0x0000ffff; leftt ^= work; right ^= (work << 16); work = ((right >>> 4) ^ leftt) & 0x0f0f0f0f; leftt ^= work; right ^= (work << 4); outInts[0] = right; outInts[1] = leftt; } // Tables, permutations, S-boxes, etc. private static byte[] bytebit = { (byte) 0x01, (byte) 0x02, (byte) 0x04, (byte) 0x08, (byte) 0x10, (byte) 0x20, (byte) 0x40, (byte) 0x80 }; private static int[] bigbyte = { 0x800000, 0x400000, 0x200000, 0x100000, 0x080000, 0x040000, 0x020000, 0x010000, 0x008000, 0x004000, 0x002000, 0x001000, 0x000800, 0x000400, 0x000200, 0x000100, 0x000080, 0x000040, 0x000020, 0x000010, 0x000008, 0x000004, 0x000002, 0x000001 }; private static byte[] pc1 = { (byte) 56, (byte) 48, (byte) 40, (byte) 32, (byte) 24, (byte) 16, (byte) 8, (byte) 0, (byte) 57, (byte) 49, (byte) 41, (byte) 33, (byte) 25, (byte) 17, (byte) 9, (byte) 1, (byte) 58, (byte) 50, (byte) 42, (byte) 34, (byte) 26, (byte) 18, (byte) 10, (byte) 2, (byte) 59, (byte) 51, (byte) 43, (byte) 35, (byte) 62, (byte) 54, (byte) 46, (byte) 38, (byte) 30, (byte) 22, (byte) 14, (byte) 6, (byte) 61, (byte) 53, (byte) 45, (byte) 37, (byte) 29, (byte) 21, (byte) 13, (byte) 5, (byte) 60, (byte) 52, (byte) 44, (byte) 36, (byte) 28, (byte) 20, (byte) 12, (byte) 4, (byte) 27, (byte) 19, (byte) 11, (byte) 3 }; private static int[] totrot = { 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28 }; private static byte[] pc2 = { (byte) 13, (byte) 16, (byte) 10, (byte) 23, (byte) 0, (byte) 4, (byte) 2, (byte) 27, (byte) 14, (byte) 5, (byte) 20, (byte) 9, (byte) 22, (byte) 18, (byte) 11, (byte) 3, (byte) 25, (byte) 7, (byte) 15, (byte) 6, (byte) 26, (byte) 19, (byte) 12, (byte) 1, (byte) 40, (byte) 51, (byte) 30, (byte) 36, (byte) 46, (byte) 54, (byte) 29, (byte) 39, (byte) 50, (byte) 44, (byte) 32, (byte) 47, (byte) 43, (byte) 48, (byte) 38, (byte) 55, (byte) 33, (byte) 52, (byte) 45, (byte) 41, (byte) 49, (byte) 35, (byte) 28, (byte) 31, }; private static int[] SP1 = { 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; private static int[] SP2 = { 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; private static int[] SP3 = { 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, Page 3 of 5 DesCipher.java 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 private private private private private 5/7/2005 19:38 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; static int[] SP4 = { 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; static int[] SP5 = { 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; static int[] SP6 = { 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; static int[] SP7 = { 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; static int[] SP8 = { 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, Page 4 of 5 DesCipher.java 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 5/7/2005 19:38 0x10040000, 0x10040040, 0x00000000, 0x10041040, 0x10001000, 0x10001040, 0x00041000, 0x00001040, 0x10041000 }; 0x10000000, 0x00040040, 0x00000000, 0x00001040, 0x00040000, 0x10000040, 0x10041040, 0x00040040, 0x10001040, 0x10040000, 0x00041000, 0x10000000, // Routines taken from other parts of the Acme utilities. // / Squash bytes down to ints. public static void squashBytesToInts(byte[] inBytes, int inOff, int[] outInts, int outOff, int intLen) { for (int i = 0; i < intLen; ++i) outInts[outOff + i] = ((inBytes[inOff + i * 4] & 0xff) << 24) | ((inBytes[inOff + i * 4 + 1] & 0xff) << 16) | ((inBytes[inOff + i * 4 + 2] & 0xff) << 8) | (inBytes[inOff + i * 4 + 3] & 0xff); } // / Spread ints into bytes. public static void spreadIntsToBytes(int[] inInts, int inOff, byte[] outBytes, int outOff, int intLen) { for (int i = 0; i < intLen; ++i) { outBytes[outOff + i * 4] = (byte) (inInts[inOff + i] >>> 24); outBytes[outOff + i * 4 + 1] = (byte) (inInts[inOff + i] >>> 16); outBytes[outOff + i * 4 + 2] = (byte) (inInts[inOff + i] >>> 8); outBytes[outOff + i * 4 + 3] = (byte) inInts[inOff + i]; } } } Page 5 of 5 Log.java 1 2 3 4 5 6 7 8 9 10 11 12 5/7/2005 19:38 package app.util; public class Log { public static void info(String texto) { // System.out.println("Info: "+texto); } public static void erro(String texto) { System.out.println("Erro: " + texto); } } Page 1 of 1 TratadorDeImagem.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:39 package app.util; import java.awt.image.BufferedImage; public class TratadorDeImagem { private int largura; private int fatorDeMovimento; private int altura; private int alturaOriginal; private int larguraOriginal; private int retX; private int retY; private int retX2; private int retY2; private int fatorDeZoomX; private int fatorDeZoomY; public TratadorDeImagem(int _largura, int _altura, int _larguraOriginal, int _alturaOriginal) { int t = _larguraOriginal / _largura; largura = _largura; altura = (int) Math.round(_alturaOriginal / t); alturaOriginal = _alturaOriginal; larguraOriginal = _larguraOriginal; retX = 0; retY = 0; retY2 = alturaOriginal; retX2 = larguraOriginal; fatorDeMovimento = 100; fatorDeZoomX = 100; fatorDeZoomY = (int) Math.round(((fatorDeZoomX * altura) / largura)); } public BufferedImage redimensionaImagem(BufferedImage imagem) { BufferedImage image = new BufferedImage(largura, altura, BufferedImage.TYPE_INT_RGB); image.getGraphics().drawImage(imagem, 0, 0, largura, altura, retX, retY, retX2, retY2, null); // imagem.getGraphics().drawImage(image, 0, 0,largura,altura, null); // Graphics g=image.getGraphics(); // / g.drawImage(imagem,x,y,width,height,this); return image; } public synchronized void moveParaEsquerda() { if (retX != 0) { if ((retX - fatorDeMovimento) >= 0) { retX = retX - fatorDeMovimento; retX2 = retX2 - fatorDeMovimento; } else { int fatorTemporario = fatorDeMovimento - retX; retX = 0; retX2 = retX2 - fatorTemporario; } } } public synchronized void moveParaDireita() { if (retX2 != larguraOriginal) { if ((fatorDeMovimento + retX2) <= larguraOriginal) { retX = retX + fatorDeMovimento; retX2 = retX2 + fatorDeMovimento; } else { int fatorTemporario = larguraOriginal - retX2; retX2 = larguraOriginal; retX = retX + fatorTemporario; } } } public synchronized void moveParaBaixo() { if (retY2 != alturaOriginal) { if ((fatorDeMovimento + retY2) <= alturaOriginal) { retY = retY + fatorDeMovimento; retY2 = retY2 + fatorDeMovimento; } else { int fatorTemporario = alturaOriginal - retY2; Page 1 of 3 TratadorDeImagem.java 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 5/7/2005 19:39 retY2 = alturaOriginal; retY = retY + fatorTemporario; } } } public synchronized void moveParaCima() { if (retY != 0) { if ((retY - fatorDeMovimento) >= 0) { retY = retY - fatorDeMovimento; retY2 = retY2 - fatorDeMovimento; } else { int fatorTemporario = fatorDeMovimento - retY; retY = 0; retY2 = retY2 - fatorTemporario; } } } public synchronized void zoomMais(TratadorDoMouse tMouse) { if (((retX2 - retX) - fatorDeZoomX) >= largura) { int fatorX = fatorDeZoomX / 2; int fatorY = fatorDeZoomY / 2; retX2 = retX2 - fatorX; retY2 = retY2 - fatorY; retX = retX + fatorX; retY = retY + fatorY; tMouse.zoomMais(); } else { int fatorDeZoomTemporario = (retX2 - retX) - largura; if (fatorDeZoomTemporario != 0) { int fatorX = (int) Math.round(fatorDeZoomTemporario / 2); int fatorDeZoomTemporarioY = (int) Math .round(((fatorDeZoomTemporario * altura) / largura)); int fatorY = (int) Math.round(fatorDeZoomTemporarioY / 2); retX2 = retX2 - fatorX; retY2 = retY2 - fatorY; retX = retX + fatorX; retY = retY + fatorY; } } } public synchronized void zoomMenos(TratadorDoMouse tMouse) { if (((retX2 - retX) + fatorDeZoomX) <= larguraOriginal) { int fatorX = fatorDeZoomX / 2; int fatorY = fatorDeZoomY / 2; retX2 = retX2 + fatorX; retY2 = retY2 + fatorY; retX = retX - fatorX; retY = retY - fatorY; tMouse.zoomMenos(); } } public int getAltura() { return altura; } public void setAltura(int altura) { this.altura = altura; } public int getAlturaOriginal() { return alturaOriginal; } public void setAlturaOriginal(int alturaOriginal) { this.alturaOriginal = alturaOriginal; } public int getFatorDeMovimento() { return fatorDeMovimento; } public void setFatorDeMovimento(int fatorDeMovimento) { Page 2 of 3 TratadorDeImagem.java 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 5/7/2005 19:39 this.fatorDeMovimento = fatorDeMovimento; } public int getFatorDeZoomX() { return fatorDeZoomX; } public void setFatorDeZoomX(int fatorDeZoomX) { this.fatorDeZoomX = fatorDeZoomX; } public int getFatorDeZoomY() { return fatorDeZoomY; } public void setFatorDeZoomY(int fatorDeZoomY) { this.fatorDeZoomY = fatorDeZoomY; } public int getLargura() { return largura; } public void setLargura(int largura) { this.largura = largura; } public int getLarguraOriginal() { return larguraOriginal; } public void setLarguraOriginal(int larguraOriginal) { this.larguraOriginal = larguraOriginal; } public int getRetX() { return retX; } public void setRetX(int retX) { this.retX = retX; } public int getRetX2() { return retX2; } public void setRetX2(int retX2) { this.retX2 = retX2; } public int getRetY() { return retY; } public void setRetY(int retY) { this.retY = retY; } public int getRetY2() { return retY2; } public void setRetY2(int retY2) { this.retY2 = retY2; } } Page 3 of 3 TratadorDoMouse.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 5/7/2005 19:39 package app.util; public class TratadorDoMouse { private int fatorDeMovimento; private int alturaOriginal; private int larguraOriginal; private int x; private int y; private int fatorDeZoom; private int fatorDeMovimentoInicial; public TratadorDoMouse(int _larguraOriginal, int _alturaOriginal) { alturaOriginal = _alturaOriginal; larguraOriginal = _larguraOriginal; x = (int) (Math.round(larguraOriginal) / 2); y = (int) (Math.round(alturaOriginal) / 2); fatorDeMovimento = 60; fatorDeMovimentoInicial = 60; fatorDeZoom = 10; } public synchronized void moveParaEsquerda() { if ((x - fatorDeMovimento) > 0) { x = x - fatorDeMovimento; } else { x = 0; } } public synchronized void moveParaDireita() { if ((x + fatorDeMovimento) < larguraOriginal) { x = x + fatorDeMovimento; } else { x = larguraOriginal; } } public synchronized void moveParaBaixo() { if ((y + fatorDeMovimento) < alturaOriginal) { y = y + fatorDeMovimento; } else { y = alturaOriginal; } } public synchronized void moveParaCima() { if ((y - fatorDeMovimento) > 0) { y = y - fatorDeMovimento; } else { y = 0; } } public synchronized void zoomMais() { if ((fatorDeMovimento - fatorDeZoom) > fatorDeZoom) { fatorDeMovimento = fatorDeMovimento - fatorDeZoom; } else { fatorDeMovimento = fatorDeZoom; } Log.info("Fator de mov em:" + fatorDeMovimento); } public synchronized void zoomMenos() { if ((fatorDeMovimento + fatorDeZoom) < fatorDeMovimento) { fatorDeMovimento = fatorDeMovimento + fatorDeZoom; } else { fatorDeMovimento = fatorDeMovimentoInicial; } Log.info("Fator de mov em:" + fatorDeMovimento); } public int getX() { return x; } public void setX(int x) { Page 1 of 2 TratadorDoMouse.java 77 78 79 80 81 82 83 84 85 86 87 5/7/2005 19:39 this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } Page 2 of 2 APÊNDICE C – Artigo JNC MOBILE – SISTEMA DE ACESSO REMOTO PARA DISPOSITIVOS MÓVEIS Andrei L. Krause e Rafael A. da Silva 1 RESUMO Apesar de a popularização dos dispositivos móveis ter corroborado para o desenvolvimento de vários serviços e funcionalidades, o poder de processamento e a capacidade de armazenamento destes dispositivos ainda são muito limitados. Em razão disso, os aplicativos desenvolvidos para estes tipos de dispositivos devem manter uma certa simplicidade. Este trabalho propõe uma aplicação que viabiliza o acesso remoto a estações de trabalho via um dispositivo móvel. Com a mobilidade e a conectividade dos dispositivos móveis aliados ao poder de processamento de estações de trabalho, é possível executar tarefas complexas a partir de um dispositivo móvel. Palavras-chave: Computação móvel. Computação remota. J2ME. Dispositivos móveis. VNC. ABSTRACT The mobile devices appear currently in the market as merchandises in frank expansion. Of this form, it is necessary that the services offered for these devices, are each time more than excellency, providing the maximum of utility to the users. The objective of this research is exactly to present a software capable to offer the power of processing of a workstation with the practice, mobility and connectivity of the mobile devices as cell phones. The tool in this presented document, makes possible the remote access of a computer through a simple cellular telephone, offering its user, the experience to use softwares available only for machines with more robust processing. It also knows the tools that make possible the conception of this new paradigm of programming and software development. Keywords: Mobile computation. Remote computation. J2ME. Móbile devices. VNC. 1 [email protected]; [email protected]. Acadêmicos do Curso de Bacharelado em Ciências da Computação da Universidade Federal de Santa Catarina. 1. INTRODUÇÃO A evolução e a popularização de dispositivos móveis como celulares, notenooks, PDAs (Personal Digital Assistants), dispositivos discados móveis (GPS – Global Positional System), entre outros, têm oferecido uma gama de serviços e funcionalidades. Para suportar estes serviços, os dispositivos móveis, que têm na forma dos telefones celulares seus mais evidentes representantes, evoluiram consideravelmente. Aparelhos que eram utilizados apenas para fazer ligações, passaram rapidamente a figurar como agendas eletrônicas, câmeras fotográficas digitais, gravadores de som digital e computadores de mão. Mesmo com tantas funcionalidades sendo oferecidas, o poder de processamento e a capacidade de armazenamento destes dispositivos ainda são muito limitados. Uma maneira de oferecer poder computacional e proporcionar acesso a serviços exclusivos das estações de trabalho é o acesso remoto via dispositivos móveis a estações de trabalho. Com o poder de mobilidade e conectividade dos dispositivos móveis, aliados a inovadora tecnologia J2ME da Sun, esta pesquisa visa apresentar uma solução capaz de conectar remotamente uma estação de trabalho a um aparelho móvel. Inicialmente, o capítulo 2 discorre sobre os dispositivos móveis e suas características. O capítulo 3 apresenta o Java 2 Micro Edition (J2ME) e trata da importância desta API para o desenvolvimento do trabalho. O capítulo 4 apresenta os princípios do VNC (Virtual Network Computing) que serviram como base para a idéia proposta. Por fim, o capítulo 5 apresenta o trabalho desenvolvido. 2. DISPOSITIVOS MÓVEIS Em geral, os dispositivos móveis possuem as seguintes características: tamanho reduzido, capacidade de trocar informações via rede, poder de processamento limitado, facilidade de transporte e ausência de cabos para conexão à rede e à energia. Os dispositivos mais utilizados para o propósito de computação móvel são notebooks, laptos, palmtops, PDAs (Personal Digital Assistants) e celulares (smartphones). Mesmo com recursos comparáveis ao de uma estação de trabalho comum, notebooks e laptops não são soluções de mobilidade ideal, pois necessitam de uma base de apoio para serem operados e possuem baterias de curta duração. Os Palmtops resolvem alguns destes empecilhos, mas limitam ainda mais as capacidades de processamento e armazenamento e dificultam os métodos de entrada e saída de dados. Apesar de assumirem funções de um telefone celular, aparelho de fax, Web browser e organizador pessoal, os PDAs também têm pouco poder de processamento e armazenamento, além de apresentarem opções de entrada e saída pouco práticas. Desenvolvidos inicialmente com o único propósito de levar a comunicação além das barreiras da telefonia fixa convencional, os celulares chegaram para transpor barreiras. A tabela 1 apresenta a evolução dos celulares a cada geração. Geração Transmisão de 1G dados analógica (AMPS). Transmissão Digital 2G de Dados (TDMA, CDMA e GSM). Disponibilização de 2,xG aplicações pré-3G. Evolução CDMA e 3G GSM. Elevação das taxas 4G de transmissão de dados. Características Taxas de 9600bps Taxas de 9600bps a 14400bps. Surgimento de aplicações WAP. Taxas de até 2Mbps. Surgimento de aplicações multimídia. Tecnologias e aplicações ainda em discussão. Quadro 1 – Gerações da telefonia celular Fonte: Figueiredo e Nakamura, 2003, p.19. As características e problemas apresentados pelos celulares assemelham-se com os citados nos PDAs. Além disso, a interação com o dispositivo é ainda maior, limitando-se na maioria dos casos, as teclas do aparelho. A solução foi incorporar aos celulares as funções de um PDA, gerando assim um novo dispositivo reconhecido pelo nome de Smartphone. 3. JAVA 2 MICRO EDITION – J2ME Basicamente J2ME é um termo que se refere a uma coleção de APIs e máquinas virtuais que tornam possível o uso de Java em dispositivos móveis. Com o J2ME é possível levar ao mundo dos dispositivos móveis, os benefícios da tecnologia Java, como flexibilidade na interface com o usuário, um modelo de segurança eficaz, suporte a diferentes tipos de aplicações, entre outros. Figura 1 – Plataforma J2ME Fonte: Sun Microsystems, 2005 A plataforma J2ME está presente na maioria dos dispositivos móveis atuais, facilitando ao usuário a aquisição de novos serviços. A figura 1 ilustra a plataforma J2ME. Toda a arquitetura J2ME define configurações, perfis e pacotes opcionais como elementos de uma aplicação Java completa. Assim, a plataforma é capaz de atender aos requisitos de diferentes dispositivos e mercados. A combinação destes elementos otimiza a capacidade de processamento, armazenamento e interfaces de entrada e saída para cada dispositivo particular. O resultado é uma plataforma de desenvolvimento Java comum, capaz de atender a diferentes tipos de equipamentos e fabricantes. 4. VIRTUAL NETWORK COMPUTING – VNC O VNC possibilita que uma estação de trabalho seja controlada remotamente apenas com o uso de um simples programa cliente (visualizador). Outra característica interessante é o fato de não ser necessário que os dispositivos utilizados (cliente – servidor) sejam do mesmo tipo e/ou possuam mesmo sistema operacional. Figura 2 – Acesso remoto com VNC Fonte: Real VNC, 2005 Um software de controle remoto como o VNC, proporciona uma variedade de benefícios, pois torna possível controlar uma estação de trabalho através de uma rede, fixa ou sem fio, como se o indivíduo estivesse operando pessoalmente a estação acessada remotamente. Constatando as facilidades que tal software proporciona, esta pesquisa propõe-se à apresentar uma solução cliente para ser embarcada em dispositivos móveis. 5. JNC MOBILE – SISTEMA DOSPOSITIVOS MÓVEIS DE ACESSO REMOTO PARA O JNC Mobile é uma aplicação que possibilita a um dispositivo móvel controlar remotamente uma estação de trabalho. O dispositivo móvel escolhido foi um telefone celular da fabricante Nokia. Como é ilustrado na figura 3, o acesso remoto necessita da seguinte arquitetura: um sofware cliente, um software servidor VNC e um bridge. Esse último é responsável por receber as requisições do cliente e encaminhá-las ao servidor VNC. Figura 3 – Acesso remoto através de dispositivo móvel com servidor bridge Fonte: Elaborada pelos autores, 2005 As requisições recebidas pelo bridge são encaminhadas ao servidor VNC através do Protocolo RFB (Remote Frame Buffer). Por sua vez, o servidor VNC retorna ao bridge o status (imagem) do desktop, e este encarrega-se de transmitir a informação ao dispositivo móvel. Como ilustra a figura 4, o bridge acumula, além da responsabilidade de tradutor entre o programa cliente e o servidor VNC, a função de compactação da imagem enviada ao cliente. Figura 4 – Compactação da imagem enviada ao cliente Fonte: Elaborada pelos autores, 2005 A imagem fornecida pelo servidor VNC é capturada pelo bridge, que verifica as coordenadas que estão sendo requisitadas pelo dispositivo móvel e as converte para que possam ser exibidas na tela. A figura 5 apresenta um exemplo de utilização da aplicação. O celular mostra a tela do computador que está sendo acessado remotamente. O usuário tem opções para, através das convenções criadas para as teclas do celular, realizar as operações de zoom in e zoom out, além de movimentar o mouse e gerar cliques. Figura 5 – Teclas do celular para o servidor VNC Fonte: elaborada pelos autores, 2005. CONSIDERAÇÕES FINAIS A tecnologia Java 2 ME mostrou-se de grande importância no desenvolvimento do trabalho, oferecendo uma série de facilidades. Além disso, apresenta-se como uma forte tendência, visto que está embutida na maioria dos dispositivos móveis do mercado e visa marcar presença em mais de 90% destes dispositivos até 2007. Uma dificuldade encontrada durante o desenvolvimento do trabalho foi a falta de padronização na indústria. Constatou-se incompatibilidade até mesmo entre aparelhos do mesmo fabricante. Este problema parece estar sendo resolvido com a iniciativa de atualização do profile do J2ME MIDP, que agora figura em sua segunda versão. Apesar das limitações de acessibilidade impostas pelos aparelhos celulares, da dificuldade de manipular as teclas do aparelho, e do tamanho reduzido do visor, e, considerando o caráter acadêmico do trabalho, é com satisfação que se apresenta o JNC Mobile como uma solução real para acesso remoto para dispositivos móveis. REFERÊNCIAS FIGUEIREDO, Carlos M. S.; NAKAMURA, Eduardo. Computação móvel: novas oportunidades e novos desafios. T&C Amazônia. Ano 1. n. 2. Jun. 2003. JAVATM 2 Platform, Micro Edition. Sun Microsystems. Disponível em: <http://java.sun.com/> Acesso: 27 mar. 2005. MOBILE Information Device Profile (MIDP); JSR 37, JSR 118 Overview. Sun Microsystems. Disponível em: <http://java.sun.com/products/midp/> Acesso: 27 mar. 2005. WHAT is VNC. RealVNC. Disponível em: <http://www.realvnc.com/what.html> Acesso: 27 mar. 2005.