Bluetooth (I): Activando y desactivando el Bluetooth en Android


El primer paso a la hora de desarrollar una aplicación que haga uso de la comunicación mediante Bluetooth es comprobar si éste está activado o no en el dispositivo y, en caso de que no sea así, solicitar al usuario permiso para activarlo.

En primer lugar, si vamos a hacer uso del Bluetooth será requisito indispensable añadir los permisos adecuados para ello en el fichero AndroidManifest.xml:


    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

Pese a que la tecnología Bluetooth está ampliamente extendida, es de obligado cumplimiento la comprobación de que el servicio está disponible en el dispositivo. Para realizar esta operación haremos uso de la clase android.bluetooth.BluetoothAdapter. Declararemos una referencia como atributo dentro de nuestra Activity y a continuación codificaremos un método, al que llamaremos configurarAdaptadorBluetooth(), que se encargará de detectar si el dispositivo puede hacer uso del Bluetooth y si éste se encuentra activo o no.

Un Button nos servirá para realizar la activación y la desactivación. Añadiremos lo siguiente en nuestro layout:


    <RelativeLayout
    	android:layout_width="match_parent"
	    android:layout_height="0dp"
	    android:layout_weight="2" >

        <Button
	        android:id="@+id/btnBluetooth"
    	    android:layout_width="wrap_content"
        	android:layout_height="wrap_content"
	        android:layout_centerHorizontal="true" />
    </RelativeLayout>

A continuación, declaramos como atributos en nuestro código una referencia al botón y otra al adaptador


	private Button btnBluetooth = (Button)findViewById(R.id.btnBluetooth);
	private BluetoothAdapter bAdapter;

El método encargado de configurar inicialmente el adaptador tendrá que comprobar, en primer lugar, si el dispositivo está disponible.


	// Obtenemos el adaptador Bluetooth. Si es NULL, significara que el
	// dispositivo no posee Bluetooth, por lo que deshabilitamos el boton
	// encargado de activar/desactivar esta caracteristica.
	bAdapter = BluetoothAdapter.getDefaultAdapter();
	if(bAdapter == null)
	{
		btnBluetooth.setEnabled(false);
		return;
	}

Lo siguiente será detectar el estado en el que se encuentra el Bluetooth. Una vez referenciado el adaptador bluetooth, nos devolverá esta información invocando a su método isEnabled(). Lo que haremos será cambiar el texto del botón dependiendo de si está activo o no.


	// Comprobamos si el Bluetooth esta activo y cambiamos el texto del
	// boton dependiendo del estado.
	if(bAdapter.isEnabled())
		btnBluetooth.setText(R.string.DesactivarBluetooth);
	else
		btnBluetooth.setText(R.string.ActivarBluetooth);

Detectando cambios de estado en el Bluetooth

En nuestra configuración inicial hemos detectado explícitamente el estado del Bluetooth. Sin embargo, este estado puede cambiar por motivos externos a nuestra aplicación (por ejemplo, que el usuario haga uso del widget de activación/desactivación del Bluetooth). Nuestra aplicación debe ser capaz de detectar estos cambios y realizar las operaciones oportunas en consecuencia.

Para detectar estos cambios, nuestra actividad deberá suscribirse a ellos. Esto se realiza mediante la clase android.content.BroadcastReceiver. Nuevamente, este proceso se realizará en dos pasos:

  1. Instanciar el objeto y codificar el comportamiento esperado en su método onReceive().
  2. Realizar la suscripción a los eventos para que el objeto invoque el método onReceive() cuando se reciba el evento deseado.

Comenzamos declarando el objeto y su método onReceive() justo a continuación de los atributos:


	// Instanciamos un BroadcastReceiver que se encargara de detectar si el estado
	// del Bluetooth del dispositivo ha cambiado mediante su handler onReceive
	private final BroadcastReceiver bReceiver = new BroadcastReceiver()
	{
		@Override
	    public void onReceive(Context context, Intent intent)
		{

	    }
	};

En el interior de este método extraeremos la acción del Intent lanzado mediante broadcast y (generalmente mediante un switch) filtraremos aquellas que nos interesen (puesto que podemos suscribirnos a varias acciones a la vez).


	final String action = intent.getAction();

	// Filtramos por la accion. Nos interesa detectar BluetoothAdapter.ACTION_STATE_CHANGED
	if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action))
	{

	}

Dentro del bloque if realizaremos un nuevo filtrado. Este código se ejecutará cuando el estado del Bluetooth cambie, pero todavía necesitamos saber cuál es el nuevo estado en el que se encuentra el dispositivo. Este estado puede ser:

  • STATE_CONNECTING: El dispositivo está realizando una conexión
  • STATE_CONNECTED: El dispositivo tiene una conexión activa
  • STATE_DISCONNECTING: El dispositivo está finalizando una conexión
  • STATE_DISCONNECTED: El dispositivo se ha desconectado de una conexión activa
  • STATE_ON: El Bluetooth está activo
  • STATE_OFF: El Bluetooth está apagado
  • STATE_TURNING_ON: El Bluetooth está activándose
  • STATE_TURNING_OFF: El Bluetooth se está desactivando

Para acceder a esta información será necesario obtener información extra del Intent. Concretamente, accederemos a un valor entero etiquetado como BluetoothAdapter.EXTRA_STATE.


	// Solicitamos la informacion extra del intent etiquetada como BluetoothAdapter.EXTRA_STATE
	// El segundo parametro indicara el valor por defecto que se obtendra si el dato extra no existe
	final int estado = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
											 BluetoothAdapter.ERROR);

Obtenido el estado, queremos conocer si el Bluetooth se encuentra activo o no. Por ello, nos centraremos en los estados STATE_ON y STATE_OFF filtrándolo mediante un switch. El código aquí mostrado únicamente cambiará el texto del botón dependiendo de si el Bluetooth está activo o no.


	switch (estado)
	{
		// Apagado
		case BluetoothAdapter.STATE_OFF:
		{
			((Button)findViewById(R.id.btnBluetooth)).setText(R.string.ActivarBluetooth);
			break;
		}

		// Encendido
		case BluetoothAdapter.STATE_ON:
		{
			((Button)findViewById(R.id.btnBluetooth)).setText(R.string.DesactivarBluetooth);
			break;
		}
		default:
			break;
	}

Nuestro código ya está preparado para recibir esta información, pero aún queda un cabo suelto: debemos realizar la suscripción, registrando nuestro BroadcastReceiver para que invoque su método onReceive() cuando detecte una determinada acción. Esto lo haremos mediante la creación de un filtro y la invocación del método registerReceiver(). Lo encapsularemos en un método que tendrá el siguiente aspecto:


    private void registrarEventosBluetooth()
    {
   	// Registramos el BroadcastReceiver que instanciamos previamente para
   	// detectar los distintos eventos que queremos recibir
   	IntentFilter filtro = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
   	this.registerReceiver(bReceiver, filtro);
    }

Visibilidad

Dejaremos los detalles sobre el descubrimiento de dispositivos para otro momento, pero es conveniente hacer una pequeña mención al concepto de la visibilidad Bluetooth.

Para realizar una conexión a un dispositivo mediante Bluetooth es necesario conocer la dirección de dicho dispositivo y que éste se encuentre disponible. Es posible realizar un enlace (pairing) entre dos dispositivos de modo que se “recuerde” y autorice ese dispositivo para futuras conexiones. Sin embargo, siempre es necesario realizar una primera conexión. ¿Cómo hacer esto? Mediante el proceso de descubrimiento (Discovery) de dispositivos.

Este proceso consta de un elemento que realiza la búsqueda y de otro que “se deja descubrir”. Por defecto y por motivos de seguridad, los dispositivos Android con Bluetooth activado permanecen en estado oculto, de forma que otros dispositivos que se encuentren realizando operaciones de descubrimiento no puedan conocer información sobre ellos.

