본문 바로가기
혼자 코딩(안드로이드 feat.JAVA)

[안드로이드 스튜디오 - 자바] 블루투스 연결_001

by 서하란 2023. 2. 8.
반응형
SMALL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 
import android.bluetooth.BluetoothSocket;
import android.os.SystemClock;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
 
public class ConnectedThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;
 
    public ConnectedThread(BluetoothSocket socket) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
 
        // Get the input and output streams, using temp objects because
        // member streams are final
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {
        }
 
        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }
 
    @Override
    public void run() {
        byte[] buffer = new byte[1024];  // buffer store for the stream
        int bytes; // bytes returned from read()
        // Keep listening to the InputStream until an exception occurs
        while (true) {
            try {
                // Read from the InputStream
                bytes = mmInStream.available();
                if (bytes != 0) {
                    buffer = new byte[1024];
                    SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
                    bytes = mmInStream.available(); // how many bytes are ready to be read?
                    bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
                }
            } catch (IOException e) {
                e.printStackTrace();
 
                break;
            }
        }
    }
 
    /* Call this from the main activity to send data to the remote device */
    public void write(String input) {
        byte[] bytes = input.getBytes();           //converts entered String into bytes
        try {
            mmOutStream.write(bytes);
        } catch (IOException e) {
        }
    }
 
    /* Call this from the main activity to shutdown the connection */
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
        }
    }
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
package com.example.mybluetooth001_002;
 
import android.Manifest;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
 
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
 
public class MainActivity extends AppCompatActivity {
    TextView mTvBluetoothStatus;
    TextView mTvReceiveData;
    TextView mTvSendData;
    TextView mTvReceiveDataView;
    Button mBtnConnect;
    Button mBtnSendData;
 
    private BluetoothAdapter mBluetoothAdapter;
    Set<BluetoothDevice> mPairedDevices;
    List<String> mListPairedDevices;
 
    Handler mBluetoothHandler;
    ConnectedBluetoothThread mThreadConnectedBluetooth;
    BluetoothDevice mBluetoothDevice;
    BluetoothSocket mBluetoothSocket;
 
 
    final static int BT_MESSAGE_READ = 2;
    final static int BT_CONNECTING_STATUS = 3;
    final static UUID BT_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
 
 
    ConnectedThread connectedThread;
 
    //tag를 사용하기 위한 선언
    private static final String TAG = "MainActivity";
    private int readBufferPosition; // 버퍼 내 문자 저장 위치
 
