Xwork's Blog

The lord is waiting to take your hand.

Mostrando las entradas con la etiqueta java. Mostrar todas las entradas
Mostrando las entradas con la etiqueta java. Mostrar todas las entradas

Vamos a programar #58 - AsyncTask en java.

Hola de nuevo a todos, el día de hoy vamos a ver cómo usar la clase "AsyncTask" para proveer de un poco de multi-threading a una aplicación.



En el la aplicacion de los números de Muchhausen, vimos que empleamos una subclase llamada "UpdateList" que hereda de "AsyncTask", el nombre de la clase es bastante descriptivo, puesto que lo que hace es ejecutar una tarea de forma asíncrona.

la clase AsyncTask posee los siguientes metodos:

  • doInBackground(Params... params).
    • Este método se debe de sobrecargar para poder realizar una tarea de forma asíncrona.
  • onCancelled(Result result)
    • Se ejecuta en el hilo principal despúes de que cancel(boolean) es invocado o  doInBackground(Object[]) ha terminado.
  • onPostExecute(Result result).
    • Se ejecuta cuando doInBackground(Params...) ha terminado su ejecución.
  • OnPreExecute()
    • Se ejecuta en el hilo principal antes que doInBackground(Params...).
  • onProgressUpdate(Progress... values)
    • Este método se ejecuta despúes de que publishProgress(Progress...) is invoked.
  • publishProgress(Progress... values)
    • Este método puede ser invocado  desde doInBackground(Params...) para actualizar elementos en el hilo principal.

Para tener una idea de cómo funciona, retomemos el ejemplo de los números de Munchhausen. Para empezar, ¿qué es lo queremos hacer?, en este caso buscamos crear una lista de resultados en la que indiquemos si un número n cumple o no la conjetura. entonces para construir la clase AsyncTask de acuerdo a nuestros requerimientos, puede ser de la siguiente forma: private  class UpdateList extends AsyncTask<Integer,Void,ArrayList> y cada parametro corresponde a:

  • Integer, son los parametros que se usaran en doInBackground(), son del tipo integer porque son los números que vamos a usar cómo limites inferior y superior, y un tercero que se usará para indicar  si se deben mostrar o no todos los números.
  • Void, el segundo parametro cómo en eeste caso no mostramos ningún progreso en concreto, simplemente mostramos el dialogo de forma indeterminada, usualmente suele ser un valor Integer.
  • ArrayList,  debido a que todos los resultados de los calculos los guardamos en un "ArrayList", para poder usar esa lista cómo resultado de la ejecución, debemos de hacerlo del mismo tipo, si por alguna razón nuestro proceso debe de devolver un valor "boolean", "String" o etc. el tercer parametro debe de ser de ese tipo.
Para ejecutar el proceso, en el hilo principal debemos de llamar a "new UpdateList().execute(Min,Max,ShowAll);" los parámetros que usemos aqui se convertiran en un array y se asignaran a la variable que se use cuando definimos nuestro proceso.

Ahora veamos el siguiente código:

// Original de https://developer.android.com/reference/android/os/AsyncTask
 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
	 protected Long doInBackground(URL... urls) {
		 int count = urls.length;
		 long totalSize = 0;
		 for (int i = 0; i < count; i++) {
			 totalSize += Downloader.downloadFile(urls[i]);
			 publishProgress((int) ((i / (float) count) * 100));
			 // Escape early if cancel() is called
			 if (isCancelled()) break;
		 }
		 return totalSize;
	 }

	 protected void onProgressUpdate(Integer... progress) {
		 setProgressPercent(progress[0]);
	 }

	 protected void onPostExecute(Long result) {
		 showDialog("Downloaded " + result + " bytes");
	 }
 }
 

Esta clase se construye de la siguiente forma: DownloadFilesTask extends AsyncTask<URL, Integer, Long>,  suponiendo que se llame a ejecutar con los siguientes parametros: "URL1", "URL2","URL3","URL4"..."URL10". El parámetro URL contendrá estos diez valores distintos entonces en "doInBackground(URL.. urls)" lo que se hace es primero asignar los parámetros a la variable "urls" y luego medir los elementos con "urls.length" y cada parámetro pasado al momento de iniciar la ejecución, estará en esta matriz. EL resultado de "doInBackground"  es del tipo "Long" que usaremos en "onPostExecute" para mostrar al usuario cuantos bytes se descargaron. Cada vez que se ejecute "publishProgress()" en "doInBackGround()", se ejecutará "onProgressUpdate()", en esta parte es donde debemos de cambiar cualquier indicador de progreso. finalmente en "onPostExecute()", mostraremos un dialogo con la información de cuantos bytes se descargaron.

En post anteriores ya hemos usado "AsyncTask"

Y bien, por ahora es todo, en el siguiente post añadiremos una barra de progreso y entenderemos mejor cómo y cuando debemos de hacer uso de "AsyncTask".

Los leo luego.

Vamos a programar #57 - Los números de Munchhausen (ver. Java android)

Hola de nuevo a todos, el día de hoy vamos a ver cómo probar los números de Munchhausen en java para usarse en dispositivos con android.

El código.

Cómo ya vimos cuales son las reglas de los números de Munchhausen en el primer post, ahora pasaremos directamente al código en java para poder usarlo. El código es el siguiente:

package com.mdev.munchhausen;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;

public class MainActivity extends Activity {

