別スレからUIをいじれないので
100ミリ秒おきにポーリングするという謎実装になった。(static String global_charっていう文字列を用意)
リソース気にしなければこれでいいと思うんだけど。
ハンドラ周りを勉強しなければ。
MainActivity.java
package com.example.android.btrev; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; public class MainActivity extends Activity { private Bt mBt; private ArrayAdapter<String> mCandidateServers; private ArrayAdapter<String> mServers; public TextView tvRcv; Button btnSnd; SimpleDateFormat sdf; static String global_char = ""; Handler mHandler = new Handler(); Runnable runnable = new Runnable(){ public void run(){ tvRcv.setText(global_char); mHandler.postDelayed(runnable, 100); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); sdf = new SimpleDateFormat("k:m:s:S"); requestWindowFeature(Window.FEATURE_NO_TITLE); mCandidateServers = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); mServers = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1); mBt = new Bt(this, mCandidateServers, mServers); setContentView(R.layout.activity_main); tvRcv = (TextView) findViewById(R.id.tvRcv); btnSnd = (Button) findViewById(R.id.btnSnd); btnSnd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Date date = new Date(); String currentTime = sdf.format(date); mBt.sendMessage(currentTime); runnable.run(); } }); } @Override protected void onResume() { super.onResume(); mBt.turnOn(); } @Override protected void onPause() { super.onPause(); mBt.cancel(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { int itemId = item.getItemId(); if (itemId == R.id.menu_discoverable) { mBt.startDiscoverable(); } else if (itemId == R.id.menu_start_server) { mBt.startServer(); } else if (itemId == R.id.menu_search_server) { mCandidateServers.clear(); ListView lv = new ListView(this); lv.setAdapter(mCandidateServers); lv.setScrollingCacheEnabled(false); final AlertDialog dialog = new AlertDialog.Builder(this).setTitle(R.string.title_dialog) .setPositiveButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mBt.cancelDiscovery(); } }).setView(lv).create(); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> items, View view, int position, long id) { dialog.dismiss(); String address = mCandidateServers.getItem(position); if (mServers.getPosition(address) == -1) { mServers.add(address); } mBt.cancelDiscovery(); } }); dialog.show(); mBt.searchServer(); } else if (itemId == R.id.menu_connect) { ListView lv = new ListView(this); final AlertDialog dialog = new AlertDialog.Builder(this).setTitle(R.string.title_dialog).setPositiveButton(android.R.string.cancel, null) .setView(lv).create(); lv.setAdapter(mServers); lv.setScrollingCacheEnabled(false); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { Handler handler = new Handler(); @Override public void onItemClick(AdapterView<?> items, View view, int position, long id) { dialog.dismiss(); final String address = mServers.getItem(position); handler.post(new Runnable(){ @Override public void run(){ mBt.connect(address); } }); } }); dialog.show(); } return true; } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { mBt.onActivityResult(requestCode, resultCode, data); } }
Bt.java
package com.example.android.btrev; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.util.Log; import android.widget.ArrayAdapter; public class Bt { private abstract class ReceiverThread extends Thread { protected BluetoothSocket mSocket; protected void sendMessage(String message) throws IOException { OutputStream os = mSocket.getOutputStream(); os.write(message.getBytes()); os.write("\n".getBytes()); } protected void loop() throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(mSocket.getInputStream())); String message; while ((message = br.readLine()) != null) { //do something MainActivity.global_char = message; } } } private class ServerThread extends ReceiverThread { private BluetoothServerSocket mServerSocket; private ServerThread() { try { mServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(mActivity.getPackageName(), mUuid); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { Log.d(TAG, "accepting..."); mSocket = mServerSocket.accept(); Log.d(TAG, "accepted"); loop(); } catch (IOException e) { e.printStackTrace(); } finally { cancel(); } } private void cancel() { try { mServerSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } private class ClientThread extends ReceiverThread { private final BluetoothDevice mServer; private ClientThread(String address) { mServer = mBluetoothAdapter.getRemoteDevice(address); try { mSocket = mServer.createRfcommSocketToServiceRecord(mUuid); } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { // connect() の前にデバイス検出をやめる必要がある mBluetoothAdapter.cancelDiscovery(); try { // サーバに接続する mSocket.connect(); loop(); } catch (IOException e) { e.printStackTrace(); } finally { cancel(); } } private void cancel() { try { mSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } private static final int REQUEST_ENABLE_BT = 1234; private static final int REQUEST_DISCOVERABLE_BT = 5678; private static final int DURATION = 300; private final String TAG = getClass().getSimpleName(); private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); private final MainActivity mActivity; private final ArrayAdapter<String> mCandidateServers; private final UUID mUuid = UUID.fromString("e74c254e-db32-4bb9-8f68-3b1f7d732f21"); // このアプリ固有の値。他のアプリで使用してはならない private ServerThread mServerThread; private ClientThread mClientThread; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { Log.d(TAG, "ACTION_FOUND"); // デバイスが見つかった場合、Intent から BluetoothDevice を取り出す BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 名前とアドレスを所定のフォーマットで ArrayAdapter に格納 mCandidateServers.add(device.getName() + "\n" + device.getAddress()); } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { Log.d(TAG, "ACTION_DISCOVERY_FINISHED"); // デバイス検出が終了した場合は、BroadcastReceiver を解除 context.unregisterReceiver(mReceiver); } } }; public Bt(MainActivity context, ArrayAdapter<String> candidateServers, ArrayAdapter<String> servers) { mActivity = context; mCandidateServers = candidateServers; Set<BluetoothDevice> devices = mBluetoothAdapter.getBondedDevices(); for (BluetoothDevice device : devices) { servers.add(device.getName() + "\n" + device.getAddress()); } } public void turnOn() { if (!mBluetoothAdapter.isEnabled()) { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); mActivity.startActivityForResult(intent, REQUEST_ENABLE_BT); } } public void onActivityResult(int requestCode, int resultCode, Intent data) { System.out.println("requestCode:" + requestCode + " resultCode:" + resultCode + " data:" + data); if (requestCode == REQUEST_ENABLE_BT) { if (resultCode != 0) { // 「はい」が選択された } } else if (requestCode == REQUEST_DISCOVERABLE_BT) { if (resultCode == DURATION) { // 「はい」が選択された } } } public void searchServer() { mCandidateServers.clear(); IntentFilter filter = new IntentFilter(); filter.addAction(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); mActivity.registerReceiver(mReceiver, filter); mBluetoothAdapter.startDiscovery(); } public void startDiscoverable() { Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); intent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DURATION); mActivity.startActivityForResult(intent, REQUEST_DISCOVERABLE_BT); } public void cancelDiscovery() { mBluetoothAdapter.cancelDiscovery(); } public void startServer() { if (mServerThread != null) { mServerThread.cancel(); } mServerThread = new ServerThread(); mServerThread.start(); } public void connect(String address) { int index; if ((index = address.indexOf("\n")) != -1) { address = address.substring(index + 1); } // クライアント用のスレッドを生成 mClientThread = new ClientThread(address); mClientThread.start(); } public void sendMessage(String message) { try { if (mServerThread != null) { mServerThread.sendMessage(message); } if (mClientThread != null) { mClientThread.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } public void cancel() { if (mServerThread != null) { mServerThread.cancel(); mServerThread = null; } if (mClientThread != null) { mClientThread.cancel(); mClientThread = null; } } }