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!
terça-feira, 26 de agosto de 2014
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:
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.
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.
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
E aqui finalizo mais um post, qualquer dúvida, sugestão, erro, etc, favor deixar comentários, e até a próxima.
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.
Obrigado e até a próxima!
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.
-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)
Obrigado à todos, e até a próxima.
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á.
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.
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.