O Prezi é
uma ferramenta online para construção de apresentação multimídia semelhante ao
famoso Power Point, porém, através de templates prontos e animações bem
trabalhadas, o Prezi consegue dar uma dinâmica e uma qualidade visual muito
maior.
Mas mesmo
com toda esta propaganda inicial me sentia desconfortável com uma situação do
Prezi: necessitaria estar perto do computador ou do notebook para ficar
trocando os slides, quer dizer, dando mais um passo na animação construída na
ferramenta. Isso pesa muito quando temos um descendente de italiano (meu caso)
que fala muito com as mãos e não consegue ficar parado durante a palestra.
Desta
forma decidi “hackear” o Prezi. Vale dizer que este termo é confundido com o
termo “Crakear”, que, neste caso, quer dizer pessoas que invadem ou roubam
dados digitais com objetivo de destruir sistemas ou de obter lucro de forma
ilícita. O Hacker é o “nerd do bem”!.
Inicialmente
tentei mudar o aplicativo que podemos baixar do Prezi e passar a ter a
apresentação off-line. Mas, logo de cara vi uma pasta com o nome “Adobe AIR”.
Fazendo uma pesquisa na Wikipedia encontrei esta excelente descrição: Adobe
Integrated Runtime, também conhecido como Adobe AIR e inicialmente chamado de Apollo,
é um programa multiplataforma de ambiente tempo de execução desenvolvida pela Adobe Systems
para construir aplicações de Internet Rica usando Adobe Flash,
Adobe Flex,
HTML, ou AJAX.
Fiquei um
pouco desanimado pelo pouco tempo que tinha para fazer este “hacking” e pelo
fato de ser iniciante nas tecnologias utilizadas pelo AIR. Então pensei: Poderia
hackear o sistema operacional e simular o clique do botão físico esquerda e
botão físico direita.
Seguindo por
este caminho obtive êxito, isso porque logo encontrei um artigo chamado “Robot,
O que é isso?”, publicado no blog “Java Simples”. Esta classe simula
eventos do teclado e do mouse, ou seja, simplesmente TUDO o que estava
precisando. Logo tinha o código Java que
simulava a esquerda e direita do teclado:
Robot
robot = new Robot();
robot.delay(500);
if (recebeu.equals("vai")){
robot.keyPress(KeyEvent.VK_RIGHT);
} else {
robot.keyPress(KeyEvent.VK_LEFT);
}
Mas um
grande problema ainda persistia. Não conseguiria fazer isso a distância. Esta
questão foi mais fácil de resolver, pelo seguinte fato: Java tem uma grande
competência em lidar com a pilha de protocolos TCP/IP, então, logo pensei em
Socket. E o problema da rede não era empecilho porque tenho um roteador wi-fi e
na grande maioria dos eventos que palestro tem rede sem fio. E como Android é
Java, também usaria Socket.
Para quem
não conhece socket, é uma comunicação ponto a ponto onde temos um servidor e um
ou mais clientes. O servidor terá um número ip e escuta em uma das 65.356
portas disponíveis no protocolo TCP/IP.
Então consegui
construir o server socket que recebe o comando e vai mudar a
animação no Prezi. Claro que este deve estar aberto. Vejam o código:
public class ServerSocket {
public static void
main(String[] args) {
OutputStreamWriter output;
BufferedWriter writer;
BufferedReader
leitorLinhas;
InputStreamReader
leitorCaracteres;
InputStream leitorSocket;
try {
ServerSocket server =
new ServerSocket(8080);
while (true){
Socket s =
server.accept();
System.out.println(server.getInetAddress());
leitorSocket =
s.getInputStream();
leitorCaracteres =
new InputStreamReader(leitorSocket);
leitorLinhas = new
BufferedReader(leitorCaracteres);
String recebeu =
leitorLinhas.readLine();
Robot robot = new
Robot();
robot.delay(500);
if
(recebeu.equals("vai")){
robot.keyPress(KeyEvent.VK_RIGHT);
} else {
robot.keyPress(KeyEvent.VK_LEFT);
}
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
O cliente socket precisará enviar o texto
vai para animar progressivamente a apresentação no Prezi ou, qualquer outro
texto, como “volto” para retroceder
na animação.
O layout da aplicação Android é muito
simples e feio. Apenas com dois botões para passar a animação, um cronômetro e
uma caixa de texto para inserir o endereço ip do server socket.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.5"
>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:onClick="volta"
android:text="Trás"
android:textSize="30sp"
/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.5"
android:onClick="vai"
android:text="Frente"
android:textSize="30sp"
/>
</LinearLayout>
<Chronometer
android:textSize="50sp"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:id="@+id/crono"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Chronometer"
/>
<EditText
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:id="@+id/ip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
Observação:
Como o artigo não pode ser muito longo, não vou colocar explicação detalhadas
sobre os códigos, porém, sintam-se a vontade para tirarem as possíveis dúvidas
nos comentários deste artigo.
Já na
parte do código Java referente ao aplicativo Android o resultado final foi
este:
public class ClientSocketPrezi extends Activity{
private Chronometer
crono;
private EditText
edtIp;
protected void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
crono
= (Chronometer) findViewById(R.id.crono);
crono.start();
edtIp = (EditText)
findViewById(R.id.ip);
}
public void vai (View v){
new
Assincrono().execute("vai");
}
public void volta (View v){
new
Assincrono().execute("volta");
}
class Assincrono
extends AsyncTask<String, Void, String>{
protected String
doInBackground(String... params) {
BufferedWriter escritorLinhas;
OutputStreamWriter escritorCaracteres;
OutputStream escritorSocket;
Socket s;
try
{
s = new Socket(edtIp.getText().toString(),
8080);
escritorSocket
= s.getOutputStream();
escritorCaracteres
= new OutputStreamWriter(escritorSocket);
escritorLinhas
= new BufferedWriter(escritorCaracteres);
escritorLinhas.write(params[0]);
escritorLinhas.flush();
escritorLinhas.close();
s.close();
return "foi";
}
catch (UnknownHostException e) {
return
"UnknownHostException: ";
}
catch (IOException e) {
return
"IOException: "+e;
}
}
}
}
Os
códigos marcados com negrito são os principais pontos neste código. Os métodos
vai e volta foram marcados no xml como
responsáveis por responderem a ação de clique nos botões com as respectivas
ações. Cada um deles aciona a classe AsyncTask
passando o texto correspondente a ação desejada.
No método
doInBackground, de implementação
obrigatória, criamos o cliente socket com
o número ip digitado no EditText , escrevemos
a ação desejada no OutputStreamWriter e
enviados ao servidor que, já deve estar rodando no servidor e escutando na
porta configurada.
Conclusão e Futuro
Depois
destes código seu aplicativo já está pronto para ser testado. Quem participou
do 3º Connecting Knowledge, evento promovido pelo Things Hacker Team, que
ocorreu no dia 19/12 na sede da Intel em São Paulo e assistiu minha palestra,
pode perceber que esteva utilizando a aplicativo com um adicional: acionamento
das animações pelo sensor do rotação do tablete, e mais, como estava só com
rede local, não mostrei, mas já tem controle via voz, via redes sociais e via
toque musicais.
Quem ver
mais sobre estes controles avançados? Existem três opções: assistir o próximo
evento do Things Hacker Team, me convidar pra palestrar (hehehe...) ou aguardar futuros artigos.
Obrigado
pela leitura.
Comentários
Evandro Barroso Gaio @ebgaio