	Button BtnDowork;
	TextView TXTMin, TxtMax;
	CheckBox CHKShowAll;
	ListView ShowResults;
	private ProgressDialog progress;

	private boolean IsMunchhausenNumber(String Number)
	{
		int Value = 0;
		int CurrentNumber = 0;
		char[] Digits = Number.toCharArray();
		for (int i = 0; i < Digits.length; i++)
		{
			CurrentNumber = Digits[i] - 48;
			Value += (int)Math.pow(CurrentNumber,CurrentNumber);
		}
		String CurrentVal = String.valueOf(Value);
		if (Number.compareTo(CurrentVal) == 0)
			return true;
		else
			return false;
	}

	private ArrayList TestNumbers(int BeginNumber, int EndNumber, int ShowAll)
	{
		ArrayList TempList = new ArrayList();
		for (int i = BeginNumber; i <= EndNumber; i++)
		{
			if (IsMunchhausenNumber(String.valueOf(i)))
				TempList.add( "La conjetura se cumple para el número " + i);
			else if (ShowAll == 1)
				TempList.add( "El número " + i + " no cumple la conjetura");;
		}
		return TempList;
	}
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		BtnDowork = (Button)findViewById(R.id.BtnDoWork);
		TXTMin = (TextView)findViewById(R.id.TXTInMin);
		TxtMax = (TextView)findViewById(R.id.TXTInMax);
		CHKShowAll = (CheckBox)findViewById(R.id.CHKShowAll);
		ShowResults = (ListView) findViewById(R.id.LVResults);
		BtnDowork.setOnClickListener(new View.OnClickListener() {
										 @Override
										 public void onClick(View v) {
											 Integer ShowAll = 0;
											 Integer Min = Integer.valueOf(TXTMin.getText().toString());
											 Integer Max = Integer.valueOf(TxtMax.getText().toString());
											 if (CHKShowAll.isChecked())
												 ShowAll = 1;
											 else
												 ShowAll = 0;
												new UpdateList().execute(Min,Max,ShowAll);
										 }
									 }

		);
	}

	private  class UpdateList extends AsyncTask<Integer,Void,ArrayList>
	{
		@Override
		protected void onPreExecute()
		{
			progress = ProgressDialog.show(MainActivity.this, "Espera...", "Espera...!!!");
		}
		@Override
		protected ArrayList doInBackground(Integer... Limits)
		{
			ArrayList Lista = new ArrayList();
			Lista = TestNumbers(Limits[0],Limits[1],Limits[2]);
			return Lista;
		}
		@Override
		protected void onPostExecute(ArrayList result)
		{
			super.onPostExecute(result);
			final ArrayAdapter adapter = new ArrayAdapter(MainActivity.this,android.R.layout.simple_list_item_1, result);
			ShowResults.setAdapter(adapter);
			progress.dismiss();
		}
	}
}

El código ha cambiado un poco, en el caso de la función "IsMunchhuasenNumber()", todo se mantiene igual, es decir; se prueba un número y si este cumple la conjetura, la funcion devuelve "true", en caso contrario se devuelve "false".

La función "TestNumbers", es la que sufrido varios cambios. Para empezar, los parámetros que está recibe, los primeros dos se mantienen del tipo "int", pero el tercer parámetro pasa a ser del tipo "boolean" al tipo "int", esto solo hace por practicidad, un poquito más adelante veremos el por qué. Otro de los cambios que sufre, es que ahora pasa a ser una función en vez de un procedimiento. El valor que regresa es un valor del tipo "ArrayList", que es la lista en la cual se van almacenado los valores de salida. Cada vez que se prueba la conjetura para un número, se regresa una cadena de texto similar a "el número n no/cumple la conjetura", en la versión de C#, directamente se usaba el delegado y la función "UpdateList()" para hacerlo pero en este y debido a cómo está estructurado, pensé que era mejor hacerlo así.

A diferencia de los muchos otros códigos que he dicho que voy a "optimizar" (y que no he hecho), este ahora si usa un "Thread" diferente para hacer los cálculos y que no se bloquee la interfaz principal, para eso hacemos uso de la Subclase "UpdateList" que hereda de la clase "AsyncTask" (no se si sea en valido decir "hereda" en java, pero creo que si o si no se entiende). En el post de la semana que viene, veremos cómo usar esta clase para poder brindar un poco de "Multithreading", pero por ahora, al crear la instancia, pasamos tres parámetros que son "<Integer, Void, ArrayList>". Para poder usar la clase "AsyncTask", debemos de sobrecargar algunos de los metodos que la componen, en este caso solo son tres (pero hay más) y son: "onPreExecute()", "doInBackground()" y "onPostExecute()". Respectivamente cada uno hace lo siguiente: Es lo que se ejecutará antes de empezar, la parte principal y que mas tiempo va a consumir y la parte donde se procesaran los resultados.

Con el código anterior podemos probar los números de Munchhausen en un dispositivo con android, en el siguiente post veremos cómo es que funciona la clase "AsyncTask" y cómo nos podra ayudar con tareas en segundo plano. El código cómo de costumbre lo pongo en mi dropbox para que lo descargues, recuerda que a partir de este post, solo ira el código del layout principal y el código java. El APK ya compilado lo puedes descargar de mi dropbox directamente o puedes visitar la seccion de descargas del blog.

Y bien, por ahora es todo, los leo luego.

Vamos a programar #37 - DecToAny, Versión java (Android).