    private BluetoothGatt mBluetoothGatt;
 
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
 
 
        //블루투스가 되는지 설정
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this"블루투스 미지원 기기입니다.", Toast.LENGTH_SHORT).show();
            finish();
        }
 
        //권한 설정
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            requestPermissions(
                    new String[]{
                            Manifest.permission.BLUETOOTH,
                            Manifest.permission.BLUETOOTH_SCAN,
                            Manifest.permission.BLUETOOTH_ADVERTISE,
                            Manifest.permission.BLUETOOTH_CONNECT,
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.ACCESS_COARSE_LOCATION
                    },
                    1);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            requestPermissions(
                    new String[]{
                            Manifest.permission.BLUETOOTH
 
                    },
                    1);
        }
 
        mTvBluetoothStatus = (TextView)findViewById(R.id.tvBluetoothStatus);
        mTvReceiveData = (TextView)findViewById(R.id.tvReceiveData);
        mTvReceiveDataView = (TextView)findViewById(R.id.tvReceiveDataView);
        mTvSendData =  (EditText) findViewById(R.id.tvSendData);
        mBtnConnect = (Button)findViewById(R.id.btnConnect);
        mBtnSendData = (Button)findViewById(R.id.btnSendData);
 
        // 블루투스 기능을 지원하는지 알아오는 메서드
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        //mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();
        //mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        // Initializes Bluetooth adapter.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
 
 
        // 버튼 눌렀을 때 동작하는 기능들
        mBtnConnect.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                listPairedDevices();
            }
        });
        mBtnSendData.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mThreadConnectedBluetooth != null) {
                    mThreadConnectedBluetooth.write(mTvSendData.getText().toString());
                    mTvSendData.setText("");
                }
            }
        });
 
        // 블루투스 핸들러로 연결 뒤, 수신된 데이터를 읽어와 ReceiveData텍스트 뷰에 표시해주는 부분
        mBluetoothHandler = new Handler(Looper.getMainLooper()){
            public void handleMessage(android.os.Message msg){
                if(msg.what == BT_MESSAGE_READ){
                    String readMessage = null;
                    try {
                        readMessage = new String((byte[]) msg.obj, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    mTvReceiveData.setText(readMessage);
                }
            }
        };
    }
 
    void listPairedDevices() {
 
        // 블루투스 활성화 상태 확인
        try{
            if (mBluetoothAdapter.isEnabled()) {
                // 이미 Paired된 Device목록을 얻어옴
                mPairedDevices = mBluetoothAdapter.getBondedDevices();
 
                //페어링 된 장치가 존재한다면 새로운 알림창을 생성
                if (mPairedDevices.size() > 0) {
                    AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle("장치 선택");
 
                    mListPairedDevices = new ArrayList<String>();
                    for (BluetoothDevice device : mPairedDevices) {
                        mListPairedDevices.add(device.getName());
                        //mListPairedDevices.add(device.getName() + "\n" + device.getAddress());
                    }
                    final CharSequence[] items = mListPairedDevices.toArray(new CharSequence[mListPairedDevices.size()]);
                    mListPairedDevices.toArray(new CharSequence[mListPairedDevices.size()]);
 
                    //장치를 누르면 connectSelectedDevice로 전달
                    builder.setItems(items, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int item) {
                            for (BluetoothDevice device : mPairedDevices) {
                                if (device.getName().equals(items[item].toString())) {
                                    connectSelectedDevice(String.valueOf(device));
                                    break;
                                }
                            }
                        }
                    });
                    // 알림창을 뛰어줌
                    AlertDialog alert = builder.create();
                    alert.show();
                } else {
                    Toast.makeText(getApplicationContext(), "페어링된 장치가 없습니다.", Toast.LENGTH_LONG).show();
                }
            }
            else {
                Toast.makeText(getApplicationContext(), "블루투스가 비활성화 되어 있습니다.", Toast.LENGTH_SHORT).show();
            }
 
        }catch (SecurityException e)
        {
            e.printStackTrace();
        }
 
    }
 
    // listPairedDevices를 통하여 전달받은 매개변수 값은 장치 이름
    @SuppressWarnings({"MissingPermission"})
    private void connectSelectedDevice(String address) {
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        mBluetoothGatt = device.connectGatt(thisfalse, mGattCallback);
    }
 
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @SuppressLint("MissingPermission")
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
        }
 
        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            // do something with the services
        }
    };
 
 
    @SuppressLint("MissingPermission")
    private BluetoothSocket createBluetoothLEConnection(BluetoothDevice device) {
        BluetoothSocket socket = null;
        try {
            socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return socket;
    }
 
    @SuppressLint("MissingPermission")
    private BluetoothGatt connectGatt(BluetoothDevice device) {
        return device.connectGatt(thisfalse, mGattCallback);
    }
 
    @SuppressWarnings({"MissingPermission"})
    private class ConnectedBluetoothThread extends Thread {
 
        private final BluetoothSocket mmSocket;
        private InputStream mmInStream;
        private OutputStream mmOutStream;
 
        //쓰레드 초기화
        public void run() {
            readBufferPosition = 0;
            byte[] buffer = new byte[1024];
            int bytes;
 
            //데이터를 지속적으로 확인하는...
            while (true) {//계속 확인하는 중인데 어떻게 안보내진다
                try {
                    //inputStream 계속 읽기(값을 받는다)
                    //bytes = mmInStream.available();
                    bytes = mmInStream.read(buffer);
                    String incomingMessage = new String(buffer, 0, bytes);
                    Log.d(TAG, "Input Stream : " + incomingMessage);
 
                    if (bytes >= 0) {
                        SystemClock.sleep(100);
                        bytes = mmInStream.available();
                        bytes = mmInStream.read(buffer, 0, bytes);
                        mBluetoothHandler.obtainMessage(BT_MESSAGE_READ, bytes, -1, buffer).sendToTarget();
 
                    }
                } catch (IOException e) {
                    try {
                        mmSocket.connect();
                    } catch (IOException ex) {
                        Log.e(TAG, "Unable to connect to socket", ex);
                        break;
                    }
                }
            }
        }
 
        public ConnectedBluetoothThread(BluetoothSocket socket) {
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
 
            // 소켓을 통한 전송을 처리
            // BluetoothSocket의 inputstream 과 outputstream을 얻는다.
            try {
                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();
            } catch (IOException e) {
                Toast.makeText(getApplicationContext(), "소켓 연결 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
            }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
 
        }
 
        //데이터 전송을 위한 스레드 메서드
        public void write(String str) {
            byte[] bytes = str.getBytes();
 
            try {
                //값을 쓰는 부분(값을 보낸다.)
                mmOutStream.write(bytes);
            } catch (IOException e) {
                //e: "java.io.IOException: socket closed"
                Toast.makeText(getApplicationContext(), "데이터 전송 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
 
                // 소켓을 다시 생성하고 연결한다.
                try {
                    mBluetoothSocket = mBluetoothDevice.createRfcommSocketToServiceRecord(BT_UUID);
                    mBluetoothSocket.connect();
                    mmOutStream = mBluetoothSocket.getOutputStream();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
 
        public void cancel() {
            try {
                mmSocket.close();
            } catch (IOException e) {
                Toast.makeText(getApplicationContext(), "소켓 해제 중 오류가 발생했습니다.", Toast.LENGTH_LONG).show();
            }
        }
    }
 
 
 
 
}
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
 
 
    <Button
        android:id="@+id/btnConnect"
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:layout_marginStart="30dp"
        android:layout_marginLeft="30dp"
        android:layout_marginTop="30dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="연결하기"
        app:layout_constraintTop_toBottomOf="@+id/tvBluetoothStatus" />
 
    <TextView
        android:id="@+id/tvBluetoothStatus"
        android:layout_width="170dp"
        android:layout_height="20dp"
        android:layout_marginStart="8dp"
        android:text="status"
        app:layout_constraintBottom_toBottomOf="@+id/btnConnect"
        app:layout_constraintStart_toEndOf="@+id/btnConnect"
        app:layout_constraintTop_toTopOf="@+id/btnConnect" />
 
 
 
    <TextView
        android:id="@+id/tvReceiveData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="Receive"
        app:layout_constraintStart_toStartOf="@+id/btnSendData"
        app:layout_constraintTop_toBottomOf="@+id/btnSendData" />
 
 
    <TextView
        android:id="@+id/tvReceiveDataView"
        android:layout_width="307dp"
        android:layout_height="427dp"
        android:layout_marginBottom="128dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="@+id/tvReceiveData" />
 
    <Button
        android:id="@+id/btnSendData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="전송"
        app:layout_constraintStart_toStartOf="@+id/btnConnect"
        app:layout_constraintTop_toBottomOf="@+id/btnConnect" />
 
    <EditText
        android:id="@+id/tvSendData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="Send Data"
        app:layout_constraintStart_toEndOf="@+id/btnSendData"
        app:layout_constraintTop_toTopOf="@+id/btnSendData" />
 
</androidx.constraintlayout.widget.ConstraintLayout>
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
 
    <!-- 블루투스 사용하기 위해 정의 -->
    <uses-permission
        android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <!-- 장치를 찾거나 블루투스 설정을 관리 -->
    <uses-permission
        android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
 
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
 
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
 
    <!-- 저전력 블루투스(지원하지 않는 기기에도 앱 제공 -->
    <uses-feature android:name="android.hardware.bluetooth_le" android:required="false"/>
 
 
    <uses-feature
        android:name="android.hardware.bluetooth"
        android:required="true" />
 
    <uses-feature
        android:name="android.hardware.bluetooth_le"
        android:required="false" />
 
    <uses-feature
        android:name="android.hardware.location.gps"
        android:required="true" />
 
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyBluetooth001_002"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
 
            <meta-data
                android:name="android.app.lib_name"
                android:value="" />
        </activity>
    </application>
 
</manifest>
cs

아직 완성된 건 아니고 일단 연결을 하는건데

 

핸드폰의 블루투스를 키고 - 대상 기기를 연결한 후 어플내에서 다시 연결을 해줘야한다.

 

권한은 있는데로 다 넣어줬다 혹시 몰라서..

반응형
LIST

댓글