﻿Set up Bluetooth access permissions with these lines in __AndroidManifest.xml__:
<manifest .... >
  <uses-permission android:name==”android.permission.BLUETOOTH” />
  <uses-permission android:name==”android.permission.BLUETOOTH_ADMIN” />
The __BLUETOOTH__ permission allows the app to connect to already-paired Bluetooth devices (such as a Bluetooth keyboard), while __BLUETOOTH_ADMIN__ allows the app to discover and pair devices.
When scanning for devices, Bluetooth distinguishes two types of device: ones that are already paired, and ones which are within range and discoverable.
(Paired devices may or may not actually be nearby; how your handset treats the
‘paired devices’ list and how long they stay there is manufacturer-dependent).
Our initial layout, __res/layout/devices.xml__ (see the DVD for the full code), has two lists, one of paired devices and one of discoverable devices. 
<?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
    ... >
  <Button android:id=”@+id/buttonFindBluetooth”
          android:text=”@string/buttonFindBluetooth”
          ...
          android:layout_gravity=”center” />
  <LinearLayout ... >
    <TextView android:id=”@+id/pairedDevicesListTitle”
              android:text=”@string/pairedDevicesListTitle” 
              ... />
  </LinearLayout>
  <LinearLayout android:layout_weight=”1” 
                ... >
    <ListView android:id=”@+id/pairedBluetoothList” 
              ... /> 
  </LinearLayout>
    <!-- repeat this for second list -->
Nesting LinearLayouts within the main LinearLayout allows you to have multiple scrollable ListViews. To avoid the TextViews hiding the ListViews, they too must be in their own LinearLayout boxes. The Button at the top will kick off finding devices. 
This is __onCreate()__ in the main Activity, BluetoothIM:
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.devices);
  bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (bluetoothAdapter == null) {
    Toast.makeText(this, R.string.noBluetooth, Toast.LENGTH_LONG).show();
    finish();
    return;
  }
  setUpButtons();
}
The BluetoothAdapter is the start point for interaction with all local Bluetooth activities: discovering other devices, talking to devices, and setting up a Bluetooth server to listen for connection requests. If there’s no default adapter available, the device doesn’t support Bluetooth, and we tell the user that and finish the Activity. (Note that a device that supports Bluetooth may not currently have it switched on! See the boxout for how to handle this.)
Next, __setUpButtons()__:
public void setUpButtons() {
  Button findBluetoothButton = 
    (Button) findViewById(R.id.buttonFindBluetooth);
  findBluetoothButton.setOnClickListener(new View.OnClickListener() {
    public void onClick(View view) {
      findPairedBluetoothDevices();
      findAllBluetoothDevices();
    }
  });
}
This calls the two scanning methods when the button is clicked, the first of which looks for paired devices: 
private void findPairedBluetoothDevices() {
  Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
  ListView pairedDevicesListView = (ListView)
      findViewById(R.id.pairedBluetoothList);
  if (pairedDevices.size() > 0) {
    for (BluetoothDevice device : pairedDevices) {
      ArrayAdapter pairedArrayAdapter = new ArrayAdapter(this, 
          android.R.layout.simple_list_item_1); 
      addDeviceToList(device, pairedArrayAdapter, pairedDevicesListView);
    }
  }
}
private void addDeviceToList(BluetoothDevice device,
  Arra yAdapter arrayAdapter, ListView listView) {
  arrayAdapter.add(device.getName() + “\n” + device.getAddress());
  listView.setAdapter(arrayAdapter);
}
The BluetoothAdapter makes it easy to grab a list of paired devices, and we can then interact with this via a BluetoothDevice object. The ArrayAdapter sits between this list and the ListView, and is accessed via __addDeviceToList()__. 
The marginally more complicated __findAllBluetoothDevices()__ method looks for all discoverable devices in the vicinity:
private void findAllBluetoothDevices() {
  final ArrayAdapter<String> deviceArrayAdapter = 
      new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
  final ListView allDevicesListView = (ListView)
      findViewById(R.id.allBluetoothList); 
  receiver = new BroadcastReceiver() {
    public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      if (BluetoothDevice.ACTION_FOUND.equals(action)) {
        BluetoothDevice device = 
            intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
        addDeviceToList(device, deviceArrayAdapter, allDevicesListView);
      }
    }
  };
  IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
  registerReceiver(receiver, filter);
  isReceiverRegistered = true; 
  bluetoothAdapter.startDiscovery();
}
Before we can start a scan using __bluetoothAdapter.startDiscovery()__, we need to register a BroadcastReceiver for the __ACTION_FOUND__ Intent so that we can get information about the devices discovered. This Intent will be broadcast every time the system finds a device. It has two Extras:
* BluetoothDevice.EXTRA_DEVICE contains the BluetoothDevice found.
* BluetoothDevice.EXTRA_CLASS contains the BluetoothClass found, which describes the device’s general characteristics and capabilities. It won’t necessarily be comprehensive.
Our receiver adds each device to the list.  We register it to receive updates, then fire up the discovery process. It’s important to unregister the receiver in the __onPause()__ and __onDestroy()__ methods to avoid using up system resources unnecessarily. The __isReceiverRegistered__ variable is a workaround to avoid unregistering a receiver that isn’t registered and throwing an exception.
At this point, you can compile and run the app, and you’ll get a list of local devices.