Hola a todos, el día de hoy vamos a ver una tercera entrega de la aplicación DecToAny, en los últimos dos post, vimos cómo crear una versión para Windows (hecha en C#), una versión para la web (hecha en javascript) y finalmente el día de hoy vamos a ver una versión para Android (hecha en Java).

Creando la interfaz.

La interfaz principal está compuesta por 4 componentes:
  • 1 TextView.
  • 1 EditText (Numérico).
  • 1 Button.
  • 1 ListView.
Todos los componentes se pueden crear con el siguiente código:

 <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:app="http://schemas.android.com/apk/res-auto"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	tools:context="com.mdev.com.dectoany.MainActivity">

	<LinearLayout
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:orientation="vertical"
		tools:layout_editor_absoluteX="8dp"
		tools:layout_editor_absoluteY="8dp">

		<TextView
			android:id="@+id/lblNumberIn"
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:text="Número a convertir" />

		<EditText
			android:id="@+id/TXTNumberIn"
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:ems="10"
			android:inputType="number" />

		<Button
			android:id="@+id/BtnConvert"
			android:layout_width="match_parent"
			android:layout_height="wrap_content"
			android:text="Convertir" />

		<ListView
			android:id="@+id/LVResults"
			android:layout_width="match_parent"
			android:layout_height="match_parent" />
	</LinearLayout>
</android.support.constraint.ConstraintLayout>

Con esto, tendremos todos los controles necesarios para que el usuario interactue con la aplicación, ahora solo queda implementar el código que hace funcionar las cosas.

El Código que hace funcionar las cosas.

El código es muy parecido al que usamos para la versión de C#. Solo que en este caso, vamos a usar el control ListView para mostrar los resultados de las conversiones.
El código java de DecToAny es el siguiente:

package com.mdev.com.dectoany;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MainActivity extends Activity {

	Button BtnConvert;
	ListView LVResults;
	TextView TxtNumberIn;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		BtnConvert = (Button) findViewById(R.id.BtnConvert);
		TxtNumberIn = (TextView) findViewById(R.id.TXTNumberIn);
		LVResults = (ListView) findViewById(R.id.LVResults);

		BtnConvert.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				DoConvert();
			}
		});
	}

	private void DoConvert(){
		ArrayList Items = new ArrayList();
		String CurrentNumber = TxtNumberIn.getText().toString();
		int MyNumber = Integer.parseInt(CurrentNumber);
		for (int I = 2; I < 30; I++){
			Items.add(ListToString(NumbersList(MyNumber, I))+"\n"+"Base "+ I);
		}
		final ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,Items);
		LVResults.setAdapter(adapter);
	}
	private String ListToString(List<Integer> Numbers)
	{
		Collections.reverse(Numbers);
		String Result = "";
		for (int i = 0; i < Numbers.size(); i++){
			int CurrentNumber = Numbers.get(i);
			if (CurrentNumber < 10)
				Result += CurrentNumber;
			else
				Result += NumberToChar(Numbers.get(i));
		}
		return Result;
	}
	private char NumberToChar(int Number){
			return (char)(Number + 55);
	}

	private List<Integer> NumbersList(Integer InNumber, int Base) {
		Integer LastNumber = InNumber;
		Integer Garbage;
		List<Integer> result = new ArrayList<Integer>();
		if (LastNumber < Base) {
			result.add(LastNumber);
		}
		else         {
			if (LastNumber >= Base) {
				do {
					Garbage = LastNumber % Base;
					LastNumber = LastNumber / Base;
					if (LastNumber < Base) {
						result.add(Garbage);
						result.add(LastNumber);
					} else {
						result.add(Garbage);
					}
				} while (LastNumber >= Base);
			}
		}
		return result;
	}
}

Para esta aplicación vamos usar 4 funciones, la primera de ellas en orden de uso (no de aparicion) es "NumberList", esta es la función que va a realizar los cálculos; cómo parámetros de entrada, recibirá un parámetro del tipo "Integer" llamado "InNumber" que es el número decimal que queremos convertir; seguido de una valor del tipo "int" llamado "Base", este; cómo su nombre lo indica; es la base de destino a la cual queremos convertir nuestro número decimal. La función regresa una lista del tipo "List<Integer>" con los valores de los dígitos para formar el número, pero en orden inverso.
Después tenemos la función "ListToString" que será la encargada de formar un número y devolverlo en forma de "String". Esta función recibe cómo parámetro un lista del tipo "List<Integer>". Esta función se encarga primero; en invertir el orden de la lista que se ingresa cómo parámetro. Después comprueba si el valor es menor a 10 (decimal), si es así, simplemente agrega al string "Result" (variable interna de la función) el valor actual, en caso contrario, manda a llamar a la función "NumberToChar" que se encargara de asignar una letra de la A a la Z a los valores mayores a 10. Finalmente devuelve un "string" que contiene la representación de los resultados de la función "NumberToList" en el formato adecuado para que cualquier persona lo pueda entender.
La función "NumberToChar" simplemente devuelve el numero que se ingresa cómo parámetro + 55.
Para la aplicación de Android también usamos un procedimiento llamado "DoConvert"; en el cual se manda a llamar a las otras funciones dentro de un bucle que va del 2 al 29. En este procedimiento se crea un "ArrayAdapter" que se llenará con los valores que se crean en el ciclo "for" y finalmente se asignan al "ListView".
Con esto podemos obtener de forma fácil el valor de un numero decimal en 27 bases diferentes. En todas las aplicaciones (Android, Windows, Web)no he revisado los errores que puedan haber, no porque sea perezoso o algo similar), pero un error critico existe en la version Web, en esta al poder escoger cual es la base a la que queremos convertir nuestro numero, podemos introducir base 1, pero esta base es imposible de usar, ya que solo disponemos del numero 0, entonces al hacer las divisiones, entramos al bucle "while", pero nunca podremos salir de el, y en algún momento la memoria se acabará hasta que finalmente el navegador en el cual se usa falle. Aunque el sentido común dice que no se debe de hacer lo antes descrito, nunca falta aquel que lo haga solo para saber que pasa. Para evitarlo basta con comprobar las base de destino, si es menor a 2, simplemente hay que informarle al usuario y terminar la ejecución.
Y bien, por ahora es todo, la aplicación compilada la puedes descargar de mi dropbox, el código lo subiré un poco después, primero voy a corregir un error minusculo en el proyecto. (Debería de ser com.mdev.dectoany, en su lugar puse com.mdev.com.dectoany ).

