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

quarta-feira, 9 de abril de 2014

Habilitando cloud9 IDE no raspberry pi

Boa tarde,
Hoje consegui habilitar cloud9 IDE no raspberry pi, para quem não sabe o que é cloud9 IDE (https://c9.io/), ela é basicamente uma WebIDE para programar pelo browser.
Vou colocar passo a passo como instalá-la no raspberry pi.

sudo npm install -g sm
git clone https://github.com/ajaxorg/cloud9.git cloud9
npm install treehugger
npm install formidable
npm install gnu-tools
npm install xmldom
cd cloud9
sudo sm install

Após isso, ela já estará instalada, porém precisamos alterar algumas configurações para funcionar corretamente.
Edite o arquivo "bin/cloud9.sh" e antes da linha "*) echo "Unkown OS"" adicione as seguintes linhas:

Linux*raspberrypi*) echo "Linux raspberrypi ARM
    node server.js "$@" -a x-www-browser
;;

Depois edite o arquivo "configs/default.js" e altere a variável host para:
var host = argv.l || "0.0.0.0";

Agora já está tudo correto para iniciar o serviço digite:
bin/cloud9.sh -w ~/PastaDoSeuProjeto

Agora é só acessá-lo pelo navegador em
http://ipdoseuraspberrypi:3131

Por hoje é só.
Até a próxima!

segunda-feira, 31 de março de 2014

Projetos em Pi - Problemas com SD-Card

Bom Dia,
Descobri esses dias, que o SD-Card tem problemas de funcionalidades, quando roda um sistema nele, problemas com leituras/gravações que ocasionam corrupções nos arquivos do sistema.
Agora estou precisando de um HD externo para poder rodar o sistema nele, se alguém quiser ajudar a comprar, pode fazer doações pelo paypal ao lado.
Obrigado à todos.
Até a próxima

sexta-feira, 28 de março de 2014

Projetos em Pi - O Recomeço

Bom Dia,
Estou recomeçando o projeto, com novas funções. Ainda tenho que esperar chegar os componentes que encomendei pelo aliexpress (www.aliexpress.com) e assim que estiver tudo comigo, começarei a postar aqui todos os passos e os códigos.
Também criarei um repositório público no github aonde colocarei o projeto completo, junto com as fotos dos hardwares, e esquemas.
Por enquanto é só, espero ter novidades em breve.