segunda-feira, 17 de agosto de 2015

Um pouco de propaganda

Bom dia pessoal,
Vim aqui hoje fazer propaganda do meu outro projeto: Projeto Jangada.
Quem quiser ajudar, será muito bem vindo.
Por enquanto é só!

terça-feira, 9 de junho de 2015

Programando em android com dados na "nuvem"

Bom dia pessoal,

Faz muito tempo que não escrevo, porém como estou num novo projeto, descobri umas ferramentas bem legais, e quis escrever aqui para compartilhar com vocês.

Bom, vou falar para vocês de um "framework" bem completo e no plano básico "grátis", conheçam o Parse.
Basicamente ele possibilita o armazenamento de dados na "nuvem", e para isso disponibiliza uma série de métodos e SDKs, para a maioria das linguagens utilizadas, "android, ios, c#, javascript, etc".
Ele também disponibiliza uma parte de "hospedagem" com node.

Agora vou focar na parte do android, com exemplos de como fazer a comunicação simples.

Primeiramente ele possui uma documentação bem explicada de todos os métodos e tudo que precisa saber. Android Guide
Com o guide deles vocês terão uma boa idéia de como fazer a comunicação e tudo mais, então vou colocar simplesmente uma classe de exemplo para que vocês possam utilizar, essa é a classe base que eu mesmo utilizo no meu projeto:


 import com.parse.Parse;  
 import com.parse.ParseException;  
 import com.parse.ParseObject;  
 public class Base {  
   protected String getParseClassName() {  
     return "";  
   }  
   public Base() {  
     backingObject = ParseObject.create(getParseClassName());  
   }  
   public Base(ParseObject object) {  
     setObject(object);  
   }  
   public void setObject(ParseObject object) {  
     backingObject = object;  
     setObject();  
   }  
   public void setObject() { }  
   public ParseObject getParseObject() {  
     return backingObject;  
   }  
   public void Save() throws ParseException {  
     getParseObject();  
     backingObject.save();  
     setObject();  
   }  
   protected ParseObject backingObject;  
   @Override  
   public int hashCode() {  
     return backingObject.getObjectId().hashCode();  
   }  
   @Override  
   public boolean equals(Object obj) {  
     if (obj == null)  
       return false;  
     if (obj == this)  
       return true;  
     return ((Base)obj).backingObject.getObjectId().equals(this.backingObject.getObjectId());  
   }  
 }  

Todas as classes de objetos do parse eu utilizo "extends Base" que basicamente ela possui um "ParseObject backingObject" o método "getParseClassName" serve para definir qual o nome da classe do objeto, seria a tabela do parse, eu deu override no hashcode e equals para comparar pelo ObjectId que é o id do parse.

Para vocês terem uma idéia de como utilizar essa classe base eu vou colocar uma classe simples que eu utilizo aqui:

 import com.parse.ParseException;  
 import com.parse.ParseObject;  
 import com.parse.ParseQuery;  
 import com.parse.ParseRelation;  
 public class Cidade extends Base {  
   public Cidade() {  
     super();  
   }  
   public Cidade(ParseObject object) {  
     super(object);  
   }  
   @Override  
   protected String getParseClassName() {  
     return "cidade";  
   }  
   public String getDescricao() {  
     return backingObject.getString("descricao");  
   }  
   @Override  
   public void setObject() {  
     //AQUI SERIA PARA COLOCAR RELAÇÕES COM OUTROS OBJETOS  
   }  
   @Override  
   public ParseObject getParseObject() {  
     ParseRelation relation = backingObject.getRelation("estado");  
     relation.add(estado.getParseObject());  
     return super.getParseObject();  
   }  
 }  


Espero que com isso vocês tenham um bom passo incial, e que comecem a pensar em utilizar o parse para envio de dados para nuvem.
Qualquer dúvidas/sugestões, etc podem postar no comentário que eu respondo.

Até a próxima!

quinta-feira, 27 de novembro de 2014

Dual-boot + Lollipop no Galaxy S3 (I9300)

Bom dia,
Hoje irei ensinar como fazer dual-boot e como colocar o lollipop (Android 5.0) no Galaxy S3 (i9300)
Irei partir do princípio que já temos um custom recovery instalado (CWM ou TWRP) na última versão, caso não tenha, clique no link para baixar e instalar o recovery.
Bom, primeira coisa que devemos fazer é instalar o arter97 kernel que irá possibilitar o dual-boot, e também possui várias funções, clique no link para ver todas as funções.
Se você não tiver root, baixe e instale também o superSU.zip
Download do superSU.zip
Download do arter97 kernel.
Copie o zip para o celular, case deseje copiar pelo adb (adb push "caminho para o kernel.zip" /sdcard/kernel.zip")
Agora reinicie o aparelho em modo recovery, desligue ele, e ligue segurando o botão Volume+, Home e Power ao mesmo tempo.
Ao entrar no recovery instale o zip (install zip from sdcard). Reinicie o aparelho, deixe ele bootar normalmente.
Após isso você estará rodando o kernel arter97, agora vamos instalar o dual-boot, baixe o multi-boot.zip do arter97, e já vamos instalar também o Android 5.0 (CyanogenMod 12)
Download do multi-boot.zip
Download da CM12
Download da GAPPs CM12
Após baixar os 3 arquivos, coloque no celular.
Reinicie ele em modo recovery
Instale o multi-boot.zip
SEM REINICIAR
Instale a CM12
Instale a GAPPs
Instale o arter97 kernel de novo
Reinicie.
Agora o celular vai reiniciar normalmente, e entrará na ROM que você já tinha.
Reinicie em modo recovery novamente
Instale de novo o multi-boot.zip
Instale o superSU.zip
Reinicie.
Quando ele ligar você vai ver na gaveta de apps um aplicativo chamado aSwitcher.
Abra o aplicativo e vai ter a opção de "Reboot to 2nd ROM"
Clique e ele irá rebootar na CM12, espere, pois o primeiro BOOT demora bastante.
Lembrando que todos os "known-bugs" estão nesse fórum (http://forum.xda-developers.com/galaxy-s3/development/wip-cyanogenmod-12-t2936990).
O teclado na CM12 só vai aparecer após você ir em configurações e habilitar o "hardware keyboard".

Agora você irá poder rebootar entre as 2 roms normalmente, testando a CM12 (Lollipop) mas continuando com a sua ROM que funciona tudo.

Até a próxima!

terça-feira, 26 de agosto de 2014

Android NDK, OpenGL ES, and Framework

Então, estava procurando tutoriais sobre openGL ES com android NDK (C++), mas existem poucos, e os mesmos não funcionam muito bem.
Por isso resolvi postar aqui tudo que eu passei para conseguir algo funcional (não digo 100% pois não consegui testar direito, mas está compilando).

Primeiramente eu uso o AndroidStudio, pois acho melhor do que o Eclipse, para configurar o NDK no studio, basta seguir esse tutorial: (NDK + Android Studio).

Após configurar tudo direitinho, você terá um diretório "jni" com o source em C++, eu não consegui fazer o gradle compilar automaticamente, então eu uso o ndk-build na pasta jni, e ele compila e joga para a pasta de libs correta.

Bom, além de tudo isso, como estou tendo que aprender tudo na raça, irei criar um framework para o openGL ES com android NDK, irei criar um repo no github para isso e depois postarei aqui novamente.
Se alguém estiver interessado em ajudar, seja programando, ou dando opniões, sempre será bem vindo.

Qualquer dúvida na configuração pode postar aqui. Até a próxima!

quarta-feira, 20 de agosto de 2014

Android Tutoriais - ContentProvider

Bom dia pessoal,
Comecei um projeto pessoal, e para facilitar a comunicação com o banco de dados sqlite, eu pesquisei um pouco sobre ContentProvider, e achei válido postar aqui um tutorial, sendo que com um ContentProvider, toda a parte de comunicação com o banco de dados fica bem mais simples.

ContentProvider serve para comunicar com o sqlite no android e retornar cursor com os registros sem a necessidade de montar um sql para todo comando, ele também é responsável por toda operação CRUD (create, read, update, delete) do aplicativo.

Bom para começar vamos definir uma tabela, criando uma classe para isso:

public class TutorialTable {
    //Tabela do BD
    public static final String TABLE_TUTORIAL = "tutorial";
    public static final String COLUMN_ID = "_id";
    public static final String COLUMN_DESCRICAO = "descricao";

    // SQL para criar a tabela
    private static final String DATABASE_CREATE = "create table "
            + TABLE_TUTORIAL
            + "("
            + COLUMN_ID + " integer primary key autoincrement, "
            + COLUMN_DESCRICAO + " text not null "
            + ");";

    public static void onCreate(SQLiteDatabase database) {
        database.execSQL(DATABASE_CREATE);
    }

    public static void onUpgrade(SQLiteDatabase database, int oldVersion,
                                 int newVersion) {
        database.execSQL("DROP TABLE IF EXISTS " + TABLE_TUTORIAL);
        onCreate(database);
    }
}


A classe da tabela é bem simples, primeiro definimos uma variável om o nome da tabela e das colunas (para acessar mais tarde), depois definimos o SQL para criar a tabela, e o upgrade (para quando mudarmos alguma coluna, aqui para facilitar ele da DROP e depois CREATE novamente, mas se não quiser ter perda de dados, poderíamos apenas usar ALTER TABLE para adicionar e remover colunas, porém teríamos que controlar as versões, como aqui é apenas para testes vou utilizar a maneira mais fácil.


Depois criaremos uma classe que será o DatabaseHelper, que fará a criação do BD e a atualização do mesmo.

public class DatabaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "tutorial.db";
    private static final int DATABASE_VERSION = 1;

    public IGDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    // Método chamado ao criar o BD
    @Override
    public void onCreate(SQLiteDatabase database) {
        TutorialTable.onCreate(database);
    }

    // Método chamado na atualização do BD, se você mudar o DATABASE_VERSION ele irá chamar esse método
    @Override
    public void onUpgrade(SQLiteDatabase database, int oldVersion,
                          int newVersion) {
        TutorialTable.onUpgrade(database, oldVersion, newVersion);
    }
}

Pronto, temos nossa tabela e nosso BD funcionando, lembrando que para cada tabela é bom criar uma classe diferente, e lembrar de adicionar o onCreate e onUpgrade no databasehelper.
Agora só falta a classe que será responsável pela comunicação com o BD, que será nosso ContentProvider.

public class CustomContentProvider extends ContentProvider {
    private DatabaseHelper database;

    private static final String AUTHORITY = "com.caioketo.tutorial.contentprovider";

    // ------- Definimos URIs uma para cada tabela
    private static final String PATH_TUTORIAL = "tutorial";

    public static final Uri CONTENT_URI_TUTORIAL = Uri.parse("content://" + AUTHORITY
            + "/" + PATH_TUTORIAL);


    // ------- Configurando o UriMatcher
    private static final int TUTORIAL = 10;
    private static final int TUTORIAL_ID = 20;
    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        sURIMatcher.addURI(AUTHORITY, PATH_PERGUNTAS, TUTORIAL);
        sURIMatcher.addURI(AUTHORITY, PATH_PERGUNTAS + "/#", TUTORIAL_ID);
    }

    @Override
    public boolean onCreate() {
        return false;
    }

    //@Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {

        // Vamos utilizar o queryBuilder em vez do método query()
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

        int uriType = sURIMatcher.match(uri);
        switch (uriType) {

            case TUTORIAL_ID:
                // Adicionamos a coluna ID
                queryBuilder.appendWhere(TutorialTable.COLUMN_ID + "="
                        + uri.getLastPathSegment());
                //$FALL-THROUGH$
            case TUTORIAL:
                queryBuilder.setTables(TutorialTable.TABLE_PERGUNTA);
                break;

            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        SQLiteDatabase db = database.getWritableDatabase();
        Cursor cursor = queryBuilder.query(db, projection, selection,
                selectionArgs, null, null, sortOrder);
        // Notificamos caso exista algum Listener
        cursor.setNotificationUri(getContext().getContentResolver(), uri);

        return cursor;
    }

    public String getPATH(int pathID) {
        switch (pathID) {
            case TUTORIAL:
                return PATH_PERGUNTAS;
            default:
                return "";
        }
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        int uriType = sURIMatcher.match(uri);
        SQLiteDatabase sqlDB = database.getWritableDatabase();
        int rowsDeleted = 0;
        long id = 0;
        switch (uriType) {
            case TUTORIAL:
                id = sqlDB.insert(TutorialTable.TABLE_TUTORIAL, null, values);
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return Uri.parse(getPATH(uriType) + "/" + id);
    }


    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int uriType = sURIMatcher.match(uri);
        SQLiteDatabase sqlDB = database.getWritableDatabase();
        int rowsDeleted = 0;
        switch (uriType) {
            case TUTORIAL:
                rowsDeleted = sqlDB.delete(TutorialTable.TABLE_TUTORIAL, selection,
                        selectionArgs);
                break;
            case TUTORIAL_ID:
                String id = uri.getLastPathSegment();
                if (TextUtils.isEmpty(selection)) {
                    rowsDeleted = sqlDB.delete(TutorialTable.TABLE_TUTORIAL,
                            TutorialTable.COLUMN_ID + "=" + id,
                            null);
                } else {
                    rowsDeleted = sqlDB.delete(TutorialTable.TABLE_TUTORIAL,
                            TutorialTable.COLUMN_ID + "=" + id
                                    + " and " + selection,
                            selectionArgs);
                }
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsDeleted;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {

        int uriType = sURIMatcher.match(uri);
        SQLiteDatabase sqlDB = database.getWritableDatabase();
        int rowsUpdated = 0;
        switch (uriType) {
            case TUTORIAL:
                rowsUpdated = sqlDB.update(TutorialTable.TABLE_TUTORIAL,
                        values,
                        selection,
                        selectionArgs);
                break;
            case TUTORIAL_ID:
                String id = uri.getLastPathSegment();
                if (TextUtils.isEmpty(selection)) {
                    rowsUpdated = sqlDB.update(TutorialTable.TABLE_TUTORIAL,
                            values,
                            TutorialTable.COLUMN_ID + "=" + id,
                            null);
                } else {
                    rowsUpdated = sqlDB.update(TutorialTable.TABLE_TUTORIAL,
                            values,
                            TutorialTable.COLUMN_ID + "=" + id
                                    + " and "
                                    + selection,
                            selectionArgs);
                }
                break;
            default:
                throw new IllegalArgumentException("Unknown URI: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return rowsUpdated;
    }

    private void checkColumns(String[] projection) {
        String[] available = { TutorialTable.COLUMN_DESCRICAO, PerguntasTable.COLUMN_ID };
        if (projection != null) {
            HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
            HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
            // check if all columns which are requested are available
            if (!availableColumns.containsAll(requestedColumns)) {
                throw new IllegalArgumentException("Unknown columns in projection");
            }
        }
    }
}


Primeiro definimos a AUTHORITY que será o path do app, para encontrar o BD, depois definimos Uris para cada tabela, e então configuramos o UriMatcher para pegar pelo ID em vez da Uri, para melhorar a velocidade. E então criamos nosso ContentProvider, os métodos são básicos como podem ver:

query(): Seria como um select, retorna um Cursor com os registros encontrados;
getPATH(): Para retornar o PATH pelo ID;
insert(): Como o nome mesmo já diz, insere registros na tabela;
delete(): Deleta registros;
update(): Atualiza os registros;
checkColumns(): esse a gente cria para verificar se a coluna existe antes de executar qualquer comando SQL, caso mude as colunas ele não vai dar erro de SQL, pois trataremos antes.

IMPORTANTE:
Após a criação do ContentProvider temos que declará-lo no AndroidManifest.XML

<provider
            android:authorities="com.caioketo.tutorial.CustomContentProvider"
            android:name=".dao.CustomContentProvider" >
</provider>

E agora sim estamos prontos para trabalhar com o BD, sempre iremos usar o ContentProvider para todas as operações, e podemos até criar um método no ContentProvider para executar um comando SQL (se nescessário) para apenas essa classe se comunicar diretamente com o BD, assim encapsulamos a comunicação.

E aqui finalizo mais um post, qualquer dúvida, sugestão, erro, etc, favor deixar comentários, e até a próxima.


terça-feira, 19 de agosto de 2014

Projetos em Pi - O Cliente [Tutorial Socket.IO + Android]

Bom, como ainda não posso começar a programar o servidor, por problemas técnicos, começarei a modelar o cliente, irei faze-lo para android, utilizando Socket.IO para comunicação.
Segue um tutorial de como utilizar o Socket.IO no android.

Tutorial Socket.IO Android

Para começar recomendo baixar e configurar o Ant para compilar o socket.io-java-client.
1- Baixe o ant-current-bin.zip (http://archive.apache.org/dist/ant/).
2- Extraia em um diretório qualquer.
3- Adicione ANT_HOME nas variáveis do sistema com o caminho para o diretório no qual vocês extraiu.

Pronto, o Ant está configurado, agora vamos baixar o socket.io-java-client. (https://github.com/Gottox/socket.io-java-client)
Na wiki do github tem bem explicadinho, qualquer dúvida coloque aqui nos comentários que eu explico melhor.

Após compilado o soket.io-java-client, você terá na pasta /jar um arquivo chamado socketio.jar, copie esse arquivo para a pasta lib do seu projeto, no android studio clique no jar com o botão direito e depois clique em "Add as library..." para adicionar ao seu projeto.
Pronto, agora estamos com tudo configurado, vamos começar a programar.

No meu projeto (que depois irei liberar no github), eu criei 2 classes para facilitar, mas você pode utilizar uma só.

Teremos a classe que fará a conexão que eu chamei de Client:


public class Client {
    private final String SERVER = "http://ip-do-servidor:porta/";
    private IOParser parser = new IOParser();
    public void Connect() {
        try {
            SocketIO socket = new SocketIO(SERVER);
            socket.connect(parser);
        }
        catch (Exception ex) {

        }
    }
}


E a outra classe que será responsável por interpretar as mensagens comunicações:

public class IOParser implements IOCallback {
    @Override
    public void onDisconnect() {

    }

    @Override
    public void onConnect() {

    }

    @Override
    public void onMessage(String s, IOAcknowledge ioAcknowledge) {

    }

    @Override
    public void onMessage(JSONObject jsonObject, IOAcknowledge ioAcknowledge) {

    }

    @Override
    public void on(String s, IOAcknowledge ioAcknowledge, Object... objects) {

    }

    @Override
    public void onError(SocketIOException e) {

    }
}

Aqui eu nem comecei a implementar, mas dá pra ter uma idéia fácil de como fazer isso.
Na classe Client você poderá adicionar depois métodos para envio de mensagens e deixar a IOParser apenas para recepção.
Bom isso é o básico, conforme vou vendo alguma coisa nova irei colocando os tutoriais aqui.

Obrigado e até a próxima!



Projetos em Pi - Reunindo funções

Bom dia para todos,
Desde a última postagem, resolvi que irei usar o LCD TFT que comprei, porém tenho que comprar mais 1 chip para poder testar tudo direitinho, enquanto não consigo comprá-lo, criei esse post para reunir as funções que colocarei nesse projeto.

O Básico

Esse projeto será para colocar o raspberry pi em um carro, com alimentação por bateria + recarregamento por painéis solares, então toda função deverá ser útil para essa situação.

As Funções

Até agora já reuni algumas funções que desejo colocar, entre elas:
-Music Player (tocar músicas que estarão em bibliotecas dentro do RPi, selecionando-as pelo celular ou tablet, conectando a saída de audio do RPi ao som do carro, e ainda sincronizando as bibliotecas com a wifi de casa, caso o alcance da wifi chegue na rua).
-Video Player (mesma coisa que as músicas, porém com vídeos, irei conectar um monitor HDMI 15'' no RPi, que também será alimentado pela mesma bateria)
-GPS Module (um módulo de GPS para navegação, através do Google Maps, ou Waze (se conseguir), pela tela TFT)
-Emuladores (colocarei emuladores de MAME, SNES, etc, para jogar pelo monitor, quando não assistindo vídeos)
-Controles PS3 (conectar os controles do ps3 para poder jogar os emuladores)

**A bateria que estou usando no projeto é uma bateria 12V de nobreak, coloquei uma bateria separada para não prejudicar (descarregar) a bateria do automóvel)

Pedido

Agora peço à todos que tiverem idéias para mais funções, colocá-las nos comentários e irei atualizando esse post com todas as funções que achar possíveis e úteis.


Obrigado à todos, e até a próxima.

sexta-feira, 15 de agosto de 2014

Projetos em Pi - Em busca da Tela

Bom dia,
Descobri que o chip que eu tenho é errado para o trabalho de ligar o monitor TFT, porém, tenho um tablet velho jogado, abri ele, tirei o LCD + Touchscreen.
Agora estou no trabalho de pesquisa para tentar conectar esse LCD no raspberry pi, se eu consegui, vai ficar até melhor do que eu esperava. Porém como o tablet é chinês, é difícil achar os datasheets do lcd, ou seja, vou ter muito trabalho para achar, e pode ser que nem ache.
Bom por hoje é só, vou continuar na pesquisa, caso encontre algo, atualizarei o blog aqui.
Até lá.

quarta-feira, 13 de agosto de 2014

Projetos em Pi - O Recomeço

Bom, após ficar um bom tempo parado, decidi hoje retornar aos meus projetos em pi.
Primeiramente, irei testar um LCD que eu comprei, (LCD + Touch), se alguém quiser verificar o modelo e schemas que vou usar estão aqui (http://marks-space.com/2013/05/23/raspberry-pi-with-a-3-2-tft-with-touch-control/).
Caso consiga colocar para funcionar o LCD com o touch, irei criar uma classe em python para controlá-lo através do socket.io, ou seja, fazer a comunicação entre a UI (botões e touch) e os componentes do projeto (músicas, controle, sensores, etc).
Hoje à tarde postarei mais atualizações, e espero não ter que parar novamente, agora vamos até o final.
Até a próxima.

sexta-feira, 23 de maio de 2014

[BerryBoot] Como bootar seu raspberry pi pela USB

Bom dia,
Hoje irei ensinar a configurar o BerryBoot, um programa que gerencia o boot no raspberry pi, e assim poderemos colocar para "bootar" pelo usb (HD ext, PenDrive, etc), lembrando que isso não tira a necessidade do cartão SD.


Instalando o BerryBoot

Primeiro iremos baixar o BerryBoot.
Para instalá-lo só precisamos extrair o zip para o cartão SD (formatado em FAT32). Apenas copie os arquivos de dentro do zip e cole no SD (simples não?).

Configurando o BerryBoot




Se seu RaspberryPi estiver conectado ele já pega toda a configuração automática. Clique em OK para continuar.



Selecione a unidade na qual será instalado o sistema operacional e clique em formatar..




Selecione o sistem (Raspbian, OpenELEC, etc)



O SO será baixado da internet e instalado automaticamente.



Esse é o menu de boot do BerryBoot, você pode adicionar mais SO se quiser, lembre-se de deixar o que você mais usa como default, assim ele irá bootar automaticamente se não for pressionada nenhuma tecla.



Pronto, assim finalizamos a instalação e configuração do BerryBoot, agora seu Raspbian (ou outro SO) roda direto do seu pen drive, ou hd ext.

Fonte: http://www.berryterminal.com/doku.php/berryboot