Los leo luego

Vamos a programar #30 - El código de Clock View (Android)

Hola de nuevo a todos, el día de hoy vamos a explicar el código que hace funcionar la aplicación de android Clock View.


La interfaz.

Antes que nada vamos a empezar ´por la interfaz, para el caso de Clock View esta compuesta de 2 partes. La primera son todos los botones de "acción" y parte principal de la aplicacion; la segunda solo es la lista que se encarga de mostrar todos los dispositivos que estén emparejados al dispositivo.

Para mostrar la interfaz principal, en el Layout principal, debemos de agregar el siguiente código.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/activity_main"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:paddingBottom="@dimen/activity_vertical_margin"
 android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 tools:context="com.mdev.clockview.MainActivity">

 <ScrollView
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_alignParentTop="true"
  android:layout_alignParentLeft="true"
  android:layout_alignParentStart="true">

  <LinearLayout
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:orientation="vertical">

   <TextView
    android:text="La hora actual es:"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/TXTView"
    tools:ignore="HardcodedText" />

   <TextClock
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="14dp"
    android:id="@+id/TXTClock"
    android:typeface="sans"
    android:textAlignment="center"
    android:textSize="30sp"
    android:fontFamily="monospace"/>

   <Button
    android:text="Conectar con arduino."
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/BtnConnect"
    android:textAlignment="center"
    android:textAllCaps="false" />

   <Button
    android:text="Cambiar 12/24 Horas."
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/BtnFormat" />

   <Button
    android:text="No/Mostrar segundos."
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/BtnShowS"/>

   <Button
    android:text="Apagar/Encender matrices"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/BtnOn"/>

   <Button
    android:text="Sincronizar hora."
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/BtnSync"/>

   <TextView
    android:text="Nivel de brillo:"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="11dp"
    android:layout_marginStart="11dp"
    android:layout_marginTop="10dp"
    android:id="@+id/textView2" />

   <SeekBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="12dp"
    android:id="@+id/SKBrillo"
    android:max="15"
    android:progress="5" />

   <TextView
    android:text="Brillo: 15"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/txtSeekValue"/>

   <TextView
    android:text="Esperando a ClockView."
    android:layout_width="match_parent"
    android:id="@+id/TxtArduinoReturn"
    android:layout_height="wrap_content" />

   <Button
    android:text="Desconectar"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/BtnDisconnect" />
  </LinearLayout>
 </ScrollView>
</RelativeLayout>

Tras implementar el código, la aplicacion lucira algo similar a la siguiente imagen:



Cómo verás, solo consta de 6 botones, una barra de seek y las etiquetas para mostrar texto.
La funcion de cada uno, la veremos en el código Java, pero antes, vamos a terminar con la interfaz. La lista que contiene los dispositivos emparejados, es un layout que solo contiene un list view y su código es el siguiente;

<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/bt_list"
 android:orientation="vertical"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <ListView
  android:id="@+id/BTList"
  android:layout_width="match_parent"
  android:layout_height="200dp"
  android:headerDividersEnabled="true"
  android:footerDividersEnabled="false">
 </ListView>

</LinearLayout>

Con esto completamos la parte de la interfaz, además en el código completo he agregado el diseño para cuando la orientacion del dispositivo es vertical y para cuando es horizontal, en lo personal preferí forzar a que la aplicacion siempre este en horizontal, pero eres libre de cambiarla a tu gusto.

El código en java.

El código en Java, lo he modificado un poco desde la última vez, corregi algunos errores, uno de ellos era: cuando se intentaba hacer la conexion y esta fallaba, al hacer click en cualquier botón, este intentaba mandar algo a traves del socket que supestemente debio de haber sido creado, al no estar disponible, la aplicion "crasheaba" y salia; el error se debia que a pesar de no haber conexion, la condicion que se debia de comprobar era verdadera debido a que se verificaba si el bluetooth estaba activado; la condicion se podia cumplir, pero eso significaria necesariamente que el socket ya se hubiera creado. Para solucionarlo, simplemente use un flag boleano que solo se cambiaba cuando se abria o cerraba la conexion, ahora si no hay conexion, simplemente no se intenta enviar nada.

Ademas coerregi algunos detalles y bugs minimos. El código actualizado es el siguiente:

package com.mdev.clockview;

import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Handler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.Calendar;

