Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
genofire
donkey
Commits
b0a6ec2b
Commit
b0a6ec2b
authored
Aug 03, 2019
by
Anon
Browse files
WIP
parent
a68b812c
Changes
6
Hide whitespace changes
Inline
Side-by-side
app/src/main/AndroidManifest.xml
View file @
b0a6ec2b
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
</activity>
</activity>
<activity
android:name=
".ScanActivity"
/>
<activity
android:name=
".ScanActivity"
/>
<activity
android:name=
".SendActivity"
/>
</application>
</application>
<uses-permission
android:name=
"android.permission.BLUETOOTH"
/>
<uses-permission
android:name=
"android.permission.BLUETOOTH"
/>
...
...
app/src/main/java/com/github/antweb/donkey/FileTransfer.kt
View file @
b0a6ec2b
...
@@ -2,15 +2,22 @@ package com.github.antweb.donkey
...
@@ -2,15 +2,22 @@ package com.github.antweb.donkey
import
android.bluetooth.BluetoothGatt
import
android.bluetooth.BluetoothGatt
import
android.bluetooth.BluetoothGattCharacteristic
import
android.bluetooth.BluetoothGattCharacteristic
import
android.bluetooth.BluetoothGattDescriptor
import
android.os.Environment
import
android.os.Environment
import
android.util.Log
import
java.io.BufferedInputStream
import
java.io.BufferedInputStream
import
java.io.File
import
java.io.File
import
java.io.FileInputStream
import
java.io.FileInputStream
import
java.nio.ByteBuffer
import
java.nio.ByteBuffer
import
java.util.*
import
java.util.zip.CRC32
private
const
val
TAG
=
"FileTransfer"
class
FileTransfer
(
class
FileTransfer
(
private
val
gatt
:
BluetoothGatt
,
private
val
gatt
:
BluetoothGatt
,
private
val
dataCharacteristic
:
BluetoothGattCharacteristic
,
private
val
tx
:
BluetoothGattCharacteristic
,
private
val
rx
:
BluetoothGattCharacteristic
,
private
val
mtu
:
Int
private
val
mtu
:
Int
)
{
)
{
private
val
filePath
=
"/Download/SEND.txt"
private
val
filePath
=
"/Download/SEND.txt"
...
@@ -18,6 +25,9 @@ class FileTransfer(
...
@@ -18,6 +25,9 @@ class FileTransfer(
private
val
iterator
=
openFile
().
iterator
()
private
val
iterator
=
openFile
().
iterator
()
private
var
offset
:
Int
=
0
private
var
offset
:
Int
=
0
private
var
lastCrc
:
Long
=
0
private
fun
openFile
():
ByteArray
{
private
fun
openFile
():
ByteArray
{
// TODO: Don't listen to Android Docs, use stuff that is not deprecated
// TODO: Don't listen to Android Docs, use stuff that is not deprecated
val
file
=
File
(
val
file
=
File
(
...
@@ -40,16 +50,15 @@ class FileTransfer(
...
@@ -40,16 +50,15 @@ class FileTransfer(
}
}
fun
sendNext
()
{
fun
sendNext
()
{
Log
.
d
(
TAG
,
"Sending next chunk: $offset"
)
if
(!
iterator
.
hasNext
())
{
if
(!
iterator
.
hasNext
())
{
return
return
}
}
gatt
?.
beginReliableWrite
()
val
chunk
=
mutableListOf
<
Byte
>()
val
chunk
=
mutableListOf
<
Byte
>()
for
(
i
in
0
until
(
mtu
-
5
))
{
// for (i in 0 until (mtu - 5)) {
for
(
i
in
0
until
(
10
))
{
chunk
.
add
(
iterator
.
next
())
chunk
.
add
(
iterator
.
next
())
}
}
...
@@ -61,12 +70,18 @@ class FileTransfer(
...
@@ -61,12 +70,18 @@ class FileTransfer(
val
sendBuffer
=
ByteBuffer
.
allocate
(
chunk
.
size
+
4
)
val
sendBuffer
=
ByteBuffer
.
allocate
(
chunk
.
size
+
4
)
sendBuffer
.
putInt
(
header
)
sendBuffer
.
putInt
(
header
)
sendBuffer
.
put
(
chunk
.
toByteArray
())
sendBuffer
.
put
(
chunk
.
toByteArray
())
val
bytes
=
sendBuffer
.
array
()
val
crc
=
CRC32
()
crc
.
update
(
bytes
)
lastCrc
=
crc
.
value
dataCharacteristic
?.
value
=
sendBuffer
.
array
()
// gatt?.beginReliableWrite()
gatt
?.
writeCharacteristic
(
dataCharacteristic
)
tx
?.
value
=
bytes
val
status
=
gatt
?.
writeCharacteristic
(
tx
)
// This will trigger the onCharacteristicWrite callback once the other side ACKs
if
(!
status
)
{
// In there, we can call the actual gatt?.executeReliableWrite()
Log
.
d
(
TAG
,
"Write status: $status"
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/com/github/antweb/donkey/MainActivity.kt
View file @
b0a6ec2b
...
@@ -15,22 +15,6 @@ private const val TAG = "MainActivity"
...
@@ -15,22 +15,6 @@ private const val TAG = "MainActivity"
class
MainActivity
:
AppCompatActivity
()
{
class
MainActivity
:
AppCompatActivity
()
{
private
val
targetDeviceName
=
"card10"
private
val
mtu
=
128
private
val
serviceUuid
=
"00422342-2342-2342-2342-234223422342"
private
val
dataCharacteristicUuid
=
"01422342-2342-2342-2342-234223422342"
private
val
bluetoothAdapter
:
BluetoothAdapter
?
by
lazy
(
LazyThreadSafetyMode
.
NONE
)
{
val
bluetoothManager
=
getSystemService
(
Context
.
BLUETOOTH_SERVICE
)
as
BluetoothManager
bluetoothManager
.
adapter
}
private
var
bluetoothGatt
:
BluetoothGatt
?
=
null
private
var
fileService
:
BluetoothGattService
?
=
null
private
var
dataCharacteristic
:
BluetoothGattCharacteristic
?
=
null
private
var
mGatt
:
BluetoothGatt
?
=
null
private
var
fileTransferService
:
FileTransfer
?
=
null
private
var
mScanning
:
Boolean
=
false
private
var
mScanning
:
Boolean
=
false
private
var
connected
=
false
private
var
connected
=
false
...
@@ -55,102 +39,4 @@ class MainActivity : AppCompatActivity() {
...
@@ -55,102 +39,4 @@ class MainActivity : AppCompatActivity() {
startActivity
(
intent
)
startActivity
(
intent
)
}
}
}
}
private
fun
scanLeDevice
()
{
val
gattCallback
=
object
:
BluetoothGattCallback
()
{
override
fun
onServicesDiscovered
(
gatt
:
BluetoothGatt
?,
status
:
Int
)
{
super
.
onServicesDiscovered
(
gatt
,
status
)
if
(
gatt
==
null
)
{
throw
NullPointerException
()
}
for
(
service
in
gatt
.
services
)
{
Log
.
d
(
TAG
,
"Found service: ${service.uuid}"
)
if
(
service
.
uuid
.
toString
()
==
serviceUuid
)
{
fileService
=
service
}
for
(
characteristic
in
service
.
characteristics
)
{
Log
.
d
(
TAG
,
"Characteristic: ${characteristic.uuid}"
)
if
(
characteristic
.
uuid
.
toString
()
==
dataCharacteristicUuid
)
{
dataCharacteristic
=
characteristic
}
}
}
if
(
fileService
==
null
||
dataCharacteristic
==
null
)
{
Log
.
e
(
TAG
,
"Could not find file transfer service"
)
return
}
gatt
.
requestMtu
(
mtu
)
}
override
fun
onConnectionStateChange
(
gatt
:
BluetoothGatt
?,
status
:
Int
,
newState
:
Int
)
{
super
.
onConnectionStateChange
(
gatt
,
status
,
newState
)
when
(
newState
)
{
BluetoothGatt
.
STATE_CONNECTED
->
{
runOnUiThread
{
tvConnection
.
text
=
"STATE_CONNECTED"
}
mGatt
=
gatt
gatt
?.
discoverServices
()
}
BluetoothGatt
.
STATE_DISCONNECTED
->
tvConnection
.
text
=
"STATE_DISCONNECTED"
BluetoothGatt
.
STATE_CONNECTING
->
tvConnection
.
text
=
"STATE_CONNECTING"
BluetoothGatt
.
STATE_DISCONNECTING
->
tvConnection
.
text
=
"STATE_DISCONNECTING"
}
}
override
fun
onMtuChanged
(
gatt
:
BluetoothGatt
?,
mtu
:
Int
,
status
:
Int
)
{
Log
.
d
(
TAG
,
"MTU changed to: $mtu"
)
runOnUiThread
{
tvValue
.
text
=
"MTU: $mtu"
}
val
lData
=
dataCharacteristic
if
(
gatt
!=
null
&&
lData
!=
null
)
{
fileTransferService
=
FileTransfer
(
gatt
,
lData
,
mtu
)
fileTransferService
?.
sendFile
()
}
}
override
fun
onReliableWriteCompleted
(
gatt
:
BluetoothGatt
?,
status
:
Int
)
{
// Last chunk sent successfully. Send next chunk
fileTransferService
?.
sendNext
()
}
override
fun
onCharacteristicWrite
(
gatt
:
BluetoothGatt
?,
characteristic
:
BluetoothGattCharacteristic
?,
status
:
Int
)
{
gatt
?.
executeReliableWrite
()
}
}
val
leScanCallback
=
BluetoothAdapter
.
LeScanCallback
{
device
,
_
,
_
->
if
(
device
.
name
==
targetDeviceName
)
{
if
(!
connected
)
{
connected
=
true
bluetoothGatt
=
device
.
connectGatt
(
this
,
true
,
gattCallback
,
BluetoothDevice
.
TRANSPORT_LE
)
}
}
}
// Stops scanning after a pre-defined period
Handler
().
postDelayed
({
mScanning
=
false
bluetoothAdapter
?.
stopLeScan
(
leScanCallback
)
},
5000
)
mScanning
=
true
bluetoothAdapter
?.
startLeScan
(
leScanCallback
)
}
}
}
app/src/main/java/com/github/antweb/donkey/ScanActivity.kt
View file @
b0a6ec2b
...
@@ -14,6 +14,11 @@ private const val TAG = "ScanActivity"
...
@@ -14,6 +14,11 @@ private const val TAG = "ScanActivity"
class
ScanActivity
:
AppCompatActivity
()
{
class
ScanActivity
:
AppCompatActivity
()
{
// HACK: Figure out how to transfer this later
companion
object
{
var
selectedDevice
:
BluetoothDevice
?
=
null
}
private
lateinit
var
listView
:
ListView
private
lateinit
var
listView
:
ListView
private
lateinit
var
listAdapter
:
DeviceListAdapter
private
lateinit
var
listAdapter
:
DeviceListAdapter
...
@@ -32,6 +37,16 @@ class ScanActivity : AppCompatActivity() {
...
@@ -32,6 +37,16 @@ class ScanActivity : AppCompatActivity() {
listAdapter
=
DeviceListAdapter
(
applicationContext
)
listAdapter
=
DeviceListAdapter
(
applicationContext
)
listView
.
adapter
=
listAdapter
listView
.
adapter
=
listAdapter
listView
.
setOnItemClickListener
{
adapterView
,
view
,
i
,
l
->
val
item
=
adapterView
.
adapter
.
getItem
(
i
)
as
?
BluetoothDevice
if
(
item
!=
null
)
{
selectedDevice
=
item
val
intent
=
Intent
(
this
,
SendActivity
::
class
.
java
)
startActivity
(
intent
)
}
}
checkPermissions
()
checkPermissions
()
scan
()
scan
()
}
}
...
@@ -47,13 +62,6 @@ class ScanActivity : AppCompatActivity() {
...
@@ -47,13 +62,6 @@ class ScanActivity : AppCompatActivity() {
val
foundDevices
=
mutableSetOf
<
BluetoothDevice
>()
val
foundDevices
=
mutableSetOf
<
BluetoothDevice
>()
val
leScanCallback
=
BluetoothAdapter
.
LeScanCallback
{
device
,
_
,
_
->
val
leScanCallback
=
BluetoothAdapter
.
LeScanCallback
{
device
,
_
,
_
->
// if (device.name == targetDeviceName) {
// if (!connected) {
// connected = true
// bluetoothGatt = device.connectGatt(this, true, gattCallback, BluetoothDevice.TRANSPORT_LE)
// }
// }
if
(!
foundDevices
.
contains
(
device
))
{
if
(!
foundDevices
.
contains
(
device
))
{
foundDevices
.
add
(
device
)
foundDevices
.
add
(
device
)
listAdapter
.
add
(
device
)
listAdapter
.
add
(
device
)
...
...
app/src/main/java/com/github/antweb/donkey/SendActivity.kt
0 → 100644
View file @
b0a6ec2b
package
com.github.antweb.donkey
import
android.bluetooth.*
import
android.content.Context
import
android.os.Bundle
import
android.util.Log
import
android.widget.TextView
import
androidx.appcompat.app.AppCompatActivity
import
java.lang.NullPointerException
import
java.util.*
private
const
val
TAG
=
"SendActivity"
class
SendActivity
:
AppCompatActivity
()
{
private
val
mtu
=
128
private
val
serviceUuid
=
"00422342-2342-2342-2342-234223422342"
private
val
centralTxCharacteristicUuid
=
UUID
.
fromString
(
"01422342-2342-2342-2342-234223422342"
)
// private var centralTxCharacteristic: BluetoothGattCharacteristic? = null
private
val
centralRxCharacteristicUuid
=
UUID
.
fromString
(
"02422342-2342-2342-2342-234223422342"
)
// private var centralRxCharacteristic: BluetoothGattCharacteristic? = null
private
val
clientConfigUuid
=
"00002902-0000-1000-8000-00805f9b34fb"
private
var
bluetoothGatt
:
BluetoothGatt
?
=
null
private
var
fileService
:
BluetoothGattService
?
=
null
private
var
mGatt
:
BluetoothGatt
?
=
null
private
var
fileTransferService
:
FileTransfer
?
=
null
private
lateinit
var
tvConnection
:
TextView
private
lateinit
var
tvValue
:
TextView
private
val
bluetoothAdapter
:
BluetoothAdapter
?
by
lazy
(
LazyThreadSafetyMode
.
NONE
)
{
val
bluetoothManager
=
getSystemService
(
Context
.
BLUETOOTH_SERVICE
)
as
BluetoothManager
bluetoothManager
.
adapter
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_send
)
tvValue
=
findViewById
(
R
.
id
.
text_value
)
tvConnection
=
findViewById
(
R
.
id
.
text_connection_status
)
tvConnection
.
text
=
"STATE_DISCONNECTED"
val
device
=
ScanActivity
.
selectedDevice
if
(
device
!=
null
)
{
connect
(
device
)
}
else
{
Log
.
e
(
TAG
,
"Device is NULL!"
)
}
}
fun
connect
(
device
:
BluetoothDevice
)
{
val
gattCallback
=
object
:
BluetoothGattCallback
()
{
override
fun
onServicesDiscovered
(
gatt
:
BluetoothGatt
?,
status
:
Int
)
{
super
.
onServicesDiscovered
(
gatt
,
status
)
if
(
gatt
==
null
)
{
throw
NullPointerException
()
}
for
(
service
in
gatt
.
services
)
{
Log
.
d
(
TAG
,
"Found service: ${service.uuid}"
)
if
(
service
.
uuid
.
toString
()
==
serviceUuid
)
{
fileService
=
service
}
// for (characteristic in service.characteristics) {
// Log.d(TAG, "Characteristic: ${characteristic.uuid}")
//
// if (characteristic.uuid.toString() == centralTxCharacteristicUuid) {
// centralTxCharacteristic = characteristic
// } else if (characteristic.uuid.toString() == centralRxCharacteristicUuid) {
// centralRxCharacteristic = characteristic
// }
// }
}
if
(
fileService
==
null
)
{
// if (fileService == null || centralTxCharacteristic == null) {
Log
.
e
(
TAG
,
"Could not find file transfer service"
)
return
}
gatt
.
requestMtu
(
mtu
)
}
override
fun
onConnectionStateChange
(
gatt
:
BluetoothGatt
?,
status
:
Int
,
newState
:
Int
)
{
super
.
onConnectionStateChange
(
gatt
,
status
,
newState
)
when
(
newState
)
{
BluetoothGatt
.
STATE_CONNECTED
->
{
runOnUiThread
{
tvConnection
.
text
=
"STATE_CONNECTED"
}
mGatt
=
gatt
gatt
?.
discoverServices
()
}
BluetoothGatt
.
STATE_DISCONNECTED
->
tvConnection
.
text
=
"STATE_DISCONNECTED"
BluetoothGatt
.
STATE_CONNECTING
->
tvConnection
.
text
=
"STATE_CONNECTING"
BluetoothGatt
.
STATE_DISCONNECTING
->
tvConnection
.
text
=
"STATE_DISCONNECTING"
}
}
override
fun
onCharacteristicChanged
(
gatt
:
BluetoothGatt
?,
characteristic
:
BluetoothGattCharacteristic
?)
{
super
.
onCharacteristicChanged
(
gatt
,
characteristic
)
}
override
fun
onCharacteristicRead
(
gatt
:
BluetoothGatt
?,
characteristic
:
BluetoothGattCharacteristic
?,
status
:
Int
)
{
super
.
onCharacteristicRead
(
gatt
,
characteristic
,
status
)
}
override
fun
onMtuChanged
(
gatt
:
BluetoothGatt
?,
mtu
:
Int
,
status
:
Int
)
{
Log
.
d
(
TAG
,
"MTU changed to: $mtu"
)
runOnUiThread
{
tvValue
.
text
=
"MTU: $mtu"
}
val
tx
=
fileService
?.
getCharacteristic
(
centralTxCharacteristicUuid
)
val
rx
=
fileService
?.
getCharacteristic
(
centralRxCharacteristicUuid
)
if
(
gatt
!=
null
&&
tx
!=
null
&&
rx
!=
null
)
{
val
descriptor
=
rx
.
getDescriptor
(
UUID
.
fromString
(
clientConfigUuid
))
if
(
descriptor
!=
null
)
{
gatt
.
setCharacteristicNotification
(
rx
,
true
)
descriptor
.
value
=
BluetoothGattDescriptor
.
ENABLE_NOTIFICATION_VALUE
val
success
=
gatt
.
writeDescriptor
(
descriptor
)
if
(!
success
)
{
Log
.
e
(
TAG
,
"Descriptor write failed"
)
}
}
else
{
Log
.
e
(
TAG
,
"Failed to write descriptor"
)
}
fileTransferService
=
FileTransfer
(
gatt
,
tx
,
rx
,
mtu
)
fileTransferService
?.
sendFile
()
}
}
override
fun
onReliableWriteCompleted
(
gatt
:
BluetoothGatt
?,
status
:
Int
)
{
// Last chunk sent successfully. Send next chunk
// fileTransferService?.sendNext()
}
override
fun
onCharacteristicWrite
(
gatt
:
BluetoothGatt
?,
characteristic
:
BluetoothGattCharacteristic
?,
status
:
Int
)
{
// gatt?.executeReliableWrite()
Thread
.
sleep
(
3000
)
fileTransferService
?.
sendNext
()
return
}
}
bluetoothGatt
=
device
.
connectGatt
(
this
,
true
,
gattCallback
,
BluetoothDevice
.
TRANSPORT_LE
)
}
}
\ No newline at end of file
app/src/main/res/layout/activity_send.xml
View file @
b0a6ec2b
...
@@ -4,4 +4,14 @@
...
@@ -4,4 +4,14 @@
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
android:layout_height=
"match_parent"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:id=
"@+id/text_connection_status"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:id=
"@+id/text_value"
/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment