web-dev-qa-db-fra.com

Déconnectez une prise Bluetooth dans Android

Je suis en train de développer un programme dans lequel, à partir d'un téléphone Android, je dois me connecter en tant que client à un capteur médical Bluetooth. J'utilise l'API Bluetooth officielle et aucun problème lors de la connexion ( Profil SPP), mais lorsque je termine la prise, le capteur est toujours connecté à mon téléphone (bien que j'aie fermé la connexion).

Existe-t-il un moyen de procéder à une déconnexion Bluetooth? Je pense qu'il y a une intention appelée ACTION_ACL_CONNECTED, qui fait cela. Quelqu'un peut-il m'expliquer comment l'utiliser?

Merci d'avance.

EDITÉ: Voici le code, si quelqu'un a besoin d'informations supplémentaires, c'est un capteur médical Nonin 4100.

Set<BluetoothDevice> pairedDevices = Activa.myBluetoothAdapter.getBondedDevices();
        // If there are paired devices
        if (pairedDevices.size() > 0) {
            // Loop through paired devices
            for (BluetoothDevice device : pairedDevices) {
                // Add the name and address to an array adapter to show in a ListView
                String name = device.getName();
                if (name.contains("Nonin")) {
                    try {
                        found = true;
//                      socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
//                      handler.sendEmptyMessage(5);
//                      Activa.myBluetoothAdapter.cancelDiscovery();
//                      socket.connect();
                        BluetoothDevice hxm = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(device.getAddress());
                        Method m;
                        try {
                            m = hxm.getClass().getMethod("createRfcommSocket", new Class[]{int.class});
                            socket = (BluetoothSocket)m.invoke(hxm, Integer.valueOf(1));
                            handler.sendEmptyMessage(5);
                            socket.connect();
                        } catch (Exception e) {
                            handler.sendEmptyMessage(7);
                            e.printStackTrace();
                            break;
                        }
                        handler.sendEmptyMessage(6);
                        InputStream in = socket.getInputStream();
                        OutputStream out = socket.getOutputStream();
                        byte[] retrieve = { 0x44, 0x31};
                        out.write(retrieve);
                        byte [] ack = new byte [1];
                        in.read(ack);
                        if (ack[0] == 0x15) {
                            cancelMeasurement();
                            return;
                        }
                        byte [] data = new byte [3];
                        long timeStart = System.currentTimeMillis();
                        this.timePassed = System.currentTimeMillis() - timeStart;
                        while ((this.timePassed < (this.time))&&(this.finished)) {
                            try {
                                in.read(data);
                                processData(data);
                                Thread.sleep(1000);
                                this.timePassed = System.currentTimeMillis() - timeStart;
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        in.close();
                        out.close();
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
}
40
user365610

N'oubliez pas de fermer d'abord vos flux d'entrée/sortie, puis fermez le socket.

En fermant les flux, vous lancez le processus de déconnexion. Après avoir fermé le socket, la connexion doit être complètement interrompue.

Si vous fermez le socket avant les flux, vous pouvez ignorer certaines étapes d'arrêt, telles que la fermeture (correcte) de la connexion de la couche physique.

Voici la méthode que j'utilise lorsqu'il est temps de rompre la connexion.

/**
 * Reset input and output streams and make sure socket is closed. 
 * This method will be used during shutdown() to ensure that the connection is properly closed during a shutdown.  
 * @return
 */
private void resetConnection() {
        if (mBTInputStream != null) {
                try {mBTInputStream.close();} catch (Exception e) {}
                mBTInputStream = null;
        }

        if (mBTOutputStream != null) {
                try {mBTOutputStream.close();} catch (Exception e) {}
                mBTOutputStream = null;
        }

        if (mBTSocket != null) {
                try {mBTSocket.close();} catch (Exception e) {}
                mBTSocket = null;
        }

}

EDIT: Ajout de code pour connect ():

// bluetooth adapter which provides access to bluetooth functionality. 
BluetoothAdapter        mBTAdapter      = null;
// socket represents the open connection.
BluetoothSocket         mBTSocket   = null;
// device represents the peer
BluetoothDevice         mBTDevice       = null; 

// streams
InputStream           mBTInputStream  = null;
OutputStream          mBTOutputStream = null;

static final UUID UUID_RFCOMM_GENERIC = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

/**
 * Try to establish a connection with the peer. 
 * This method runs synchronously and blocks for one or more seconds while it does its thing 
 * SO CALL IT FROM A NON-UI THREAD!
 * @return - returns true if the connection has been established and is ready for use. False otherwise. 
 */
private  boolean connect() {

        // Reset all streams and socket.
        resetConnection();

        // make sure peer is defined as a valid device based on their MAC. If not then do it. 
        if (mBTDevice == null) 
                mBTDevice = mBTAdapter.getRemoteDevice(mPeerMAC);

        // Make an RFCOMM binding. 
        try {mBTSocket = mBTDevice.createRfcommSocketToServiceRecord(UUID_RFCOMM_GENERIC);
        } catch (Exception e1) {
                msg ("connect(): Failed to bind to RFCOMM by UUID. msg=" + e1.getMessage());
                return false;
        }

        msg ("connect(): Trying to connect.");

        try {
                mBTSocket.connect();
        } catch (Exception e) {
                msg ("connect(): Exception thrown during connect: " + e.getMessage());
                return false;
        }

        msg ("connect(): CONNECTED!");

        try {
                mBTOutputStream = mBTSocket.getOutputStream();
                mBTInputStream  = mBTSocket.getInputStream();
        } catch (Exception e) {
                msg ("connect(): Error attaching i/o streams to socket. msg=" + e.getMessage());
                return false;
        }

        return true;
}
63
Brad Hein

J'ai constaté que si j'appelle socket.close () trop tôt après une communication récente via OutputStream, la fermeture échoue et je ne peux pas me reconnecter. J'ai ajouté un Thread.sleep (1000) juste avant l'appel à close () et cela semble le résoudre.

16
djilk

SALUT,

J'ai vu exactement le même problème (HTC Desire). Malgré la fermeture du socket par le livre (comme Brad le suggère), le prochain connect () se bloque pour toujours - jusqu'à ce qu'il soit terminé par close () par un autre thread.

J'ai contourné le problème en appelant toujours BluetoothAdapter.disable () /. Enable () avant de me connecter. Hack horrible et hostile, je sais ...

Je soupçonne que certains des problèmes BT actuels sont spécifiques au fabricant, car certains implémenteurs d'applications semblent vivre heureux avec createRfcommSocketToServiceRecord (), qui échoue définitivement sur mon HTC Desire (Android 2.1 mise à jour 1).

J'ai vu des indications (désolé, je n'ai pas de références) que la pile BT du HTC Desire diffère du Nexus One, bien qu'il semble s'agir d'appareils très similaires ...

BR Per

(ajout) Voici une activité très simple pour reproduire le problème (sans désactiver/activer le "traitement"):

package com.care2wear.BtTest;

import Java.io.IOException;
import Java.io.InputStream;
import Java.io.OutputStream;
import Java.lang.reflect.InvocationTargetException;
import Java.lang.reflect.Method;

import Android.app.Activity;
import Android.bluetooth.BluetoothAdapter;
import Android.bluetooth.BluetoothDevice;
import Android.bluetooth.BluetoothSocket;
import Android.os.Bundle;
import Android.util.Log;
import Android.widget.TextView;

public class BtTestActivity extends Activity {
    private static final String TAG="BtTest";

    BluetoothAdapter mBtAdapter = null;
    BluetoothDevice mBtDev = null;
    BluetoothSocket mBtSocket = null;
    InputStream isBt;
    OutputStream osBt;  
    String mAddress = "00:18:E4:1C:A4:66";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        init();

        connect();  // ok
        disconnect(); // ok
        connect(); // this invariably fails - blocked until BT is switched off by someone else, or the peer device turns off/goes out of range
        disconnect();
    }

    private void init() {
        Log.d(TAG, "initializing");
        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
        mBtDev = mBtAdapter.getRemoteDevice(mAddress);
        Log.d(TAG, "initialized");
    }

    private void connect() {
        try {
            Log.d(TAG, "connecting");
            Method m = mBtDev.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
            mBtSocket = (BluetoothSocket) m.invoke(mBtDev, 1);
            mBtSocket.connect();
            Log.d(TAG, "connected");
        } catch (SecurityException e) {
            Log.e(TAG, "SecEx", e);
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "NsmEx", e);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "IArgEx", e);
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IAccEx", e);
        } catch (InvocationTargetException e) {
            Log.e(TAG, "ItEx", e);
        } catch (IOException e) {
            Log.e(TAG, "IOEx", e);
        }

    }

    private void disconnect() {
        Log.d(TAG, "closing");

        if (isBt != null) {
            try {
                isBt.close();
            } catch (IOException e) {
                Log.e(TAG, "isBt IOE", e);              
            }
            isBt = null;
        }
        if (osBt != null) {
            try {
                osBt.close();
            } catch (IOException e) {
                Log.e(TAG, "osBt IOE", e);              
            }
            osBt = null;
        }
        if (mBtSocket != null) {
            try {
                mBtSocket.close();
            } catch (IOException e) {
                Log.e(TAG, "socket IOE", e);                
            }
            mBtSocket = null;
        }
        Log.d(TAG, "closed");       
    }
}

Si quelqu'un peut repérer si je le fais mal, n'hésitez pas à commenter :)

(ajout 2) Je pense que je l'ai fait fonctionner maintenant:

  1. La méthode officielle de connexion de RFCOMM (via SDP) semble maintenant fonctionner (HTC Desire, 2.1 mise à jour 1), MAIS J'ai dû supprimer et recoupler l'appareil BT. Allez comprendre..
  2. La reconnexion peut toujours échouer (échec de découverte du service) si je me reconnecte "trop rapidement" (quittez l'application, puis redémarrez immédiatement). Je suppose que la connexion n'est pas encore complètement interrompue ..
  3. Si je termine toujours la (dernière) activité non seulement avec finish (), mais aussi avec Runtime.getRuntime (). Exit (0) ;, cela fonctionne beaucoup mieux. Allez à nouveau ...

Si quelqu'un peut expliquer cela, je l'apprendrai avec plaisir. /Par

(ajout 3) J'ai enfin obtenu la mise à jour Froyo (2.2) pour mon Desire, et pour autant que je puisse voir, SPP fonctionne maintenant :)/Per

11
Per Laursen

Je développais une application qui se connecte à un appareil BT. Votre code fonctionne bien dans mon HTC Wildfire mais avec un Samsung Galaxy I5700 ne fonctionne pas. Les deux OS sont une mise à jour 2.1 mais .....

L'exception était "InvocationTargetException"

La seule chose que j'ai dû modifier, c'est la déconnexion ().

private void disconnect() {
         if(Conectado){ 
            try {
                ***mBtSocket.close();***
                 texto.setText(texto.getText()+"\nDesconectado");
                 Conectado = false;
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                texto.setText(texto.getText()+"\n"+e1.getMessage());
            } 
            catch (Exception e2) {
                // TODO Auto-generated catch block
                texto.setText(texto.getText()+"\n"+e2.getMessage());
            }    
         }
2
user343464

Hé, donc j'utilise l'application Bluetooth Chat du site de développement Android et ils fournissent une méthode stop() dans la classe BluetoothChatService. J'ai donc simplement créé une instance de celle-ci dans mon classe principale et et appelé la fonction d'arrêt de mon bouton de déconnexion.

Voici comment je l'appelle dans ma classe principale

// Objet membre pour les services de chat

private BluetoothManager mChatService = null;
case R.id.disconnect:
        mChatService.stop();
break;

La méthode stop () dans BluetoothChatService

private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
public synchronized void stop() 
{
    if (mConnectThread != null)
    {
        mConnectThread.cancel(); mConnectThread = null;
    }
    if (mConnectedThread != null) 
    {
        mConnectedThread.cancel(); mConnectedThread = null;
    }
    if (mAcceptThread != null) 
    {
        mAcceptThread.cancel(); mAcceptThread = null;
    }
}
1
Rafael Mancilla

J'ai le même problème. C'est le problème avec le module Bluetooth CSR BC417, présent dans de nombreux appareils comme adaptateur série à bluetooth avec profil SPP. Avec un autre module Bluetooth Android fonctionne bien, et le bluetooth libère la connexion après la fermeture du socket, mais pas avec les appareils avec ce noyau CSR. Testé sur SPP Bluetooth vers adaptateur série basé sur CSR BC417 et le module Bluetooth d'Actisys. Tous les deux avec des appareils Android 4.0. Je ne sais pas pourquoi mais c'est un problème de compatibilité entre les logiciels, essayez de changer l'adaptateur série pour un autre avec un Core différent. J'essaie par programme pour trouver une solution, même en désactivant un bluetooth, mais c'est impossible, le problème provient du module CSR.

0
Cacho Paraguay