import static com.mdev.clockview.R.layout.paired_devices_list;

public class MainActivity extends Activity {

 BluetoothAdapter myBluetoothAdapter = null;
 Button BtnConnect, BtnOnOff, BtnSecondsShow, BtnSyncHour, BtnChangeFormat,BtnDisconnect;
 SeekBar SkBright;
 TextView TxtArduinoRec, TxtBrigthValue;

 String address = null;
 private ProgressDialog progress;
 BluetoothSocket btSocket = null;
 private boolean isBtConnected = false;
 private static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
 final int RECEIVE_MESSAGE = 1;
 private StringBuilder sb = new StringBuilder();
 private ConnectedThread mConnectedThread;
 Handler h;

 private Set<BluetoothDevice> pairedDevices;
 ListView myListView;
 ArrayAdapter BTArrayAdapter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
  BtnConnect = (Button)findViewById(R.id.BtnConnect);
  myListView = (ListView)findViewById(R.id.BTList);
  TxtArduinoRec = (TextView)findViewById(R.id.TxtArduinoReturn);
  BtnOnOff = (Button)findViewById(R.id.BtnOn);
  BtnSecondsShow = (Button)findViewById(R.id.BtnShowS);
  BtnSyncHour = (Button)findViewById(R.id.BtnSync);
  BtnChangeFormat = (Button)findViewById(R.id.BtnFormat);
  BtnDisconnect = (Button)findViewById(R.id.BtnDisconnect);
  SkBright = (SeekBar)findViewById(R.id.SKBrillo);
  TxtBrigthValue = (TextView)findViewById(R.id.txtSeekValue);

  myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