#Server thread, Accept Thread
private class AcceptThread extends Thread {
  private final BluetoothServerSocket serverSocket;

  public AcceptThread(boolean secure) {
    BluetoothServerSocket tmp = null;
    try {
      tmp = adapter.listenUsingRfcommWithServiceRecord(CHAT_NAME,
            MY_UUID);
    } catch (IOException e) {
      Log.e(TAG, “listen() failed”, e);
    }
    serverSocket = tmp;
  }
  public void run() {
    setName(“AcceptThread”);
    BluetoothSocket socket = null;
    while (state != STATE_CONNECTED) {
      try {
        socket = serverSocket.accept();
      } catch (IOException e) {
        Log.e(TAG, “accept() failed”, e);
        break;
      }
      if (socket != null) {
        synchronized (BluetoothIMService.this) {
          switch (state) {
          case STATE_LISTEN:
          case STATE_CONNECTING:
            connected(socket, socket.getRemoteDevice());
            break;
          case STATE_NONE:
          case STATE_CONNECTED:
            try {
              socket.close();
            } catch (IOException e) {
              Log.e(TAG, “Could not close unwanted socket”, e);
            }
            break;
          }
        }
      }
    }
  }
  public void cancel() {
    try {
      serverSocket.close();
    } catch (IOException e) {
      Log.e(TAG, “close() of server failed”, e);
    }
  }
}




# DataTransferThread
private class DataTransferThread extends Thread {
  private final BluetoothSocket socket;
  private final InputStream inStream;
  private final OutputStream outStream;
  public DataTransferThread(BluetoothSocket s) {
    socket = s;
    InputStream tmpIn = null;
    OutputStream tmpOut = null;
    try {
      tmpIn = socket.getInputStream();
      tmpOut = socket.getOutputStream();
    } catch (IOException e) {
      Log.e(TAG, “temp sockets not created”, e);
    }
    inStream = tmpIn;
    outStream = tmpOut;
  }
  public void run() {
    byte[] buffer = new byte[1024];
    int bytes;
    while (true) {
      try {
        bytes = inStream.read(buffer);
        handler.obtainMessage(BluetoothIM.MESSAGE_READ, bytes, -1, buffer)
               .sendToTarget();
      } catch (IOException e) {
        Log.e(TAG, “disconnected”, e);
        connectionLost();
        BluetoothIMService.this.start();
        break;
      }
    }
  }
  public void write(byte[] buffer) {
    try {
      outStream.write(buffer);
      handler.obtainMessage(BluetoothIM.MESSAGE_WRITE, -1, -1, buffer)
             .sendToTarget();
    } catch (IOException e) {
      Log.e(TAG, “Exception during write”, e);
    }
  }
  public void cancel() {
    try {
      socket.close();
    } catch (IOException e) {
      Log.e(TAG, “close() of connected socket failed”, e);
    }
  }
}
