お世話になります。Android初心者です。現在、bluetooth(HID方式)で接続したバーコードリーダからのデータを読み取るための試験的
なクラスを作成しています。android-sdk に付属している「BluetoothChat」を元に、必要なソースコードだけを拾い上げてのテス
トです。参考にしたのは、下記の2つのサイトになります。
http://www.bright-sys.co.jp/blog/android-using-bluetooth-spp/
http://d.hatena.ne.jp/hdk_embedded/20110206/1297012049
デバックをかけるとリッスンまでは進むようなのですが、コネクトできません。テストコード中では、UUIDに、バーコードリーダの.infファイル中の
ClassGuidを指定しており、この部分でひっかかっているような気もします(UUIDを他のものに変えた場合にも、デバック結果は、同一になりま
す)。
ちなみに、EditTextにフォーカシングさえされていれば、アプリケーション上はコネクトされていないにもかかわらず、Android OSレベル
ではコネクトしているためか、そのままバーコードリーダで読み込んだ数値がEditTextに表示されてしまいます。ただし、EditTextのイベン
トに頼った場合、フォーカシング有無の問題や、カーソルの位置によって入力値がぶれるなどの問題があるため、できれば、バーコードリーダで読み込んだ数
値をEditTextに直接読み込ませるようなことはせず、バーコードリーダから受け取ったデータを1度バッファして、数値(バーコードリーダから送ら
れている最後の改行コード部分)を加工し、TextViewに表示させたいと思っております。
どうも相当に見当違いのことをしているような気もするため、どなたかお教えいただけないでしょうか。bluetooth接続や、バーコードリーダの利用
が初めてということもあり、敢えて、ソースを全て掲載いたします。よろしくお願い申し上げます。
【バーコードリーダの.infファイルより】
[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%KoamTac%
LayoutFile=layout.inf
DriverVer=10/15/1999,5.0.2153.1
【BluetoothServiceクラス】
package
test.com;
import java.io.IOException;
// 省略
import android.util.Log;
public class BluetoothService {
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // 何もしていない
public static final int STATE_LISTEN = 1; // コネクションのリッスン
public static final int STATE_CONNECTING = 2; // outgoingコネクションの初期化
public static final int STATE_CONNECTED = 3; // コネクション成立
// Name for the SDP record when creating server sockt
private static final String NAME_SECURE = "BluetoothSecure";
// Unique UUID for this application たぶん、この辺りに問題がありそう(どのUUIDを利用しても結果は同
じ)
private static final UUID UUID_FOR_HID = UUID.fromString("4D36E978-
E325-11CE-BFC1-08002BE10318");
private static final UUID UUID_FOR_HID2 = UUID.fromString("fa87c0d0-
afac-11de-8a39-0800200c9a66");
private static final UUID UUID_FOR_HID3 =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter bluetoothAdapter;
private final Handler handler;
private AcceptThread acceptThread;
private ConnectThread connectThread;
private ConnectedThread connectedThread;
private int state;
// constructor
public BluetoothService(Context context, Handler handler) {
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
state = STATE_NONE;
this.handler = handler;
}
/*
* Set the current state of the connection
* @param state An integer defining the current connection state
*/
private synchronized void setState(int state) {
this.state = state;
// Give the new state to the Handler so the UI Activity can update
handler.obtainMessage(BarcodeTestForGettingDataCorrectlyActivity.MESSAGE_STATE_CHANGE,
state, -1).sendToTarget();
}
/*
* Return the current connection state.
*/
public synchronized int getState() {
return state;
}
/*
* Start the service. Specifically start AcceptThread to begin a
* session in listening (server) mode. Called by the Activity
onResume()
*/
public synchronized void start() {
// Cancel any thread attempting to make a connection
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
}
// Cancel any thread currently running a connection
if (connectedThread != null) {
connectedThread.cancel();
connectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (acceptThread == null) {
acceptThread = new AcceptThread();
acceptThread.start();
}
setState(STATE_LISTEN);
}
/*
* Start the ConnectThread to initiate a connection to a remote
device.
* @param bluetoothDevice The BluetootheDevice to connect
*/
public synchronized void connect(BluetoothDevice bluetoothDevice) {
// Cancel any thread attempting to make a connection
if (state == STATE_CONNECTING) {
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
}
}
// Cancel any thread currently running a connection
if (connectedThread != null) {
connectedThread.cancel();
connectedThread = null;
}
// Start the thread to connect with the given device
connectThread = new ConnectThread(bluetoothDevice);
connectThread.start();
setState(STATE_CONNECTING);
}
/*
* Start the ConnectedThread to begin managing a Bluetooth connection
* @param bluetoothSocket The BluetoothSocket on which the connection
was made
* @param bluetoothDevice The BluetoothDevice that has been connected
*/
public synchronized void connected(BluetoothSocket bluetoothSocket,
BluetoothDevice bluetoothDevice) {
// Cancel the thread that completed the connection
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
}
// Cancel any thread currently running a connection
if (connectThread != null) {
connectedThread.cancel();
connectedThread = null;
}
// Cancel the accept thread because we only want to connect to one
device
if (acceptThread != null) {
acceptThread = null;
}
// Start the thread to manage the connection and perform
transmissions
connectedThread = new ConnectedThread(bluetoothSocket);
connectedThread.start();
// Send the name of the connected device back to the UI Activity
Message message =
handler.obtainMessage(BarcodeTestForGettingDataCorrectlyActivity.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BarcodeTestForGettingDataCorrectlyActivity.DEVICE_NAME,
bluetoothDevice.getName());
message.setData(bundle);
handler.sendMessage(message);
setState(STATE_CONNECTED);
}
/*
* Stop all threads
*/
public synchronized void stop() {
if (connectThread != null) {
connectThread.cancel();
connectThread = null;
}
if (connectedThread != null) {
connectedThread.cancel();
connectedThread = null;
}
if (acceptThread != null) {
acceptThread.cancel();
acceptThread = null;
}
setState(STATE_NONE);
}
/*
* Indicate that the connection attempt failed and notify the UI
Activity
*/
private void connectionFailed() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message message =
handler.obtainMessage(BarcodeTestForGettingDataCorrectlyActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BarcodeTestForGettingDataCorrectlyActivity.TOAST,
"Unable to connect device");
message.setData(bundle);
handler.sendMessage(message);
}
/*
* indicate that the connection was lost and notify the UI Activity.
*/
private void connectionLost() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message message =
handler.obtainMessage(BarcodeTestForGettingDataCorrectlyActivity.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BarcodeTestForGettingDataCorrectlyActivity.TOAST,
"Device connection was lost");
message.setData(bundle);
handler.sendMessage(message);
}
/*
* This thread runs while listening for incoming connections.
* It behaves like a server-side client.
* It runs until a connection is accepted (or until cancelled).
*/
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket bluetoothServerSocket;
// constructor
public AcceptThread() {
BluetoothServerSocket bluetoothServerSocketTmp = null;
// Create a new listening server socket
try {
// ここでUUID_FOR_HID2やUUID_FOR_HID3をしても、デ
バックの結果は同じ
bluetoothServerSocketTmp =
bluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
UUID_FOR_HID);
} catch (IOException ioException) {
}
bluetoothServerSocket = bluetoothServerSocketTmp;
}
public void run() {
setName("AcceptThread");
BluetoothSocket bluetoothSocket = null;
// Listen to the server socket if we're not connected
while (state != STATE_CONNECTED) {
try {
// This is a blocking call
// and will only return on a successful connection or an
exception
bluetoothSocket = bluetoothServerSocket.accept();
} catch (IOException ioException) {
break;
}
// If a connection was accepted
if (bluetoothSocket != null) {
synchronized (BluetoothService.this) {
switch (state) {
case STATE_LISTEN:
case STATE_CONNECTING:
// Situation normal. Start the connected thread.
connected(bluetoothSocket, bluetoothSocket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate new socket.
try {
bluetoothSocket.close();
} catch (IOException ioException) {
}
break;
}
}
}
}
}
public void cancel() {
try {
bluetoothServerSocket.close();
} catch (IOException e) {
}
}
}
/**
* This thread runs while attempting to make an outgoitng connection
with a device.
* It runs straight through; the connection either succeeds or fails.
*/
private class ConnectThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final BluetoothDevice bluetoothDevice;
public ConnectThread(BluetoothDevice bluetoothDevice) {
this.bluetoothDevice = bluetoothDevice;
BluetoothSocket bluetoothSocketTmp = null;
// Get a BluetoothSockt for a connection with the given
BluetoothDevice
try {
// デバックモードでは、ここのUUIDには到達しない
bluetoothSocketTmp =
bluetoothDevice.createRfcommSocketToServiceRecord(UUID_FOR_HID);
} catch (IOException ioException) {
}
bluetoothSocket = bluetoothSocketTmp;
}
public void run() {
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
bluetoothAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a successful
connection or an exception
bluetoothSocket.connect();
} catch (IOException ioException) {
connectionFailed();
// Close the socket
try {
bluetoothSocket.close();
} catch (IOException ioException2) {
}
// Start the service over to restart listening mode
BluetoothService.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothService.this) {
connectThread = null;
}
// Start the connected thread
connected(bluetoothSocket, bluetoothDevice);
}
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException ioException) {
}
}
}
/*
* This thread runs during a connection with a remote device.
* It handles all incoming transmissions.
*/
private class ConnectedThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
public ConnectedThread(BluetoothSocket bluetoothSocket) {
this.bluetoothSocket = bluetoothSocket;
InputStream inputStreamTmp = null;
// Get the BluetoothSocket input stream
try {
inputStreamTmp = bluetoothSocket.getInputStream();
} catch (IOException ioException) {
}
this.inputStream = inputStreamTmp;
}
public void run() {
byte[] bufferByte = new byte[1024];
int bytes;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = inputStream.read(bufferByte);
// Send the obtained bytes to the UI Activity
handler.obtainMessage(BarcodeTestForGettingDataCorrectlyActivity.MESSAGE_READ,
bytes, -1, bufferByte)
.sendToTarget();
} catch (IOException ioException) {
connectionLost();
break;
}
}
}
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException ioException) {
}
}
}
}
【TestForGettingDataCorrectlyActivityクラス】
package
test.com;
import android.app.Activity;
// インポート宣言省略
import android.widget.Toast;
public class BarcodeTestForGettingDataCorrectlyActivity extends
Activity {
private TextView textView1;
private TextView textView2;
private Button button1;
// フォーカスが当たっていれば、このEditTextにそのままバーコードリーダの値が読み込まれてしまう。UUIDは無関係
private EditText editText1;
// BluetoothService Handlerから送られてきたメッセージタイプ
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
// BluetoothService Handlerから受け取ったキー・ネーム
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
private static final int REQUEST_ENABLE_BT = 2;
// 接続された機器名
private String connectedDeviceName = null;
// Local Bluetooth adapter
private BluetoothAdapter bluetoothAdapter = null;
// Member object for the service
private BluetoothService bluetoothService = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setViews();
// BluetoothAdapterの取得と有効化
// Get local Bluetooth adapter
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// bluetoothAdapterがnullであれば、bluetoothはサポートされていない
if (bluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available",
Toast.LENGTH_LONG).show();
finish();
return;
}
}
@Override
public void onStart() {
super.onStart();
// Bluetoothがonでない場合、使用可能なようにリクエストする
// setupReceive() will then be called during onActivityResult
if (bluetoothAdapter.isEnabled() == false) {
Toast.makeText(this, "Bluetooth is not available. reason:ブルートゥース
無効", Toast.LENGTH_LONG).show();
Intent enableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
} else {
if (bluetoothService == null) {
setupReceive();
}
}
}
@Override
public synchronized void onResume() {
super.onResume();
// Performing this check in onResume() covers the case in which
Bluetooth was
// not enabled during onStart(), so we were paused to enable
it...
// onResume() will be called when ACTION_REQUEST_ENABLE activity
returns.
if (bluetoothService != null) {
// Only if the state is STATE_NONE, do we know that we haven't
started already
if (bluetoothService.getState() == BluetoothService.STATE_NONE)
{
// Start the Bluetooth services
bluetoothService.start();
}
}
}
private void setupReceive() {
// Initialize the BluetoothService to perform bluetooth
connections
bluetoothService = new BluetoothService(this, this.handler);
}
@Override
public synchronized void onPause() {
super.onPause();
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
// Stop the Bluetooth services
if (bluetoothService != null) {
bluetoothService.stop();
}
}
// The Handler that gets information back from the BluetoothService
private final Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MESSAGE_STATE_CHANGE:
switch (message.arg1) {
case BluetoothService.STATE_CONNECTED:
textView1.setText("接続されているデバイス: ");
textView1.append(connectedDeviceName);
textView2.setText("");
break;
case BluetoothService.STATE_CONNECTING:
textView1.setText("接続中");
break;
case BluetoothService.STATE_LISTEN:
case BluetoothService.STATE_NONE:
// デバックモードでは、ここで、agr1が1を取得し、終了す
る
textView1.setText("接続されていません。arg1:" + message.arg1);
break;
}
break;
case MESSAGE_READ:
byte[] bufferByte = (byte[]) message.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(bufferByte, 0, message.arg1);
textView2.setText(readMessage);
break;
case MESSAGE_DEVICE_NAME:
// save the connected device's name
connectedDeviceName =
message.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to " +
connectedDeviceName, Toast.LENGTH_LONG).show();
break;
case MESSAGE_TOAST:
Toast.makeText(getApplicationContext(),
message.getData().getString(TOAST), Toast.LENGTH_LONG).show();
break;
}
}
};
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
public void onActivityResult(int requestCode, int resultCode, Intent
data) {
switch (requestCode) {
// When the request to enable Bluetooth retuerns
case REQUEST_ENABLE_BT:
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
setupReceive();
} else {
// User did not enable Bluetooth or an error occured
Log.d(TAG, "Bluetooth not enabled");
Toast.makeText(this, "Bluetooth not enabled, leaving.",
Toast.LENGTH_LONG).show();
finish();
}
}
}
private void setViews() {
textView1 = (TextView) findViewById(R.id.textView1);
textView2 = (TextView) findViewById(R.id.textView2);
button1 = (Button) findViewById(R.id.button1);
editText1 = (EditText) findViewById(R.id.editText1);
}
}