  if (myBluetoothAdapter == null) {
   msg("El bluetooth no es soportado por este dispositivo");
  }
  else {
   msg("Esperando la conexion");
  }
  SkBright.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
            boolean fromUser) {
    TxtBrigthValue.setText("Brillo: " + String.valueOf(progress));
    if (isBtConnected)
    {
     String result = String.format(">SETB%1$02d", progress);
     mConnectedThread.write(result);
    }
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {
   }

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {

   }
  });
  BtnConnect.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    if (!myBluetoothAdapter.isEnabled()) {
     Intent turnOnIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
     startActivityForResult(turnOnIntent, 1);
    }else{
     showBTDialog();
    }
   }
  });
  BtnOnOff.setOnClickListener(new View.OnClickListener()
  {
   @Override
   public void onClick(View view){
    if (isBtConnected)
    {
     mConnectedThread.write(">SCRA");
    }
   }
  });

  BtnSecondsShow.setOnClickListener(new View.OnClickListener()
  {
   @Override
   public void onClick(View view){
    if (isBtConnected)
    {
     mConnectedThread.write(">DISS");
    }
   }
  });

  BtnSyncHour.setOnClickListener(new View.OnClickListener()
  {
   @Override
   public void onClick(View view){
    if (isBtConnected)
    {
     mConnectedThread.write(BuildHour(true));
    }
   }
  });

  BtnChangeFormat.setOnClickListener(new View.OnClickListener()
  {
   @Override
   public void onClick(View view){
    if (isBtConnected)
    {
     mConnectedThread.write(">SETF");
    }
   }
  });
  BtnDisconnect.setOnClickListener(new View.OnClickListener()
  {
   @Override
   public void onClick(View view){
    if (isBtConnected)
    {
     Disconnect();
    }
   }
  });
  //encargado de procesar los mensajes.
  h = new Handler() {
   public void handleMessage(android.os.Message msg) {
    switch (msg.what)
    {
     case RECEIVE_MESSAGE:
      byte[] readBuf = (byte[]) msg.obj;
      String strIncom = new String(readBuf, 0, msg.arg1);
      sb.append(strIncom);
      int endOfLineIndex = sb.indexOf("\r\n");
      if (endOfLineIndex > 0)
      {
       String sbprint = sb.substring(0, endOfLineIndex);
       sb.delete(0, sb.length());
       TxtArduinoRec.setText("Data from Arduino: " + sbprint);
      }
     break;
    }
   };
  };

 }
 private void msg(String s)
 {
  Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
 }
 private String BuildHour(boolean ForArduino){
  //>SETH2016122119001004
  //>SETHAAAAMMDDHHMMSSWW
  Calendar c = Calendar.getInstance();
  int DiaSemana = c.get(Calendar.DAY_OF_WEEK);
  int Anio = c.get(Calendar.YEAR);
  int Mes = c.get(Calendar.MONTH);
  int Dia = c.get(Calendar.DAY_OF_MONTH);
  int Horas = c.get(Calendar.HOUR_OF_DAY);
  int Minutos = c.get(Calendar.MINUTE);
  int Segundos = c.get(Calendar.SECOND);
  String Fecha = null;
  if (ForArduino == true){
   Fecha = String.format(">SETH%1$04d%2$02d%3$02d%4$02d%5$02d%6$02d%7$02d",
     Anio, Mes + 1, Dia, Horas, Minutos,Segundos, DiaSema);
   msg(Fecha);
  }else {
   Fecha = String.format("%1$04d/%2$02d/%3$02d - %4$02d:%5$02d:%6$02d",
     Anio, Mes + 1, Dia, Horas, Minutos,Segundos);
  }
  return Fecha;
 }

 private void Disconnect()
 {
  if (btSocket!=null)
  {
   try
   {
    btSocket.close();
    isBtConnected = false;
   }
   catch (IOException e)
   { msg("Error");}
  }
 }

 private AdapterView.OnItemClickListener myListClickListener = new AdapterView.OnItemClickListener()
 {
  public void onItemClick (AdapterView<?> av, View v, int arg2, long arg3) {
   if (myBluetoothAdapter.isEnabled()) {
    String info = ((TextView) v).getText().toString();
    address = info.substring(info.length() - 17);
    msg(info);

   } else {
    msg("El Bluetooth debe de estar encendido.");
   }
  }
 };


 public void showBTDialog() {
  final AlertDialog.Builder popDialog = new AlertDialog.Builder(this);
  final LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
  final View Viewlayout = inflater.inflate(paired_devices_list, (ViewGroup) findViewById(R.id.bt_list));

  popDialog.setTitle("Dispositivos Bluetooth:");
  popDialog.setView(Viewlayout);

  myListView = (ListView) Viewlayout.findViewById(R.id.BTList);
  BTArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
  myListView.setAdapter(BTArrayAdapter);
  pairedDevices = myBluetoothAdapter.getBondedDevices();

  for(BluetoothDevice device : pairedDevices)
   BTArrayAdapter.add(device.getName()+ "\n" + device.getAddress());

  myListView.setOnItemClickListener(myListClickListener);
  // Button OK
  popDialog.setPositiveButton("Conectar",
    new DialogInterface.OnClickListener() {
     public void onClick(DialogInterface dialog, int which) {
      if (address != null)
      {
       new ConnectBT().execute();
      }
      dialog.dismiss();
     }
    });
  popDialog.create();
  popDialog.show();

 }
 private class ConnectedThread extends Thread {
  private final InputStream mmInStream;
  private final OutputStream mmOutStream;

  public ConnectedThread(BluetoothSocket socket) {
   InputStream tmpIn = null;
   OutputStream tmpOut = null;
   try {
    tmpIn = socket.getInputStream();
    tmpOut = socket.getOutputStream();
   } catch (IOException e) { }

   mmInStream = tmpIn;
   mmOutStream = tmpOut;
  }

  public void run() {
   byte[] buffer = new byte[256];
   int bytes;
   while (true) {
    try {
     bytes = mmInStream.read(buffer);
     h.obtainMessage(RECEIVE_MESSAGE, bytes, -1, buffer).sendToTarget();
    } catch (IOException e) {
     break;
    }
   }
  }

  public void write(String message) {
   byte[] msgBuffer = message.getBytes();
   try {
    mmOutStream.write(msgBuffer);
   } catch (IOException e) {
    msg("Error al enviar: " + e.getMessage());

   }
  }
 }

 private class ConnectBT extends AsyncTask<Void, Void, Void>
 {
  private boolean ConnectSuccess = true;

  @Override
  protected void onPreExecute()
  {
   progress = ProgressDialog.show(MainActivity.this, "Conectando ("+ address +")...", "Espera...!!!");
  }

  @Override
  protected Void doInBackground(Void... devices)
  {
   try
   {
    if (btSocket == null || !isBtConnected)
    {
     myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
     BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
     BluetoothDevice dispositivo = myBluetoothAdapter.getRemoteDevice(address);
     btSocket = createBluetoothSocket(dispositivo);
     btSocket.connect();
    }
   }
   catch (IOException e)
   {
    ConnectSuccess = false;
   }
   return null;
  }

  private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
   if(Build.VERSION.SDK_INT >= 10){
    try {
     final Method  m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
     return (BluetoothSocket) m.invoke(device, myUUID);
    } catch (Exception e) {
     msg("No se pudo crear la conexion");
    }
   }
   return  device.createRfcommSocketToServiceRecord(myUUID);
  }

  @Override
  protected void onPostExecute(Void result)
  {
   super.onPostExecute(result);

   if (!ConnectSuccess)
   {
    msg("La conexion falló, intentelo de nuevo");
    isBtConnected = false;
   }
   else
   {
    msg("Conectado.");
    isBtConnected = true;
    mConnectedThread = new ConnectedThread(btSocket);
    mConnectedThread.start();
   }
   progress.dismiss();
  }
 }
}

Ahora con el código actualizado vamos a ver que hace cada parte del el.

Clock view está compuesto por tres clases, la primera de ellas es la que se encarga de mostrar todos los componente de la interfaz principal (crear lo eventos para los botones, inflar las cosas necesarias, etc), la segunda es ConnectedThread.

La clase ConnectedThread, es la que se va a encarga de enviar y recibir los datos de y hacia la aplicación.
En ella hay dos métodos: run() y write(). En el método run es donde vamos a leer todos los datos que vienen desde el arduino. Lo pasaremos cómo mensaje y despues el manejado h, se encargará de re-direccionar el contenido y mostrarlo en un textview.
El método write(), servirá para enviar datos hacia el arduino, está es la función que se debe de usar para enviar los comandos, por ejemplo, para enviar el comando para mostrar los segundos, debemos de llamar a la función con el parámetro ">DISS" write(">DISS").
La tercera clase es la que se encarga de crear la conexion y mostrar un dialogo de progreso/espera, cuando la conexión se realiza, deja un socket bluetooth listo para usarse.

Cómo verás, la aplicación es realmente sencilla, pero aun queda mucho por agregar a ambas partes de Clock View, por ahora el código fuente completo lo reservo para cuando ya tenga todas la funciones listas, pero con lo anterior, ya puedes crear tu propia versión.

