// DeviceListActivity.java import java.util.Set; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.TextView; import android.widget.AdapterView.OnItemClickListener; /** * This Activity appears as a dialog. It lists any paired devices and * devices detected in the area after discovery. When a device is chosen * by the user, the MAC address of the device is sent back to the parent * Activity in the result Intent. */ public class DeviceListActivity extends Activity { //디버깅 private static final String TAG = "DeviceListActivity"; private static final boolean D = true; //연결할 장치의 MAC 어드레스 public static String EXTRA_DEVICE_ADDRESS = "device_address"; //블루투스 아답타 private BluetoothAdapter mBtAdapter; //페어링된 기기 private ArrayAdaptermPairedDevicesArrayAdapter; //새로 발견한 기기 private ArrayAdapter mNewDevicesArrayAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //윈도우 셋업 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.device_list); // Set result 사용자가 나갔을때 setResult(Activity.RESULT_CANCELED); // device discovery 를 하기위한 버튼 Button scanButton = (Button) findViewById(R.id.button_scan); scanButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { //device discovery 메소드 doDiscovery(); //버튼을 보이지 않게 한다. v.setVisibility(View.GONE); } }); //페어링된 디바이스를 표시할 ArrayAdapter 객체생성하기. mPairedDevicesArrayAdapter = new ArrayAdapter (this, R.layout.device_name); //새로 발견된 디바이스를 표시할 ArrayAdapter 객체 생성하기. mNewDevicesArrayAdapter = new ArrayAdapter (this, R.layout.device_name); //페어링된 장비를 출력할 리스트 뷰 ListView pairedListView = (ListView) findViewById(R.id.paired_devices); pairedListView.setAdapter(mPairedDevicesArrayAdapter); pairedListView.setOnItemClickListener(mDeviceClickListener); //새로 찾은 장비를 출력할 리스트뷰 ListView newDevicesListView = (ListView) findViewById(R.id.new_devices); newDevicesListView.setAdapter(mNewDevicesArrayAdapter); newDevicesListView.setOnItemClickListener(mDeviceClickListener); //디바이스가 Discover 되었을때 방송을 수신할 방송수신자 등록하기. IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(mReceiver, filter); //디바이스 Discovering 이 끝났을때 방송을 수신할 방송수신자 등록하기. filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(mReceiver, filter); //블루투스 아답타 객체 얻어오기. mBtAdapter = BluetoothAdapter.getDefaultAdapter(); //이미 페어링된 디바이스를 얻어온다. Set pairedDevices = mBtAdapter.getBondedDevices(); //페어링된 디바이스가 존재한다면 출력하기위해 ArrayAdapter 에 추가한다. if (pairedDevices.size() > 0) { findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE); for (BluetoothDevice device : pairedDevices) { mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } else { //페어링된 디바이스가 없다면 없다고 출력하기 위해서 String noDevices = getResources().getText(R.string.none_paired).toString(); mPairedDevicesArrayAdapter.add(noDevices); } } @Override protected void onDestroy() { super.onDestroy(); //Discovering 작업을 취소한다. if (mBtAdapter != null) { mBtAdapter.cancelDiscovery(); } //방송수신자를 등록해제한다. this.unregisterReceiver(mReceiver); } //디바이스 Discovering 를 하는 메소드 private void doDiscovery() { if (D) Log.d(TAG, "doDiscovery()"); //디버깅 하기 위해서. //제목에 스케닝 상태 출력하기. setProgressBarIndeterminateVisibility(true); setTitle(R.string.scanning); // Turn on sub-title for new devices findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE); //이미 Discovering 하고 있었다면 취소한다. if (mBtAdapter.isDiscovering()) { mBtAdapter.cancelDiscovery(); } //Discovering 시작하기. mBtAdapter.startDiscovery(); } //리스트뷰에 등록할 아이템 클릭 리스너 객체. private OnItemClickListener mDeviceClickListener = new OnItemClickListener() { public void onItemClick(AdapterView av, View v, int arg2, long arg3) { //연결하기 위해서 현재 Discovering 을 취소한다. mBtAdapter.cancelDiscovery(); //장비의 MAC 어드레스를 얻어온다. (마지막 17 글짜이다.) String info = ((TextView) v).getText().toString(); String address = info.substring(info.length() - 17); //인텐트 객체를 생성하고 연결할 장치의 MAC 어드레스정보를 넣어준다. Intent intent = new Intent(); intent.putExtra(EXTRA_DEVICE_ADDRESS, address); //Request 코드를 등록 지정하고 인텐트를 전달한다. setResult(Activity.RESULT_OK, intent); finish();//액티비티를 종료한다. } }; //방송 수신자 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { //어떤 방송이 수신되었는지 알아온다. String action = intent.getAction(); //Discovering 결과 장비를 찾았을때 if (BluetoothDevice.ACTION_FOUND.equals(action)) { //BluetoothDevice 객체를 인텐트로 부터 얻어온다. BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); //이미 페어링된 장비라면 무시한다. if (device.getBondState() != BluetoothDevice.BOND_BONDED) { //새로운 장비라면 출력하기 위해서. mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } //Discovering 이 끝났다면 타이틀을 바꿔준다. } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { //프로그래스 바를 정지 하기 위해서. setProgressBarIndeterminateVisibility(false); //제목도 바꿔준다. setTitle(R.string.select_device); if (mNewDevicesArrayAdapter.getCount() == 0) { String noDevices = getResources().getText(R.string.none_found).toString(); mNewDevicesArrayAdapter.add(noDevices); } } } }; } // BluetoothChat.java import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; /** * This is the main Activity that displays the current chat session. */ public class BluetoothChat extends Activity { // Debugging private static final String TAG = "BluetoothChat"; private static final boolean D = true; //블루투스 Service 에서 핸들러에 보내온 메세지의 종류 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; // Key names received from the BluetoothChatService Handler public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; // Intent request codes private static final int REQUEST_CONNECT_DEVICE = 1; private static final int REQUEST_ENABLE_BT = 2; // Layout Views private TextView mTitle; private ListView mConversationView; private EditText mOutEditText; private Button mSendButton; // Name of the connected device private String mConnectedDeviceName = null; //대화 내용을 출력하기 위한 아답터객체 private ArrayAdapter mConversationArrayAdapter; //출력할 메세지를 담을 StringBuffer 객체 private StringBuffer mOutStringBuffer; //블루투스 아답터 private BluetoothAdapter mBluetoothAdapter = null; // Member object for the chat services private BluetoothChatService mChatService = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(D) Log.e(TAG, "+++ ON CREATE +++"); //윈도우 레이아웃 설정 requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); setContentView(R.layout.main); getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title); // Set up the custom title mTitle = (TextView) findViewById(R.id.title_left_text); mTitle.setText(R.string.app_name); mTitle = (TextView) findViewById(R.id.title_right_text); //블루투스 아답타 객체 얻어오기. mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); //블루투스 장치가 없다면 null 이 리턴된다. if (mBluetoothAdapter == null) { Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show(); finish(); //끝내기 return; } } @Override public void onStart() { super.onStart(); Log.e("#####","onStart()"); if(D) Log.e(TAG, "++ ON START ++"); //블루투스 장치는 있지만 꺼져 있을때 켜도록 해야한다. if (!mBluetoothAdapter.isEnabled()) { //블루투스 장치를 켜도록 요청하는 인텐트를 작성한다. Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); //인텐트를 이용한 액티비티를 시작한다. (현재 액티비티는 onPause() 상태가 된다 결과를 받아올때까지) //결과를 받아오면 onActivityResult() 메소드가 호출된다. //비동기 요청이므로 실행순서는 바로 다음으로 넘어간다. startActivityForResult(enableIntent, REQUEST_ENABLE_BT); } else { Log.e("#####","else"); //켜져 있지만 쳇팅 서비스가 시작이 안되었다면 쳇팅서비스를 시작한다. if (mChatService == null) setupChat(); } } @Override public synchronized void onResume() { super.onResume(); if(D) Log.e(TAG, "+ ON RESUME +"); //onPause 상태에서 사용자가 블루투스 켜기를 승인했다면 다시 onResume() 메소드가 호출된다. if (mChatService != null) { Log.e("#####","mChatService != null"); //처음 시작했다면 상태가 STATE_NONE 이다. if (mChatService.getState() == BluetoothChatService.STATE_NONE) { Log.e("#####","mChatService.start()"); //블루투스 쳇팅서비스 시작하는 메소드 mChatService.start(); } } } //쳇팅하는데 필요한 각종 초기화 작업을 한다. private void setupChat() { Log.d(TAG, "setupChat()"); //대화내용을 표시하는 아답타 객체 생성하기. mConversationArrayAdapter = new ArrayAdapter (this, R.layout.message); //대화내용을 표시할 ListView 객체 얻어오기. mConversationView = (ListView) findViewById(R.id.in); //ListView 객체에 아답타를 연결한다. mConversationView.setAdapter(mConversationArrayAdapter); //전송할 문자열을 입력할 EditText 객체얻어오기. mOutEditText = (EditText) findViewById(R.id.edit_text_out); //EditText 객체에 액션 리스너를 등록한다. mOutEditText.setOnEditorActionListener(mWriteListener); //전송 버튼 객체를 얻어온다. mSendButton = (Button) findViewById(R.id.button_send); //버튼에 리스너객체를 생성해서 등록한다. mSendButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { //??? 의문이다.. 위에서 읽어왔는데 왜 다시 객체의 참조값을 읽어오는지 TextView view = (TextView) findViewById(R.id.edit_text_out); String message = view.getText().toString(); //입력한 문자열을 읽어와서 전송한다. sendMessage(message); } }); //블루투스 서비스 객체 생성하기. mChatService = new BluetoothChatService(this, mHandler); //StringBuffer 객체 생성하기. mOutStringBuffer = new StringBuffer(""); } @Override public synchronized void onPause() { super.onPause(); if(D) Log.e(TAG, "- ON PAUSE -"); } @Override public void onStop() { super.onStop(); if(D) Log.e(TAG, "-- ON STOP --"); } @Override public void onDestroy() { super.onDestroy(); // Stop the Bluetooth chat services if (mChatService != null) mChatService.stop(); if(D) Log.e(TAG, "--- ON DESTROY ---"); } //다른 기기에서 자신의 기기를 300 초 동안 검색할수 있도록 만든다. private void ensureDiscoverable() { if(D) Log.d(TAG, "ensure discoverable"); //아답타의 스켄모드가 Disvoverable 상태가 아니라면 if (mBluetoothAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { //인텐트를 작성하고 Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); //300초 동안 검색할수 있도록 액스트라 값을 가지고 discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); //액티비티를 실행한다.(현재 액티비티는 onPause() 상태가 되었다가 승인하면 다시 onResume()이된다.) Log.e("#####","startActivity(discoverableIntent);"); startActivity(discoverableIntent); } } //메세지 보내기. private void sendMessage(String message) { //서비스의 상태가 연결 상태가 아니라면 if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) { //연결되지 않았다는 메세지를 띄우고 Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show(); //메소드를 끝낸다. return; } //보낼 메세지가 있다면 if (message.length() > 0) { //메세지를 byte[] 형태로 얻어온다. byte[] send = message.getBytes(); //서비스 객체를 이용해서 전송한다. mChatService.write(send); //StringBuffer 객체와 입력창을 초기화 한다. mOutStringBuffer.setLength(0); mOutEditText.setText(mOutStringBuffer); } } // The action listener for the EditText widget, to listen for the return key private TextView.OnEditorActionListener mWriteListener = new TextView.OnEditorActionListener() { public boolean onEditorAction(TextView view, int actionId, KeyEvent event) { // If the action is a key-up event on the return key, send the message if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) { String message = view.getText().toString(); sendMessage(message); } if(D) Log.i(TAG, "END onEditorAction"); return true; } }; // The Handler that gets information back from the BluetoothChatService private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_STATE_CHANGE: //메세비 서비스의 상태가 바뀌었을때 if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1); switch (msg.arg1) { //연결된 상태 case BluetoothChatService.STATE_CONNECTED: mTitle.setText(R.string.title_connected_to); mTitle.append(mConnectedDeviceName); mConversationArrayAdapter.clear(); break; //연결을 시도하고 있는 상태 case BluetoothChatService.STATE_CONNECTING: mTitle.setText(R.string.title_connecting); break; case BluetoothChatService.STATE_LISTEN: //아무런 상태도 아닐때 case BluetoothChatService.STATE_NONE: mTitle.setText(R.string.title_not_connected); break; } break; //메세지를 전송하는 상태 case MESSAGE_WRITE: //전달된 문자열을 byte 배열 byte[] writeBuf = (byte[]) msg.obj; //바이트 배열을 이용해서 String 객체를 생성한후 String writeMessage = new String(writeBuf); //대화창에 자신이 보낸 메세지도 표시를 해준다. mConversationArrayAdapter.add("Me: " + writeMessage); break; //원격 디바이스에서 전송한 메세지를 읽어오는 상태 case MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; //읽어온 메세지를 화면에 출력하기 위해서 String 으로 변환한다. String readMessage = new String(readBuf, 0, msg.arg1); mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage); break; //연결한 장치명을 표시한다. case MESSAGE_DEVICE_NAME: // save the connected device's name mConnectedDeviceName = msg.getData().getString(DEVICE_NAME); Toast.makeText(getApplicationContext(), "Connected to " + mConnectedDeviceName, Toast.LENGTH_SHORT).show(); break; //토스트 메세지를 띄우기 위해서. case MESSAGE_TOAST: Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST), Toast.LENGTH_SHORT).show(); break; } } }; public void onActivityResult(int requestCode, int resultCode, Intent data) { if(D) Log.d(TAG, "onActivityResult " + resultCode); switch (requestCode) { case REQUEST_CONNECT_DEVICE: // When DeviceListActivity returns with a device to connect if (resultCode == Activity.RESULT_OK) { // Get the device MAC address String address = data.getExtras() .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS); // Get the BLuetoothDevice object BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // Attempt to connect to the device mChatService.connect(device); } break; case REQUEST_ENABLE_BT: //사용자가 블루투스 켜는것을 승인했을때 if (resultCode == Activity.RESULT_OK) { //블루투스가 켜져 있으므로 쳇팅을 할수 있도록 셋업한다. setupChat(); } else { // User did not enable Bluetooth or an error occured Log.d(TAG, "BT not enabled"); Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show(); finish(); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { //메뉴전개자 객체 얻어오기. MenuInflater inflater = getMenuInflater(); //옵션 메뉴를 전개한다. inflater.inflate(R.menu.option_menu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.scan: //장치에 연결하는 액티비티 실행하기 위해서 인텐트를 작성한다. Intent serverIntent = new Intent(this, DeviceListActivity.class); startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE); return true; case R.id.discoverable: // Ensure this device is discoverable by others ensureDiscoverable(); return true; } return false; } } // BluetoothChatService.java import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothServerSocket; import android.bluetooth.BluetoothSocket; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; /** * This class does all the work for setting up and managing Bluetooth * connections with other devices. It has a thread that listens for * incoming connections, a thread for connecting with a device, and a * thread for performing data transmissions when connected. */ public class BluetoothChatService { // Debugging private static final String TAG = "BluetoothChatService"; private static final boolean D = true; // Name for the SDP record when creating server socket private static final String NAME = "BluetoothChat"; // Unique UUID for this application private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); // Member fields private final BluetoothAdapter mAdapter; private final Handler mHandler; private AcceptThread mAcceptThread; private ConnectThread mConnectThread; private ConnectedThread mConnectedThread; private int mState; // Constants that indicate the current connection state public static final int STATE_NONE = 0; // we're doing nothing public static final int STATE_LISTEN = 1; // now listening for incoming connections public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection public static final int STATE_CONNECTED = 3; // now connected to a remote device /** * Constructor. Prepares a new BluetoothChat session. * @param context The UI Activity Context * @param handler A Handler to send messages back to the UI Activity */ public BluetoothChatService(Context context, Handler handler) { mAdapter = BluetoothAdapter.getDefaultAdapter(); mState = STATE_NONE; mHandler = handler; } //Message 를 핸들러에 보낸다. private synchronized void setState(int state) { if (D) Log.d(TAG, "setState() " + mState + " -> " + state); mState = state; //핸들러에 새로운 상태를 넘겨준다 UI 액티비티가 수정될수 있도록. mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget(); } //상태값 얻어오는 메소드 public synchronized int getState() { return mState; } //쳇팅 서비스를 시작하는 메소드 //BluetoothChat 액티비티의 onResume() 메소드에서 호출된다. public synchronized void start() { if (D) Log.d(TAG, "start"); //연결을 시도하는 스레드가 있다면 취소한다. if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} //현재 연결된 스래드가 있다면 취소한다. if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} // Start the thread to listen on a BluetoothServerSocket if (mAcceptThread == null) { mAcceptThread = new AcceptThread(); mAcceptThread.start(); } setState(STATE_LISTEN); } //인자로 전달된 원격 블루투스 장치에 연결을 시도하는 메소드 //사용자가 연결하고자하는 장치가 인자로 전달된다. public synchronized void connect(BluetoothDevice device) { if (D) Log.d(TAG, "connect to: " + device); //현재 연결하고 연결을 시도하고 있는 상태라면 취소한다. if (mState == STATE_CONNECTING) { if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} } //현태 연결된 상태라면 취소한다. if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} //인자로 전달된 장치에 연결을 시도하기 위해 스레드 객체를 생성한다. mConnectThread = new ConnectThread(device); //연결을 시도하는 스레드 시작하기. mConnectThread.start(); //현재 상태를 바꿔준다.(연결을 시도하는 상태로 UI 액티비티에서 출력할수 있도록) setState(STATE_CONNECTING); } /** * Start the ConnectedThread to begin managing a Bluetooth connection * @param socket The BluetoothSocket on which the connection was made * @param device The BluetoothDevice that has been connected */ public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) { if (D) Log.d(TAG, "connected"); if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;} // Start the thread to manage the connection and perform transmissions mConnectedThread = new ConnectedThread(socket); mConnectedThread.start(); //연결한 장치명을 UI 액티비티에서 출력하기 위해서 Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME); Bundle bundle = new Bundle(); bundle.putString(BluetoothChat.DEVICE_NAME, device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); setState(STATE_CONNECTED); } //모든 스레드를 정지 시키는 메소드 public synchronized void stop() { if (D) Log.d(TAG, "stop"); if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;} if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;} if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread = null;} //상태값도 바꿔준다. setState(STATE_NONE); } /** * Write to the ConnectedThread in an unsynchronized manner * @param out The bytes to write * @see ConnectedThread#write(byte[]) */ public void write(byte[] out) { // Create temporary object ConnectedThread r; // Synchronize a copy of the ConnectedThread synchronized (this) { if (mState != STATE_CONNECTED) return; r = mConnectedThread; } // Perform the write unsynchronized r.write(out); } /** * 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 msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(BluetoothChat.TOAST, "Unable to connect device"); msg.setData(bundle); mHandler.sendMessage(msg); } /** * 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 msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST); Bundle bundle = new Bundle(); bundle.putString(BluetoothChat.TOAST, "Device connection was lost"); msg.setData(bundle); mHandler.sendMessage(msg); } //원격 접속 요청을 받아들이는 스레드 private class AcceptThread extends Thread { // The local server socket private final BluetoothServerSocket mmServerSocket; public AcceptThread() { BluetoothServerSocket tmp = null; // Create a new listening server socket try { tmp = mAdapter. listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { Log.e(TAG, "listen() failed", e); } mmServerSocket = tmp; } public void run() { if (D) Log.d(TAG, "BEGIN mAcceptThread" + this); setName("AcceptThread"); BluetoothSocket socket = null; // Listen to the server socket if we're not connected while (mState != STATE_CONNECTED) { try { // This is a blocking call and will only return on a // successful connection or an exception socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "accept() failed", e); break; } // If a connection was accepted if (socket != null) { synchronized (BluetoothChatService.this) { switch (mState) { case STATE_LISTEN: case STATE_CONNECTING: // Situation normal. Start the connected thread. connected(socket, socket.getRemoteDevice()); break; case STATE_NONE: case STATE_CONNECTED: // Either not ready or already connected. Terminate new socket. try { socket.close(); } catch (IOException e) { Log.e(TAG, "Could not close unwanted socket", e); } break; } } } } if (D) Log.i(TAG, "END mAcceptThread"); } public void cancel() { if (D) Log.d(TAG, "cancel " + this); try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of server failed", e); } } } /** * This thread runs while attempting to make an outgoing connection * with a device. It runs straight through; the connection either * succeeds or fails. */ //장치에 연결을 시도하는 스레드 private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; //생성자로 연결할 장치를 주입받고 BluetoothSocket 객체를 얻어온다. public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; try { //주어진 장치에 연결해서 BluetoothSocket 객체를 얻어온다.(내가 Client 의 입장이다) tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, "create() failed", e); } //에러가 발생했다면 mmSocket 은 null 일 것이다. mmSocket = tmp; } public void run() { Log.i(TAG, "BEGIN mConnectThread"); //스레드의 이름 설정하기 setName("ConnectThread"); //느려질수 있으므로 Discovery 를 취소한다. mAdapter.cancelDiscovery(); // Make a connection to the BluetoothSocket try { //연결이 성공하거나 혹은 익셉션이 발생할때 까지 이 메소드는 블록킹된다. mmSocket.connect(); //소켓 객체를 이용해서 연결하기. } catch (IOException e) { connectionFailed();//연결이 실패했다면 try { mmSocket.close(); //소켓을 닫아준다. } catch (IOException e2) { Log.e(TAG, "unable to close() socket during connection failure", e2); } // Start the service over to restart listening mode BluetoothChatService.this.start(); return; } // Reset the ConnectThread because we're done synchronized (BluetoothChatService.this) { //연결이 성공하였기 때문에 스레드를 비우고 mConnectThread = null; } //원격 블루투스 장치에 연결 되었을때 사용하는 스레드를 기동하는 메소드를 호출한다. connected(mmSocket, mmDevice); } //취소하는 메소드 public void cancel() { try { //소켓을 닫아준다. mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } /** * This thread runs during a connection with a remote device. * It handles all incoming and outgoing transmissions. */ private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "create ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the BluetoothSocket input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // Keep listening to the InputStream while connected while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); // Send the obtained bytes to the UI Activity mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "disconnected", e); connectionLost(); break; } } } /** * Write to the connected OutStream. * @param buffer The bytes to write */ public void write(byte[] buffer) { try { mmOutStream.write(buffer); // Share the sent message back to the UI Activity mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer) .sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } }
이 블로그 검색
2013년 4월 11일 목요일
Bluetooch Chat
피드 구독하기:
댓글 (Atom)
댓글 없음:
댓글 쓰기