Para que un dispositivo pueda “descubrirnos” deberemos cambiar nuestra visibilidad de forma explícita. Generalmente este proceso se realiza de forma temporal, es decir, el dispositivo se revela durante una cantidad limitada de tiempo (por ejemplo, dos minutos). Si queremos que esto ocurra, deberemos solicitar permiso al usuario de forma explícita, del mismo modo que cuando activamos el Bluetooth y que veremos a continuación. Así, si queremos que cuando el Bluetooth se active se solicite permiso al usuario para hacerse visible durante un par de minutos, cambiaríamos el segundo case por lo siguiente:


	// Encendido
	case BluetoothAdapter.STATE_ON:
	{
		// Cambiamos el texto del boton
		((Button)findViewById(R.id.btnBluetooth)).setText(R.string.DesactivarBluetooth);

		// Lanzamos un Intent de solicitud de visibilidad Bluetooth, al que añadimos un par
		// clave-valor que indicara la duracion de este estado, en este caso 120 segundos
		Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
		discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 120);
		startActivity(discoverableIntent);

		break;
	}

El resultado daría lugar a algo como lo siguiente:

Bluetooth Discovery

Pulsando el botón

Manejar los eventos asociados a la pulsación de botones también puede realizarse de varias formas. Si se poseen pocos botones suele ser buena idea realizar esta operación inline, pero si el número de botones en nuestra actividad es elevado, puede resultar un poco caótico debido a la cantidad de listeners que hay que codificar. En este segundo caso, lo aconsejable es hacer que nuestra Activity implemente la interfaz OnClickListener y codificar el método onClick(), en el que filtraremos por el identificador del botón. Esta será la declaración de nuestra actividad:


	public class MainActivity extends Activity
				implements OnClickListener	{

El método onClick(), encargado de atender a estos eventos, tendrá la siguiente forma:


	@Override
	public void onClick(View v) {
		switch(v.getId())
		{
			// Codigo ejecutado al pulsar el Button que se va a encargar de activar y
			// desactivar el Bluetooth.
			case R.id.btnBluetooth:
			{
				// 1. Comprobar si el Bluetooth esta activado o desactivado
				// 2. Codificar la activacion/desactivacion del Bluetooth
			}
		}
	}

Nuestra actividad ya está preparada para atender los eventos onClick() del botón btnBluetooth, pero nuestro botón aún no tiene asociado ningún listener de este evento. Deberemos realizar lo siguiente:


	btnBluetooth.setOnClickListener(this);

Activando y desactivando el Bluetooth

Y llegamos finalmente al propósito inicial de este artículo: la activación y desactivación del Bluetooth. Realizaremos esta operación mediante la pulsación de un botón (que referenciamos aquí).

Android permite realizar la operación de activación del Bluetooth de forma explícita (es decir, sin intervención del usuario), pero se considera muy mala práctica. Para activar el Bluetooth bastaría con hacer lo siguiente:


	bAdapter.enable();

Sin embargo, debido a que al usuario generalmente le gusta ser consciente de lo que activa y desactiva en su dispositivo, es aconsejable pedirle permiso para ello. En la práctica esta solicitud no es tan estricta para la desactivación. Por lo tanto, deberemos comprobar el estado del Bluetooth y cambiarlo al estado opuesto. La desactivación es sencilla:


	if(bAdapter.isEnabled())
		bAdapter.disable();

La activación, al igual que ocurría con la solicitud de cambio de visibilidad, requiere de un Intent que le solicitará permiso al usuario y de la lectura de la respuesta (el usuario puede cancelar la activación).

Para recibir una respuesta de una actividad en la actividad actual, ésta se lanzará mediante el método startActivityForResult(), en el que se especificará el Intent que queremos lanzar y un entero que servirá de clave para filtrar la respuesta en el método onActivityResult(), que será el que se ejecutará al volver de la actividad y contendrá el resultado de la operación.

Así, declaramos una constante entera que identifique de forma unívoca la llamada.


	private static final int 	REQUEST_ENABLE_BT 	= 1;

El código completo de nuestro case tendrá la siguiente forma:


	if(bAdapter.isEnabled())
		bAdapter.disable();
	else
	{
		// Lanzamos el Intent que mostrara la interfaz de activacion del
		// Bluetooth. La respuesta de este Intent se manejara en el metodo
		// onActivityResult
		Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
		startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
	}
	break;

Finalmente, codificamos el método onActivityResult() y filtramos por el código de petición.


	/**
	 * Handler del evento desencadenado al retornar de una actividad. En este caso, se utiliza
	 * para comprobar el valor de retorno al lanzar la actividad que activara el Bluetooth.
	 * En caso de que el usuario acepte, resultCode sera RESULT_OK
	 * En caso de que el usuario no acepte, resultCode valdra RESULT_CANCELED
	 */
	@Override
	protected void onActivityResult (int requestCode, int resultCode, Intent data) {
		switch(requestCode)
		{
			case REQUEST_ENABLE_BT:
			{
				if(resultCode == RESULT_OK)
				{
					// Acciones adicionales a realizar si el usuario activa el Bluetooth
				}
				else
				{
					// Acciones adicionales a realizar si el usuario no activa el Bluetooth
				}
				break;
			}

			default:
				break;
		}
	}

He aquí el resultado:

Activación de Bluetooth

Como último paso, conviene eliminar el registro a los eventos capturados por el BroadcastReceiver. Esto se realizará en el método onDestroy() de la actividad.


	// Ademas de realizar la destruccion de la actividad, eliminamos el registro del
	// BroadcastReceiver.
	@Override
	public void onDestroy() {
	    super.onDestroy();
	    this.unregisterReceiver(bReceiver);
	}

Una vez que sabemos cómo activar y desactivar el Bluetooth, lo siguiente que deberemos hacer será hacer uso del proceso de descubrimiento para seleccionar el dispositivo al cual queremos conectar.

Anuncios

29 comments

    1. Hola, Diego.

      Al final de la serie de artículos dedicados al Bluetooth en Android están los enlaces tanto al código del ejemplo que describo como al código de ejemplo que proporciona Google.

      Un saludo.

  1. Hola, estado probando el código y cuando estoy mirando si el bluetooth esta disponible, “bAdapter = BluetoothAdapter.getDefaultAdapter();” me devuelve un null, por que sucede eso si el dispositivo tiene bluetooth?

    Gracias

    Saludos

  2. No me resulta el código… tengo el siguiente error
    Description Resource Path Location Type
    The method setOnClickListener(View.OnClickListener) in the type View is not applicable for the arguments (MainActivity) MainActivity.java /BluetoothHub/src/com/bluetoothhub line 115 Java Problem

    si alguien me puede ayudar!!!

    Gracias…

  3. Tenes idea si para trabajar con Smarphone y Google Glass es asi como se deberia utilizar la comunicacion entre ellos? Siempre via bluetooth y utilizando esos procedimentos?

  4. Hay un error en el código:

    if(bAdapter.isEnabled())
    {
    btnBluetooth.setText(R.string.DesactivarBluetooth);
    servicio = new BluetoothService(this, handler, bAdapter);
    }

    Ahora mismo, el servicio solo se inicializaría al activar el bluetooth, pero si al iniciar la aplicación ya estaba activado, no funcionaria.

    Muchas gracias por el código! me sirvió mucho de ayuda 🙂

  5. He estado intentando que me funcione esto pero nada Lamentablemente el código que ofreces es un código final en donde lo descargue y no lo pude ejecutar, ademas de que hay modificaciones del código final con este, el objetivo era seguir paso a paso el proyecto pero no das el código completo en el blog y ni el proyecto a descargar según el articulo, SOY NOVATO lo entiendo pero lamentablemente no me ayudo (me ayudo en el sentido de buscar en otros post poniendo de referencia los titulos de este articulo)

  6. Todo muy bien, muchísimas gracias por tan excelente contenido me funciona bien cuando activo y desactivo el bluetooth, pero cuando no detecta el cambio de conectado a desconectado ya probé con desconectando y desconectado y no me anda ninguna. Alguna recomendación ?

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s