La parte del código para arduino se actualizará, pero ese en cuanto lo cambie, también actualizaré el vinculo en dropbox.

Por ahora es todo, pero a esto aun le resta bastante para que sea un reloj funcional (más funcional).
Los leo luego.

Vamos a programar #29 - Inútil Apps #2 - Creando un socket bluetooth (arduino y android)

Hola a todos, el día de hoy vamos a continuar con Clock View. Ahora con todo el hardware listo y con la parte de software de arduino también listo, solo queda crear una forma de interactuar con el hardware de Clock View. Al carecer de botones solo nos queda la opción de usar el modulo Bluetooth, para comunicarnos por medio de este, podemos usar aplicaciones que ya estan disponibles en la Playstore (S2 Terminal for bluetooth por ejemplo), pero esa no es la idea del blog, en la mediada de lo posible trataremos de usar nuestro propio software para hacer las cosas.

El dia de hoy les quiero presentar Clock View para android, una aplicación que tiene cómo unica función; conectar con el modulo bluetooth HC-05 o HC-06 y cambiar los ajustes de Clock View.

La aplicacion dispone de 6 botones y una barra de "seek". Para usarla, primero debes de asegurarte de que todo el hardware está listo, despues debes de iniciar la conexion con el boton "Conectar con clock view", cuando aparace un mensaje diciendo que la conexion se llevo a cabo, puedes modificar los ajustes.


Hoy solo veremos el código, en el siguiente post, explicaré un poco acerca de cómo se realiza el intercambio de datos entre arduino y android.

El código.

El siguiente es el código en java que se encarga de hacer funcionar las cosas, los estilos y demás "layouts", irán en la descarga completa al final del post.

package com.mdev.clockview;

import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Handler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.Calendar;

import static com.mdev.clockview.R.layout.paired_devices_list;

public class MainActivity extends Activity {

	BluetoothAdapter myBluetoothAdapter = null;
	Button BtnConnect, BtnOnOff, BtnSecondsShow, BtnSyncHour, BtnChangeFormat,BtnDisconnect;
	SeekBar SkBright;
	TextView TxtArduinoRec, TxtBrigthValue;

	String address = null;
	private ProgressDialog progress;
	BluetoothSocket btSocket = null;
	private boolean isBtConnected = false;
	private static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	final int RECEIVE_MESSAGE = 1;
	private StringBuilder sb = new StringBuilder();
	private ConnectedThread mConnectedThread;
	Handler h;

	private Set<BluetoothDevice> pairedDevices;
	ListView myListView;
	ArrayAdapter BTArrayAdapter;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		//setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
		BtnConnect = (Button)findViewById(R.id.BtnConnect);
		myListView = (ListView)findViewById(R.id.BTList);
		TxtArduinoRec = (TextView)findViewById(R.id.TxtArduinoReturn);
		BtnOnOff = (Button)findViewById(R.id.BtnOn);
		BtnSecondsShow = (Button)findViewById(R.id.BtnShowS);
		BtnSyncHour = (Button)findViewById(R.id.BtnSync);
		BtnChangeFormat = (Button)findViewById(R.id.BtnFormat);
		BtnDisconnect = (Button)findViewById(R.id.BtnDisconnect);
		SkBright = (SeekBar)findViewById(R.id.SKBrillo);
		TxtBrigthValue = (TextView)findViewById(R.id.txtSeekValue);

		myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

