Skip to content

Commit 8f9c5a5

Browse files
authored
Merge pull request #88 from sieunju/develop
[RELEASE] 1.3.5-beta02
2 parents c725388 + 70df653 commit 8f9c5a5

42 files changed

Lines changed: 648 additions & 173 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

β€Žapp/build.gradleβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ dependencies {
5757
// implementation("com.github.sieunju.httptracking:interceptor:1.3.2")
5858
implementation(project(':ui'))
5959
implementation(project(':interceptor'))
60+
implementation(project(":hardware"))
6061

6162
/**
6263
* Android X

β€Žapp/src/main/java/com/hmju/httptracking/BleTestProvider.ktβ€Ž

Lines changed: 64 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.bluetooth.BluetoothDevice
66
import android.bluetooth.BluetoothGatt
77
import android.bluetooth.BluetoothGattCallback
88
import android.bluetooth.BluetoothGattCharacteristic
9+
import android.bluetooth.BluetoothGattDescriptor
910
import android.bluetooth.BluetoothManager
1011
import android.bluetooth.BluetoothProfile
1112
import android.bluetooth.le.ScanCallback
@@ -14,20 +15,16 @@ import android.bluetooth.le.ScanResult
1415
import android.bluetooth.le.ScanSettings
1516
import android.content.Context
1617
import android.os.Build
17-
import android.os.SystemClock
1818
import androidx.annotation.RequiresPermission
1919
import androidx.appcompat.app.AppCompatActivity
20-
import androidx.core.util.forEach
21-
import androidx.core.util.isNotEmpty
2220
import hmju.http.tracking_interceptor.TrackingDataManager
23-
import hmju.http.tracking_interceptor.model.ChildModel
24-
import hmju.http.tracking_interceptor.model.ContentsModel
25-
import hmju.http.tracking_interceptor.model.SummaryModel
26-
import hmju.http.tracking_interceptor.model.TitleModel
27-
import hmju.http.tracking_interceptor.model.TrackingModel
21+
import hmju.tracking.hardware.HardwareTrackingModel
2822
import timber.log.Timber
23+
import java.nio.ByteBuffer
2924
import java.text.SimpleDateFormat
3025
import java.util.Locale
26+
import java.util.UUID
27+
import java.util.concurrent.Executors
3128

3229

3330
class BleTestProvider(
@@ -117,24 +114,23 @@ class BleTestProvider(
117114

118115
override fun onScanResult(callbackType: Int, result: ScanResult?) {
119116
if (result == null) return
120-
// if (!duplicationSet.contains(result.device.address)) {
121-
// duplicationSet.add(result.device.address)
122-
// TrackingDataManager.getInstance().add(getBleTrackingModel(result, dateFmt))
123-
// }
124-
TrackingDataManager.getInstance().add(getBleTrackingModel(result, dateFmt))
117+
if (!duplicationSet.contains(result.device.address)) {
118+
duplicationSet.add(result.device.address)
119+
TrackingDataManager.getInstance().add(HardwareTrackingModel(result))
120+
}
125121
}
126122

127123
override fun onBatchScanResults(results: MutableList<ScanResult>?) {
128124
if (results == null) return
129-
results.forEach {result ->
130-
TrackingDataManager.getInstance().add(getBleTrackingModel(result, dateFmt))
125+
results.forEach { result ->
126+
TrackingDataManager.getInstance().add(HardwareTrackingModel(result))
131127
}
132128
}
133129
}
134130
val setting = ScanSettings.Builder()
135131
.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
136132
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
137-
.setReportDelay(1000)
133+
// .setReportDelay(1000)
138134
.build()
139135

140136
val filter = ScanFilter.Builder()
@@ -145,18 +141,64 @@ class BleTestProvider(
145141
}
146142

147143
@SuppressLint("MissingPermission")
148-
private fun startConnection(
149-
macAddress: String
144+
fun startConnection(
145+
macAddress: String,
146+
findUuid: String
150147
) {
151148
val callback = object : BleGattCallback() {
152149
override fun onConnected(gatt: BluetoothGatt) {
153-
connectionSet.add(macAddress)
154-
Timber.d("μ—°κ²° μ™„λ£Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. $macAddress μ—°κ²°λœ 개수:${connectionSet.size}")
150+
Timber.d("onConnected $gatt")
155151
}
156152

157153
override fun onDisconnected(gatt: BluetoothGatt) {
158-
connectionSet.remove(macAddress)
159-
Timber.d("μ—°κ²° ν•΄μ œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. $macAddress μ—°κ²°λœ 개수:${connectionSet.size}")
154+
Timber.d("onDisconnected $gatt")
155+
}
156+
157+
override fun onServicesDiscovered(gatt: BluetoothGatt) {
158+
var characteristic: BluetoothGattCharacteristic? = null
159+
for (service in gatt.services) {
160+
for (character in service.characteristics) {
161+
val uuid = character.uuid.toString().uppercase()
162+
if (findUuid.contains(uuid) || uuid.contains(findUuid)) {
163+
characteristic = character
164+
break
165+
}
166+
}
167+
}
168+
Timber.d("characteristic μ°ΎμŠ΅λ‹ˆλ‹€..$characteristic")
169+
if (characteristic == null) return
170+
val writeBytes = ByteBuffer.allocate(2)
171+
.putShort(10000.toShort())
172+
.array() + ByteBuffer.allocate(2)
173+
.putShort(10387.toShort()).array()
174+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
175+
Timber.d("데이터 μ‚¬μš©ν•©λ‹ˆλ‹€. ${writeBytes.contentToString()}")
176+
gatt.writeCharacteristic(
177+
characteristic,
178+
writeBytes,
179+
BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
180+
)
181+
Executors.newSingleThreadExecutor().submit {
182+
Thread.sleep(300)
183+
gatt.setCharacteristicNotification(characteristic, true)
184+
val descriptor = characteristic.getDescriptor(
185+
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
186+
)
187+
gatt.writeDescriptor(
188+
descriptor,
189+
BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
190+
)
191+
}
192+
}
193+
}
194+
195+
override fun onCharacteristicRead(gatt: BluetoothGatt, value: ByteArray) {
196+
TrackingDataManager.getInstance().add(HardwareTrackingModel(gatt, value))
197+
}
198+
199+
override fun onCharacteristicChanged(gatt: BluetoothGatt, value: ByteArray) {
200+
Timber.d("onCharacteristicChanged ${value.contentToString()}")
201+
TrackingDataManager.getInstance().add(HardwareTrackingModel(gatt, value))
160202
}
161203
}
162204
val device = adapter.getRemoteDevice(macAddress)
@@ -167,78 +209,4 @@ class BleTestProvider(
167209
BluetoothDevice.TRANSPORT_LE
168210
).also { it.requestMtu(300) }
169211
}
170-
171-
@SuppressLint("MissingPermission")
172-
private fun getBleTrackingModel(
173-
data: ScanResult,
174-
dateFmt: SimpleDateFormat
175-
): TrackingModel {
176-
val bootTimeMillis = System.currentTimeMillis() - SystemClock.elapsedRealtime()
177-
val scanTime = bootTimeMillis + (data.timestampNanos / 1_000_000L)
178-
val device = data.device
179-
val summary = SummaryModel(
180-
colorHexCode = "#367CEE",
181-
titleList = listOf(
182-
"πŸ›œBLE",
183-
"Advertising",
184-
dateFmt.format(scanTime)
185-
),
186-
contentsList = listOf(
187-
if (!device.name.isNullOrEmpty()) device.name else "Unknown",
188-
device.address,
189-
"${data.rssi}dBm"
190-
)
191-
)
192-
val req = mutableSetOf<ChildModel>()
193-
req.add(TitleModel("#C62828", "[Device]"))
194-
if (!device.name.isNullOrEmpty()) {
195-
req.add(ContentsModel(text = "Name:${device.name}"))
196-
}
197-
req.add(ContentsModel(hexCode = "#222222", text = device.address))
198-
when (device.type) {
199-
BluetoothDevice.DEVICE_TYPE_LE -> "Low Energy"
200-
BluetoothDevice.DEVICE_TYPE_DUAL -> "Dual Mode"
201-
BluetoothDevice.DEVICE_TYPE_CLASSIC -> "Classic"
202-
BluetoothDevice.DEVICE_TYPE_UNKNOWN -> "Unknown"
203-
else -> "Invalid"
204-
}.run { req.add(ContentsModel(hexCode = "#222222", text = "Device type:${this}")) }
205-
req.add(ContentsModel(hexCode = "#222222", text = "πŸ“Ά${data.rssi}dBm"))
206-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
207-
val phy = when (data.primaryPhy) {
208-
BluetoothDevice.PHY_LE_1M -> "LE 1M"
209-
BluetoothDevice.PHY_LE_2M -> "LE 2M"
210-
BluetoothDevice.PHY_LE_CODED -> "LE Coded"
211-
else -> "Unknown"
212-
}
213-
req.add(ContentsModel(hexCode = "#222222", text = "Phy:${phy}"))
214-
req.add(ContentsModel(text = "Connectable:${data.isConnectable}"))
215-
}
216-
val scanRecord = data.scanRecord
217-
if (scanRecord != null) {
218-
req.add(TitleModel("#C62828", "[UUID]"))
219-
if (!scanRecord.serviceUuids.isNullOrEmpty()) {
220-
scanRecord.serviceUuids.forEach {
221-
req.add(ContentsModel(hexCode = "#222222", text = it.uuid.toString()))
222-
}
223-
}
224-
if (scanRecord.manufacturerSpecificData.isNotEmpty()) {
225-
req.add(TitleModel("#C62828", "[Manufacture]"))
226-
scanRecord.manufacturerSpecificData.forEach { key, value ->
227-
ContentsModel(
228-
hexCode = "#222222",
229-
text = "ID:${String.format("0x%04X", key)}"
230-
).run { req.add(this) }
231-
ContentsModel(
232-
hexCode = "#222222",
233-
text = value.joinToString { String.format("%02X", it) }
234-
).run { req.add(this) }
235-
}
236-
}
237-
}
238-
return TrackingModel(
239-
req = req.toList(),
240-
res = listOf(),
241-
summary = summary
242-
)
243-
}
244212
}

β€Žapp/src/main/java/com/hmju/httptracking/MainActivity.ktβ€Ž

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ internal class MainActivity : AppCompatActivity() {
1212

1313
private lateinit var httpTest: HttpTestProvider
1414
private lateinit var bleTest: BleTestProvider
15+
private lateinit var nfcTest: NfcTestProvider
1516

1617
private val permissionsLauncher = registerForActivityResult(
1718
ActivityResultContracts.RequestMultiplePermissions()
@@ -32,13 +33,21 @@ internal class MainActivity : AppCompatActivity() {
3233
setContentView(R.layout.activity_main)
3334
httpTest = HttpTestProvider(this).onInit()
3435
bleTest = BleTestProvider(this)
36+
nfcTest = NfcTestProvider(this)
3537

3638
findViewById<Button>(R.id.bFileUpload).setOnClickListener {
3739
httpTest.startFileUpload()
3840
}
41+
findViewById<Button>(R.id.bNfc).setOnClickListener { nfcTest.startTag() }
3942

4043
findViewById<Button>(R.id.bHttp).setOnClickListener { httpTest.startHttpTest() }
41-
findViewById<Button>(R.id.bBle).setOnClickListener { bleTest.startBleAdv() }
44+
findViewById<Button>(R.id.bBleAdv).setOnClickListener { bleTest.startBleAdv() }
45+
findViewById<Button>(R.id.bBleConnect).setOnClickListener {
46+
bleTest.startConnection(
47+
macAddress = "01:A1:02:14:89:27",
48+
findUuid = "02001201-4202-EAB5-ED11"
49+
)
50+
}
4251

4352
permissionsLauncher.launch(getPermissions())
4453
onBackPressedDispatcher.addCallback(this, backPressCallback)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.hmju.httptracking
2+
3+
import android.nfc.NfcAdapter
4+
import android.nfc.tech.Ndef
5+
import android.os.Bundle
6+
import androidx.appcompat.app.AppCompatActivity
7+
import hmju.http.tracking_interceptor.TrackingDataManager
8+
import hmju.tracking.hardware.HardwareTrackingModel
9+
10+
class NfcTestProvider(
11+
private val activity: AppCompatActivity
12+
) {
13+
14+
private val adapter: NfcAdapter by lazy { NfcAdapter.getDefaultAdapter(activity) }
15+
16+
private val callback = NfcAdapter.ReaderCallback { tag ->
17+
if (tag == null) return@ReaderCallback
18+
try {
19+
val ndef = Ndef.get(tag) ?: throw NullPointerException("Ndef is Null")
20+
if (!ndef.isConnected) {
21+
ndef.connect()
22+
}
23+
TrackingDataManager.getInstance().add(HardwareTrackingModel(ndef))
24+
} catch (ex: Exception) {
25+
ex.printStackTrace()
26+
}
27+
}
28+
29+
fun startTag() {
30+
val flags = NfcAdapter.FLAG_READER_NFC_A or
31+
NfcAdapter.FLAG_READER_NFC_B or
32+
NfcAdapter.FLAG_READER_NFC_F or
33+
NfcAdapter.FLAG_READER_NFC_V
34+
val config = Bundle()
35+
config.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 20)
36+
adapter.enableReaderMode(activity, callback, flags, config)
37+
}
38+
}

β€Žapp/src/main/res/layout/activity_main.xmlβ€Ž

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,17 @@
2121
android:text="NFC ν…ŒμŠ€νŠΈ" />
2222

2323
<androidx.appcompat.widget.AppCompatButton
24-
android:id="@+id/bBle"
24+
android:id="@+id/bBleAdv"
2525
android:layout_width="match_parent"
2626
android:layout_height="wrap_content"
27-
android:text="BLE ν…ŒμŠ€νŠΈ" />
27+
android:text="BLE ADV ν…ŒμŠ€νŠΈ" />
28+
29+
<androidx.appcompat.widget.AppCompatButton
30+
android:id="@+id/bBleConnect"
31+
android:layout_width="match_parent"
32+
android:layout_height="wrap_content"
33+
android:text="BLE Connect ν…ŒμŠ€νŠΈ" />
34+
2835

2936
<androidx.appcompat.widget.AppCompatButton
3037
android:id="@+id/bFileUpload"

β€Žhardware/.gitignoreβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

β€Žhardware/build.gradleβ€Ž

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
plugins {
2+
id 'com.android.library'
3+
id 'org.jetbrains.kotlin.android'
4+
id 'kotlin-kapt'
5+
id 'maven-publish'
6+
}
7+
8+
android {
9+
namespace 'hmju.tracking.hardware'
10+
compileSdk 34
11+
12+
defaultConfig {
13+
minSdk 23
14+
15+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
16+
consumerProguardFiles "consumer-rules.pro"
17+
}
18+
19+
buildTypes {
20+
release {
21+
minifyEnabled false
22+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23+
}
24+
}
25+
compileOptions {
26+
sourceCompatibility JavaVersion.VERSION_17
27+
targetCompatibility JavaVersion.VERSION_17
28+
}
29+
kotlinOptions {
30+
jvmTarget = "17"
31+
}
32+
}
33+
34+
dependencies {
35+
api(project(":model"))
36+
37+
implementation 'androidx.core:core-ktx:1.6.0'
38+
}
39+
40+
afterEvaluate {
41+
publishing {
42+
publications {
43+
deploy(MavenPublication) {
44+
from components.release
45+
groupId = 'com.github.sieunju.httptracking'
46+
artifactId = 'hardware'
47+
version = deps.release
48+
}
49+
}
50+
}
51+
}

β€Žhardware/consumer-rules.proβ€Ž

Whitespace-only changes.

β€Žhardware/proguard-rules.proβ€Ž

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile

0 commit comments

Comments
Β (0)