		if (myBluetoothAdapter == null) {
			msg("El bluetooth no es soportado por este dispositivo");
		}
		else {
			msg("Esperando la conexion");
		}
		SkBright.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress,
										  boolean fromUser) {
				TxtBrigthValue.setText(String.valueOf(progress));
				if (isBtConnected)
				{
					String result = String.format(">SETB%1$02d", progress);
					mConnectedThread.write(result);
				}
			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
			}

			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {

			}
		});
		BtnConnect.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				if (!myBluetoothAdapter.isEnabled()) {
					Intent turnOnIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
					startActivityForResult(turnOnIntent, 1);
				}else{
					showBTDialog();
				}
			}
		});
		BtnOnOff.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View view){
				if (isBtConnected)
				{
					mConnectedThread.write(">SCRA");
				}
			}
		});

		BtnSecondsShow.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View view){
				if (isBtConnected)
				{
					mConnectedThread.write(">DISS");
				}
			}
		});

		BtnSyncHour.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View view){
				if (isBtConnected)
				{
					mConnectedThread.write(BuildHourToArduino());
				}
			}
		});

		BtnChangeFormat.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View view){
				if (isBtConnected)
				{
					mConnectedThread.write(">SETF");
				}
			}
		});
		
		BtnDisconnect.setOnClickListener(new View.OnClickListener()
		{
			@Override
			public void onClick(View view){
				if (isBtConnected)
				{
					Disconnect();
				}
			}
		});
		//encargado de procesar los mensajes.
		h = new Handler() {
			public void handleMessage(android.os.Message msg) {
				switch (msg.what)
				{
					case RECEIVE_MESSAGE:
						byte[] readBuf = (byte[]) msg.obj;
						String strIncom = new String(readBuf, 0, msg.arg1);
						sb.append(strIncom);
						int endOfLineIndex = sb.indexOf("\r\n");
						if (endOfLineIndex > 0)
						{
							String sbprint = sb.substring(0, endOfLineIndex);
							sb.delete(0, sb.length());
							TxtArduinoRec.setText("Data from Arduino: " + sbprint);
						}
						break;
				}
			};
		};

	}
	private void msg(String s)
	{
		Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
	}
	private String BuildHourToArduino(){
		//>SETH2016122119001004
		//>SETHAAAAMMDDHHMMSSWW
		Calendar c = Calendar.getInstance();
		int DiaSemana = c.get(Calendar.DAY_OF_WEEK);
		int Anio = c.get(Calendar.YEAR);
		int Mes = c.get(Calendar.MONTH);
		int Dia = c.get(Calendar.DAY_OF_MONTH);
		int Horas = c.get(Calendar.HOUR_OF_DAY);
		int Minutos = c.get(Calendar.MINUTE);
		int Segundos = c.get(Calendar.SECOND);

		String DateForArduino = String.format(">SETH%1$04d%2$02d%3$02d%4$02d%5$02d%6$02d%7$02d",
				Anio, Mes + 1, Dia, Horas, Minutos,Segundos, DiaSemana);
		msg(DateForArduino);

		return DateForArduino;
	}

	private void Disconnect()
	{
		if (btSocket!=null)
		{
			try
			{
				btSocket.close();
				isBtConnected = false;
			}
			catch (IOException e)
			{ msg("Error");}
		}
	}

	private AdapterView.OnItemClickListener myListClickListener = new AdapterView.OnItemClickListener()
	{
		public void onItemClick (AdapterView<?> av, View v, int arg2, long arg3) {
			if (myBluetoothAdapter.isEnabled()) {
				String info = ((TextView) v).getText().toString();
				address = info.substring(info.length() - 17);
				msg(address);

			} else {
				msg("El Bluetooth debe de estar encendido.");
			}
		}
	};


	public void showBTDialog() {
		final AlertDialog.Builder popDialog = new AlertDialog.Builder(this);
		final LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
		final View Viewlayout = inflater.inflate(paired_devices_list, (ViewGroup) findViewById(R.id.bt_list));

		popDialog.setTitle("Dispositivos Bluetooth:");
		popDialog.setView(Viewlayout);

		myListView = (ListView) Viewlayout.findViewById(R.id.BTList);
		BTArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
		myListView.setAdapter(BTArrayAdapter);
		pairedDevices = myBluetoothAdapter.getBondedDevices();

		for(BluetoothDevice device : pairedDevices)
			BTArrayAdapter.add(device.getName()+ "\n" + device.getAddress());

		myListView.setOnItemClickListener(myListClickListener);
		// Button OK
		popDialog.setPositiveButton("Conectar",
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						if (address != null)
						{
							new ConnectBT().execute();
						}
						dialog.dismiss();
					}
				});
		popDialog.create();
		popDialog.show();

	}
	private class ConnectedThread extends Thread {
		private final InputStream mmInStream;
		private final OutputStream mmOutStream;

		public ConnectedThread(BluetoothSocket socket) {
			InputStream tmpIn = null;
			OutputStream tmpOut = null;
			try {
				tmpIn = socket.getInputStream();
				tmpOut = socket.getOutputStream();
			} catch (IOException e) { }

			mmInStream = tmpIn;
			mmOutStream = tmpOut;
		}

		public void run() {
			byte[] buffer = new byte[256];
			int bytes;
			while (true) {
				try {
					bytes = mmInStream.read(buffer);
					h.obtainMessage(RECEIVE_MESSAGE, bytes, -1, buffer).sendToTarget();
				} catch (IOException e) {
					break;
				}
			}
		}

		public void write(String message) {
			byte[] msgBuffer = message.getBytes();
			try {
				mmOutStream.write(msgBuffer);
			} catch (IOException e) {
				msg("Error al enviar: " + e.getMessage());

			}
		}
	}



	private class ConnectBT extends AsyncTask<Void, Void, Void>
	{
		private boolean ConnectSuccess = true;

		@Override
		protected void onPreExecute()
		{
			progress = ProgressDialog.show(MainActivity.this, "Conectando...", "Espera...!!!");
		}

		@Override
		protected Void doInBackground(Void... devices)
		{
			try
			{
				if (btSocket == null || !isBtConnected)
				{
					myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
					BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
					BluetoothDevice dispositivo = myBluetoothAdapter.getRemoteDevice(address);
					btSocket = createBluetoothSocket(dispositivo);
					btSocket.connect();
				}
			}
			catch (IOException e)
			{
				ConnectSuccess = false;
			}
			return null;
		}

		private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
			if(Build.VERSION.SDK_INT >= 10){
				try {
					final Method  m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
					return (BluetoothSocket) m.invoke(device, myUUID);
				} catch (Exception e) {
					msg("No se pudo crear la conexion");
				}
			}
			return  device.createRfcommSocketToServiceRecord(myUUID);
		}

		@Override
		protected void onPostExecute(Void result)
		{
			super.onPostExecute(result);

			if (!ConnectSuccess)
			{
				msg("La conexion falló, intentelo de nuevo");
				isBtConnected = false;
			}
			else
			{
				msg("Conectado.");
				isBtConnected = true;
				mConnectedThread = new ConnectedThread(btSocket);
				mConnectedThread.start();
			}
			progress.dismiss();
		}
	}
}

Cómo todo el código requiere una explicacion detallada (o si no quieres meterte en programacion), por ahora solo dejo el APK ya compilado,
Los leo luego.